数据结构哈弗曼编译码———c语言版
- 格式:doc
- 大小:306.50 KB
- 文档页数:15
一、需求分析目前,进行快速远距离通信的主要手段是电报,即将需传送的文字转化成由二级制的字符组成种字符,只需两个字符的串,便可”,它只有4的字符串。
例如,假设需传送的电文为“ABACCDA,00010010101100”则上述和11,7个字符的电文便为“以分辨。
假设A、B、C、D、的编码分别为00,01,10 14位,对方接受时,可按二位一分进行译码。
总长当然,在传送电文时,希望总长尽可能地短。
如果对每个字符设计长度不等的编码,且让电文DC、中出现次数较多的字符采用尽可能短的编码,则传送电文的总长便可减少。
如果设计A、B、。
但是,000011010”,则上述7个字符的电文可转换成总长为9的字符串“的编码分别为0,00,1,01”就可以有很多种译法,0000个字符的字串“这样的电文无法翻译,例如传送过去的字符串中前4”等。
因此,若要设计长短不等的编码,则必须是任一字ABAAAAA”或者“BB”,或者“或是“符的编码都不是另一个字符的编码的前缀,这种编码称作前缀编码。
然而,如何进行前缀编码就是利用哈夫曼树来做,也就有了现在的哈夫曼编码和译码。
二、概要设计译码利用哈夫曼树编/ 、建立哈夫曼树(一)、对哈夫曼树进行编码(二)、输出对应字符的编码(三)、译码过程(四)主要代码实现://结构体的定义struct code{char a;int w;int parent;int lchild;int rchild;};void creation(code *p,int n,int m); //建立哈夫曼树//编码void coding(code *p,int n);//输出函数void display(code *p,int n,int m);//译码void translate(char **hc,code *p,int n);详细设计三、(一)、建立哈夫曼树10序号:5 3 4 2 7 6 1* * *c *字符:db a 4 6 6 权值:10 6 4 2 3 3 1 d **33333 c*c * * 1 2 2 1 2 1 abb a 3-3图3-1 图b a 3-2 图1(二)、对哈夫曼树进行编码主要代码实现:从叶子到根逆向求编码for(c=i,f=p[i].parent;f!=0;c=f,f=p[f].parent){*'0'//左孩子编码为if(p[f].lchild==c) 1 { d* cd[--start]='0'; 0 1} c* 1 0 '1'else //右孩子编码为{ bacd[--start]='1';3-4图}}(三)、输出对应字符的码编码字符110 a111 b10 c3-1表d(四)、译码过程主要代码实现:0 比较两个字符串是否相等,相等则输出if(strcmp(a,hc[i])==0) //{或'1'确定找左孩子或右孩子//从根出发,按字符'0' for(c=2*n-1,j=0;a[j]!='\0';j++){if(a[j]=='0') //左孩子从跟到叶子顺向求字符{*c=p[c].lchild;1 0}d * else 1 0{c *右孩子c=p[c].rchild; // 1 0}ba }3-5 图2调试分析四、、数字的输入判断(一)4-1 图、字母的输入判断(二)4-2 图(三)、程序是否继续进行的判断4-3 图用户手册五、;提示输(一)、首先根据提示输入初始化数据,提示输入一个数字,请输入一个数a,0<a<9999中的一个字符;请勿在输入一个数字后再输入一个入一个字母,则请输入一个字母(a~z)或者(A~Z) 字符,或者在输入一个字符后再输入一个数字。
题目:哈夫曼树编码译码院系:信息工程系专业:计算机科学与技术(网络方向)*名:***学号: **********指导教师:赵莹莹刘欣日期: 2013年7月3日桂林电子科技大学信息科技学院实训报告目录一、设计思想............................. 错误!未定义书签。
1.1建立哈夫曼树的思想................. 错误!未定义书签。
1.2建立哈夫曼编码表................... 错误!未定义书签。
1.3对文件进行编码 (2)1.4对文件进行解码 (2)二、算法流程图 (3)三、运行结果 (8)四、遇到的问题及解决 (10)五、心得体会............................. 错误!未定义书签。
一、设计思想要完成哈夫曼的编码和解码需要首先建立哈夫曼树,之后对所有字符根据权重进行编码,最后再对文件内容进行编码和解码。
1.1建立哈夫曼树的思想。
首先定义适合哈夫曼树的节点类型,需要定义的有当前节点的字符,当前节点的左子、右子和父亲指针。
在建立哈夫曼树之前还需要对出现的字符和权重进行统计和记录,并且定义一个可以筛选出最小权重的函数。
初始化树节点之后开始建立哈夫曼树。
先在所有可能出现的字符中筛选出当前权重最小的两个字符,将这两个字符分别作为新节点的左子和右子建立一个小的二叉树,并将两个字符的权重之和赋值给新节点,将新二叉树放入筛选字符中,再将筛选过的两个字符从筛选列表中淘汰掉。
依次对列表中剩下的字符进行权重最小的筛选,直到根节点(如果编码表共有N个字符,则2*N-1就为最终根节点)为止,也就是当筛选列表为空的时候,哈夫曼树即建立完成。
对于哈夫曼编码树来说,由于哈夫曼编码是前缀码,所以所有要编码的字符最终都将是这颗树的叶子节点,而其它节点并没有真正的字符意义。
即当哈夫曼编码树建立之后,对树的所有叶子节点进行打印可知道是否有字符遗漏或多余。
1.2建立哈夫曼编码表。
哈夫曼编码译码C语言编写10[ 标签:哈夫曼,编码,译码 ]如上题 C语言编个程序懂的帮搞个能运行的程序来#11别到网上找那些我找过了没用的蝶风待夕魂回答:2 人气:19 解决时间:2009-05-14 18:44满意答案好评率:100%#include<stdio.h>#include<stdlib.h>#include<string.h>typedef char ElemType;typedef struct{ElemType elem;unsigned int weight;unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;typedef char** HuffmanCode;typedef int Status;typedef struct {char elem;unsigned int weight;}Weight; // save the information of the symbolizes;void HuffmanCoding(HuffmanTree *,HuffmanCode *,Weight *,int);void Select(HuffmanTree,int,int *,int *);void OutputHuffmanCode(HuffmanTree,HuffmanCode,int);Status main(void){HuffmanTree HT;HuffmanCode HC;Weight *w;char c;int i,n;int wei;printf("input the tatol number of the Huffman Tree:" );scanf("%d",&n);w=(Weight *)malloc(n*sizeof(Weight));for(i=0;i<n;i++){printf("input the element & its weight:");scanf("%1s%d",&c,&wei);w[i].elem=c;w[i].weight=wei;}HuffmanCoding(&HT,&HC,w,n);OutputHuffmanCode(HT,HC,n);return 1;}回答人的补充 2009-05-08 00:07接上面的。
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言⒈简介本文档旨在介绍一个使用C语言实现的哈夫曼编码译码器的数据结构。
哈夫曼编码是一种用于数据压缩的算法,它通过将频率较高的字符用较短的编码表示,从而实现数据的压缩和解压缩。
⒉哈夫曼编码(Huffman Coding)基本概念⑴字符频率统计在进行哈夫曼编码之前,我们首先需要统计每个字符在待编码的数据中出现的频率。
通过遍历数据,记录每个字符的出现次数,我们可以得到一个字符频率的统计表。
⑵构建哈夫曼树通过字符频率的统计表,我们可以构建一个哈夫曼树。
哈夫曼树是一种二叉树,其中每个叶节点表示一个字符,而每个内部节点表示一个权重,即两个子节点的频率之和。
⑶哈夫曼编码在哈夫曼树构建完成后,我们可以根据树的结构每个字符的编码。
哈夫曼编码的特点是没有任何一个字符的编码是另一个字符编码的前缀,这种编码方式称为前缀编码。
⑷哈夫曼译码根据字符的哈夫曼编码,我们可以将编码后的数据进行解码,还原为原始的数据。
通过遍历哈夫曼树,从根节点开始,根据每个二进制位的取值进行向左或向右的移动,直至叶节点,然后获取该叶节点对应的字符。
⒊数据结构设计⑴结点结构定义一个哈夫曼树的结点结构,包含以下字段:●`char data`:字符●`int frequency`:字符的频率●`int is_leaf`:是否为叶节点●`struct Node left_child`:左子节点●`struct Node right_child`:右子节点⑵频率统计表使用一个数组或链表来记录每个字符的频率统计信息,包含以下字段:●`char data`:字符●`int frequency`:字符的频率⑶编码表使用一个数组或链表来记录每个字符的哈夫曼编码,包含以下字段:●`char data`:字符●`char code`:编码⒋算法流程⑴字符频率统计算法步骤:⒈初始化频率统计表为空。
⒉读取待编码的数据。
数据结构课程设计一、目的《数据结构》是一门实践性较强的软件基础课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。
本课程设计的目的就是要达到理论与实际应用相结合,使同学们能够根据数据对象的特性,学会数据组织的方法,能把现实世界中的实际问题在计算机内部表示出来,并培养基本的、良好的程序设计技能。
二、要求通过这次设计,要求在数据结构析逻辑特性和物理表示,数据结构的选择的应用、算法的设计及其实现等方面中深对课程基本内容的理解。
同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
三、内容2.哈夫曼编码/译码器【问题描述】设计一个利用哈夫曼算法的编码和译码系统,重复地显示并处理以下项目,直到选择退出为止。
【基本要求】(1)初始化:键盘输入字符集大小n、n个字符和n个权值,建立哈夫曼树;(2)编码:利用建好的哈夫曼树生成哈夫曼编码;(3)输出编码;(4)设字符集及频度如下表:字符空格A B C D E F G H I J K L M频度186 64 13 22 32 103 21 15 47 57 1 5 32 20字符N O P Q R S T U V W X Y Z频度57 63 15 1 48 51 80 23 8 18 1 16 1【选做内容】(1)译码功能;(2)显示哈夫曼树;(3)界面设计的优化。
哈夫曼编写编译码一、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,这要求在发送端通过一个编码系统对待传输预先编码,在接收端将传来的数据进行译码。
对于双工通道,每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
二、概要设计1.哈夫曼树的定义:在一棵二叉树中,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。
2.哈夫曼树的构造:假设有N个权值,则构造出的哈夫曼树有N个叶子结点。
N个权值分别设为W1,W2,……….Wn,则哈夫曼树的构造规则为:(1)将W1,W2,……….Wn看成有N棵树的森林;(2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左,右子树,且新树的根结点为其左,右子树结点权值之和;(3)从森林中删除选取取的两面三刀棵树,并将新树加入森林;(4)重复(2)(3)步,直到森林中只剩一棵树为止,该树即为我们所求得的哈夫曼树。
哈夫曼编码c语言代码1.统计数据中每个字符出现的次数。
2.根据每个字符出现的次数建立哈夫曼树。
3.根据哈夫曼树构建每个字符的编码,相同的字符具有不同的编码。
4.用编码替换原数据中的字符。
根据上述步骤,我们可以得到以下的C语言实现。
C语言实现哈夫曼编码在C语言中,我们可以使用结构体来表示哈夫曼树节点及其信息:```ctypedef struct node 。
char content;int freq;struct node某 left;struct node某 right;} node;```其中content表示节点所代表的字符,freq表示该字符在数据中出现的次数,left和right分别指向节点的左右子节点。
我们可以使用一个链表来存储所有的字符及其出现的次数:```ctypedef struct listNode 。
node某 n;struct listNode某 ne某t;} listNode;```这个链表可以通过遍历数据,统计每个字符出现的次数来构建。
我们可以使用一个堆来存储所有的树节点,每次从堆中取出频率最小的两个节点,构建一个新的节点,然后将这个新节点插入堆中。
重复这个过程直到堆中只剩下一个根节点,这个节点就是哈夫曼树的根节点。
```ctypedef struct heap 。
int size;node某某 nodes;} heap;```定义堆的时候,size表示堆中节点的数量,nodes是一个数组,存储所有的节点。
我们可以使用一棵二叉堆来实现堆的操作,即将频率最小的节点放在堆的顶部。
构建好哈夫曼树后,我们可以通过遍历树来给每个字符一个独一无二的编码。
编码的时候,我们可以使用一个栈来存储每个节点的信息,然后倒序输出栈中的内容来得到编码。
最后,我们可以使用编码替换原数据中的字符。
在解码的时候,我们只需要将编码反向遍历树即可还原原始数据。
总结。
哈夫曼编码详解(C语言实现)哈夫曼编码是一种常见的前缀编码方式,被广泛应用于数据压缩和传输中。
它是由大卫·哈夫曼(David A. Huffman)于1952年提出的,用于通过将不同的字符映射到不同长度的二进制码来实现数据的高效编码和解码。
1.统计字符频率:遍历待编码的文本,记录每个字符出现的频率。
2.构建哈夫曼树:根据字符频率构建哈夫曼树,其中出现频率越高的字符位于树的较低层,频率越低的字符位于树的较高层。
3.生成编码表:从哈夫曼树的根节点开始,遍历哈夫曼树的每个节点,为每个字符生成对应的编码。
在遍历过程中,从根节点到叶子节点的路径上的“0”表示向左,路径上的“1”表示向右。
4.进行编码:根据生成的编码表,将待编码的文本中的每个字符替换为对应的编码。
5.进行解码:根据生成的编码表和编码结果,将编码替换为原始字符。
下面是一个用C语言实现的简单哈夫曼编码示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>//定义哈夫曼树的节点结构体typedef struct HuffmanNodechar data; // 字符数据int freq; // 字符出现的频率struct HuffmanNode *left; // 左子节点struct HuffmanNode *right; // 右子节点} HuffmanNode;//定义编码表typedef structchar data; // 字符数据char *code; // 字符对应的编码} HuffmanCode;//统计字符频率int *countFrequency(char *text)int *frequency = (int *)calloc(256, sizeof(int)); int len = strlen(text);for (int i = 0; i < len; i++)frequency[(int)text[i]]++;}return frequency;//创建哈夫曼树HuffmanNode *createHuffmanTree(int *frequency)//初始化叶子节点HuffmanNode **leaves = (HuffmanNode **)malloc(256 * sizeof(HuffmanNode *));for (int i = 0; i < 256; i++)if (frequency[i] > 0)HuffmanNode *leaf = (HuffmanNode*)malloc(sizeof(HuffmanNode));leaf->data = (char)i;leaf->freq = frequency[i];leaf->left = NULL;leaf->right = NULL;leaves[i] = leaf;} elseleaves[i] = NULL;}}//构建哈夫曼树while (1)int min1 = -1, min2 = -1;for (int i = 0; i < 256; i++)if (leaves[i] != NULL)if (min1 == -1 , leaves[i]->freq < leaves[min1]->freq) min2 = min1;min1 = i;} else if (min2 == -1 , leaves[i]->freq < leaves[min2]->freq)min2 = i;}}}if (min2 == -1)break;}HuffmanNode *parent = (HuffmanNode*)malloc(sizeof(HuffmanNode));parent->data = 0;parent->freq = leaves[min1]->freq + leaves[min2]->freq;parent->left = leaves[min1];parent->right = leaves[min2];leaves[min1] = parent;leaves[min2] = NULL;}HuffmanNode *root = leaves[min1];free(leaves);return root;//生成编码表void generateHuffmanCode(HuffmanNode *root, HuffmanCode *huffmanCode, char *code, int depth)if (root->left == NULL && root->right == NULL)code[depth] = '\0';huffmanCode[root->data].data = root->data;huffmanCode[root->data].code = strdup(code);return;}if (root->left != NULL)code[depth] = '0';generateHuffmanCode(root->left, huffmanCode, code, depth + 1);}if (root->right != NULL)code[depth] = '1';generateHuffmanCode(root->right, huffmanCode, code, depth + 1);}//进行编码char *encodeText(char *text, HuffmanCode *huffmanCode)int len = strlen(text);int codeLen = 0;char *code = (char *)malloc(len * 8 * sizeof(char));for (int i = 0; i < len; i++)strcat(code + codeLen, huffmanCode[(int)text[i]].code);codeLen += strlen(huffmanCode[(int)text[i]].code);}return code;//进行解码char* decodeText(char* code, HuffmanNode* root) int len = strlen(code);char* text = (char*)malloc(len * sizeof(char)); int textLen = 0;HuffmanNode* node = root;for (int i = 0; i < len; i++)if (code[i] == '0')node = node->left;} elsenode = node->right;}if (node->left == NULL && node->right == NULL) text[textLen] = node->data;textLen++;node = root;}}text[textLen] = '\0';return text;int maichar *text = "Hello, World!";int *frequency = countFrequency(text);HuffmanNode *root = createHuffmanTree(frequency);HuffmanCode *huffmanCode = (HuffmanCode *)malloc(256 * sizeof(HuffmanCode));char code[256];generateHuffmanCode(root, huffmanCode, code, 0);char *encodedText = encodeText(text, huffmanCode);char *decodedText = decodeText(encodedText, root);printf("Original Text: %s\n", text);printf("Encoded Text: %s\n", encodedText);printf("Decoded Text: %s\n", decodedText);//释放内存free(frequency);free(root);for (int i = 0; i < 256; i++)if (huffmanCode[i].code != NULL)free(huffmanCode[i].code);}}free(huffmanCode);free(encodedText);free(decodedText);return 0;```上述的示例代码实现了一个简单的哈夫曼编码和解码过程。
#include <iostream.h>#include <iomanip.h>#include <string.h>#include <malloc.h>#include <stdio.h>//typedef int TElemType;const int UINT_MAX = 1000;typedef struct{int weight;int parent, lchild, rchild;} HTNode, *HuffmanTree;typedef char **HuffmanCode;//-----------全局变量-----------------------HuffmanTree HT;HuffmanCode HC;int *w, i, j, n;char *z;int flag = 0;int numb = 0;// -----------------求赫夫曼编码-----------------------int min(HuffmanTree t, int i){// 函数void select()调用int j, flag;int k = UINT_MAX; // 取k为不小于可能的值for (j = 1; j <= i; j++)if (t[j].weight < k && t[j].parent == 0)k = t[j].weight, flag = j;t[flag].parent = 1;return flag;}//--------------------slect函数----------------------void select(HuffmanTree t, int i, int &s1, int &s2){// s1为最小的两个值中序号小的那个int j;s1 = min(t, i);s2 = min(t, i);if (s1 > s2){j = s1;s1 = s2;s2 = j;}}// --------------算法6.12--------------------------void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){// w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC int m, i, s1, s2, start;//unsigned c,f;int c, f;HuffmanTree p;char *cd;if (n <= 1)return ;//检测结点数是否可以构成树m = 2 * n - 1;HT = (HuffmanTree)malloc((m + 1) *sizeof(HTNode)); // 0号单元未用for (p = HT + 1, i = 1; i <= n; ++i, ++p, ++w){p->weight = *w;p->parent = 0;p->lchild = 0;p->rchild = 0;}for (; i <= m; ++i, ++p)p->parent = 0;for (i = n + 1; i <= m; ++i)// 建赫夫曼树{// 在HT[1~i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2 select(HT, i - 1, s1, s2);HT[s1].parent = HT[s2].parent = i;HT[i].lchild = s1;HT[i].rchild = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;}// 从叶子到根逆向求每个字符的赫夫曼编码HC = (HuffmanCode)malloc((n + 1) *sizeof(char*));// 分配n个字符编码的头指针向量([0]不用)cd = (char*)malloc(n *sizeof(char)); // 分配求编码的工作空间cd[n - 1] = '\0'; // 编码结束符for (i = 1; i <= n; i++){// 逐个字符求赫夫曼编码start = n - 1; // 编码结束符位置for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)// 从叶子到根逆向求编码if (HT[f].lchild == c)cd[--start] = '0';elsecd[--start] = '1';HC[i] = (char*)malloc((n - start) *sizeof(char));// 为第i个字符编码分配空间strcpy(HC[i], &cd[start]); // 从cd复制编码(串)到HC}free(cd); // 释放工作空间}//--------------初始化赫夫曼链表---------------------------------void Initialization(){flag = 1;int num;int num2;cout << "下面初始化赫夫曼链表" << endl << "数请输入结点的个n:";cin >> num;n = num;w = (int*)malloc(n *sizeof(int));z = (char*)malloc(n *sizeof(char));cout << "\n请依次输入" << n << "个字符(字符型)\n注意:必须以回车结束:" << endl;char base[2];for (i = 0; i < n; i++){cout << "第" << i + 1 << "个字符:" << endl;gets(base);*(z + i) = *base;for (i = 0; i <= n - 1; i++){cout << setw(6) << *(z + i);}cout << "\n请依次输入" << n << "个权值(\n注意:必须以回车结束):" << endl; for (i = 0; i <= n - 1; i++){cout << endl << "第" << i + 1 << "个字符的权值:";cin >> num2;*(w + i) = num2;}HuffmanCoding(HT, HC, w, n);//------------------------打印编码-------------------------------------------cout << "字符对应的编码为:" << endl;for (i = 1; i <= n; i++){//cout<<"字符"<<*(z+i-1)<<"的编码";puts(HC[i]);}//--------------------------将赫夫曼编码写入文件------------------------cout << "下面将赫夫曼编码写入文件" << endl << "...................." << endl; FILE *htmTree;char r[] =' ', '\0'};if ((htmTree = fopen("htmTree.txt", "w")) == NULL){cout << "can not open file" << endl;return ;}fputs(z, htmTree);for (i = 0; i < n + 1; i++){fprintf(htmTree, "%6d", *(w + i));fputs(r, htmTree);}for (i = 1; i <= n; i++){fputs(HC[i], htmTree);fputs(r, htmTree);}fclose(htmTree);cout << "已将字符与对应编码写入根目录下文件htmTree.txt中" << endl << endl; }//---------------------获取报文并写入文件---------------------------------void InputCode()//cout<<"请输入你想要编码的字符"<<endl;FILE *tobetran;char str[100];if ((tobetran = fopen("tobetran.txt", "w")) == NULL){cout << "不能打开文件" << endl;return ;}cout << "请输入你想要编码的字符" << endl;gets(str);fputs(str, tobetran);cout << "获取报文成功" << endl;fclose(tobetran);}//---------------------编码函数---------------------------------void Encoding(){cout << "下面对目录下文件tobetran.txt中的字符进行编码" << endl; FILE *tobetran, *codefile;if ((tobetran = fopen("tobetran.txt", "rb")) == NULL){cout << "不能打开文件" << endl;}if ((codefile = fopen("codefile.txt", "wb")) == NULL) {cout << "不能打开文件" << endl;}char *tran;i = 99;tran = (char*)malloc(100 *sizeof(char));while (i == 99){if (fgets(tran, 100, tobetran) == NULL){cout << "不能打开文件" << endl;break;}for (i = 0; *(tran + i) != '\0'; i++){for (j = 0; j <= n; j++){if (*(z + j - 1) == *(tran + i)){fputs(HC[j], codefile);if (j > n){cout << "字符错误,无法编码!" << endl;break;}}}}}cout << "编码工作完成" << endl << "编码写入目录下的codefile.txt中" << endl << endl;fclose(tobetran);fclose(codefile);free(tran);}//-----------------译码函数---------------------------------void Decoding(){cout << "下面对根目录下文件codefile.txt中的字符进行译码" << endl;FILE *codef, *txtfile;if ((txtfile = fopen("Textfile.txt", "w")) == NULL){cout << "不能打开文件" << endl;}//txtfile=fopen("Textfile.txt","w");if ((codef = fopen("codefile.txt", "r")) == NULL){cout << "不能打开文件" << endl;}//codef=fopen("codefile.txt","r");char *work, *work2, i2;int i4 = 0, i, i3;unsigned long length = 10000;work = (char*)malloc(length *sizeof(char)); fgets(work, length, codef);work2 = (char*)malloc(length *sizeof(char)); i3 = 2 * n - 1;for (i = 0; *(work + i - 1) != '\0'; i++){i2 = *(work + i);if (HT[i3].lchild == 0){*(work2 + i4) = *(z + i3 - 1);i4++;i3 = 2 * n - 1;i--;}else if (i2 == '0')i3 = HT[i3].lchild;i3 = HT[i3].rchild;}*(work2 + i4) = '\0';fputs(work2, txtfile);cout << "译码完成" << endl << "内容写入根目录下的文件txtfile.txt中" << endl << endl;cout << work2;free(work);free(work2);fclose(txtfile);fclose(codef);}//------------------------打印赫夫曼树的函数-----------------------void coprint(HuffmanTree start, HuffmanTree HT){if (start != HT){FILE *TreePrint;if ((TreePrint = fopen("TreePrint.txt", "a")) == NULL){cout << "创建文件失败" << endl;return ;numb++; //该变量为已被声明为全局变量coprint(HT + start->rchild, HT);cout << setw(5 *numb) << start->weight << endl;fprintf(TreePrint, "%d\n", start->weight);coprint(HT + start->lchild, HT);numb--;fclose(TreePrint);}}void Tree_printing(HuffmanTree HT, int w){HuffmanTree p;p = HT + w;cout << "下面打印赫夫曼树" << endl;coprint(p, HT);cout << "打印工作结束" << endl;}//------------------------主函数------------------------------------void main(){char choice;cout << " 赫夫曼编码解码系统" << endl;cout << "1.要初始化赫夫曼链表请输入'i'" << endl;cout << "2.要编码请输入'e'" << endl;cout << "3.要译码请输入'd'" << endl;cout << "4.要打印编码请输入'p'" << endl;cout << "5.要打印赫夫曼树请输入't'" << endl;cout << "6.要离开请输入'q'" << endl;// if(flag==0)cout<<"\n请先初始化赫夫曼链表,输入'i'"<<endl; cin >> choice;switch (choice){case 'i':Initialization();break;case 'w':InputCode();break;case 'e':Encoding();break;Decoding();break;case 't':Tree_printing(HT, 2 *n - 1);break;case 'q':default:cout << "input error" << endl;}}free(z);free(w);free(HT);}运行结果:赫夫曼编码解码系统1.要初始化赫夫曼链表请输入'i'2.要编码请输入'e'3.要译码请输入'd'4.要打印编码请输入'p'5.要打印赫夫曼树请输入't'6.要离开请输入'q'下面初始化赫夫曼链表数请输入结点的个n:8请依次输入8个字符(字符型)注意:必须以回车结束:第1个字符:a第2个字符:b第3个字符:c第4个字符:d第5个字符:e第6个字符:f第7个字符:g第8个字符:ha b c d e f g h 请依次输入8个权值(注意:必须以回车结束):第1个字符的权值:5第2个字符的权值:29第3个字符的权值:7第4个字符的权值:8第5个字符的权值:14第6个字符的权值:23第7个字符的权值:3第8个字符的权值:11字符对应的编码为:01101011101111110000111010下面将赫夫曼编码写入文件....................已将字符与对应编码写入根目录下文件htmTree.txt中赫夫曼编码解码系统1.要初始化赫夫曼链表请输入'i'2.要编码请输入'e'3.要译码请输入'd'4.要打印编码请输入'p'5.要打印赫夫曼树请输入't'6.要离开请输入'q'i下面初始化赫夫曼链表数请输入结点的个n:27请依次输入27个字符(字符型)注意:必须以回车结束:第1个字符:第2个字符:a第3个字符:b第4个字符:c第5个字符:d第6个字符:第7个字符: f第8个字符: g第9个字符: h第10个字符: i第11个字符: j第12个字符: k第13个字符: l第14个字符: m第15个字符: n第16个字符: o第17个字符: p第19个字符:r第20个字符:s第21个字符:t第22个字符:u第23个字符:v第24个字符:w第25个字符:x第26个字符:y第27个字符:za b c d e f gm n o p q r s t z请依次输入27个权值(第1个字符的权值:186第2个字符的权值:64第3个字符的权值:13第4个字符的权值:22第5个字符的权值:32第6个字符的权值:103第7个字符的权值:21第8个字符的权值:15第9个字符的权值:47第10个字符的权值:57第11个字符的权值:1第12个字符的权值:5第13个字符的权值:32第14个字符的权值:20第15个字符的权值:57第16个字符的权值:63第17个字符的权值:15第18个字符的权值:1第19个字符的权值:48第20个字符的权值:51第21个字符的权值:80第22个字符的权值:23第23个字符的权值:8第24个字符的权值:18第25个字符的权值:1第26个字符的权值:16第27个字符的权值:1字符对应的编码为: 11010101001000001010110010111110100101000001101111011100111101101011111111101111000100110111101110100100011111000011111101011110011110111101001111111011111下面将赫夫曼编码写入文件....................已将字符与对应编码写入根目录下文件htmTree.txt中。
c语言实现哈夫曼编码一、概述哈夫曼编码是一种常用的无损数据压缩算法,其原理是基于字符的出现概率来构建编码表,从而实现数据的压缩。
本教程将介绍如何使用C语言实现哈夫曼编码算法。
二、算法原理哈夫曼编码算法的基本思想是:将字符按照出现概率的大小进行排序,然后构建一个树状结构,每个节点代表一个字符,节点的左子节点和右子节点分别代表字符的频率较小和较大的分支。
最终,通过路径进行解码即可还原出原始数据。
三、实现步骤1.统计字符频率,构建字符频率表;2.按照频率从小到大排序,构建哈夫曼树;3.根据哈夫曼树构建编码表,将字符映射为编码;4.实现解码过程,还原出原始数据。
四、代码实现下面是一个简单的C语言实现哈夫曼编码的示例代码:```c#include<stdio.h>#include<stdlib.h>#include<ctype.h>#defineMAX_CHARS1000//最大字符数#defineMAX_FREQ100//最大频率值//字符频率表intfreq[MAX_CHARS+1];//构建哈夫曼树函数structnode{charch;intfreq;structnode*left,*right;};structnode*build_huffman_tree(intfreq[],intn){structnode*root=(structnode*)malloc(sizeof(structnode));root->freq=freq[0];//根节点的频率为最小的频率值root->left=root->right=NULL;for(inti=1;i<=n;i++){if(freq[i]==root->freq){//如果当前字符的频率与根节点的频率相同,则添加到左子树或右子树中if(i<n&&freq[i]==freq[i+1]){//如果当前字符的频率与下一个字符的频率相同,则添加到左子树中root->left=(structnode*)malloc(sizeof(structnode));root->left->ch=i+'a';//左子节点的字符为当前字符的下一个字符(假设所有字符都是小写字母)root->left->left=root->left->right=NULL;//左子树为空树i++;//跳过下一个字符,继续寻找下一个不同的频率值}else{//如果当前字符的频率与下一个字符的频率不相同,则添加到右子树中root->right=(structnode*)malloc(sizeof(structnode));root->right->ch=i+'a';//右子节点的字符为当前字符root->right->left=root->right->right=NULL;//右子树为空树}}elseif(freq[i]<root->freq){//如果当前字符的频率小于根节点的频率,则添加到左子树中root->left=(structnode*)malloc(sizeof(structnode));root->left->ch=i+'a';//左子节点的字符为当前字符的下一个字符(假设所有字符都是小写字母)root->left->left=build_huffman_tree(freq,i);//子树的左孩子为当前字符构成的右子树节点和子哈夫曼树的左孩子合并得到的左孩子节点,这个步骤继续调用本函数,从而继续构建右子树的下一级和再下一级,最终实现三级左右子的嵌套式结构树型哈夫曼编码)注:这种思想并非标准的哈夫曼编码)//子树的右孩子为当前节点(即当前字符)构成的右子树节点和子哈夫曼树的右孩子节点合并得到的右孩子节点)注:这种思想并非标准的哈夫曼编码)//子树的左孩子为空树)注:这种思想并非标准的哈夫曼编码)根节点的频率是根节点的最小频率值(因为构建哈夫曼树的过程中总是从最小的频率值开始)根节点的左子树是构建出的三级左右子的嵌套式结构树型哈夫曼编码根节点的右子树为空树(假设所有字符都是小写字母)在添加左子节点后需要调用本函数构建右子树的下一级和再下一级来得到三级左右子的嵌套式结构。
HUBEI UNIVERSITY OF AUTOMOTIVE TECHNOLOGY数据结构课程设计报告课设题目:哈夫曼(Huffman)编/译码器专业:计算机科学与技术(嵌入式)班级:计算机143姓名:王龙完成日期:2016年1月21日指导教师:魏本昌1、题目的内容及要求【问题描述】利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼码的编/译码系统。
【任务要求】一个完整的系统应具有以下功能:1)I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
2)E:编码(Encoding)。
利用以建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。
3)D:译码(Decoding)。
利用已建好的哈夫曼树将文件CodeFile中的代码进行译码,结果存入文件TextFile中。
4)P:印代码文件(Print)。
将文件CodeFile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件CodePrin中。
5)T:印哈夫曼树(Tree Printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。
2、需求分析利用哈夫曼树(Huffman)编/译码(一)、初始化哈夫曼树(二)、建立哈夫曼树(三)、对哈夫曼树进行编码(四)、输出对应字符的编码(五)、译码过程(六)、输出哈夫曼树3、概要设计(包括选择什么数据结构?数据结构采用哪种存储方式?选择的原因?设计哪些操作?这些操作之间的调用关系等等)选择了线性数据结构,数据结构采用顺序存储方式,选择的原因:结构简单,可以方便调用任何一个数组,无需为结点间的逻辑关系而增加额外的空间。
设计初始化哈夫曼树、编码、译码、输出哈夫曼树等操作。
这些操作之间的调用关系:通过主函数逐个完成,执行译码、编码、输出前,必须先建立哈夫曼树。
4、详细设计(包括数据结构的类型定义,每个操作的算法描述)定义两个结构体变量HuffNode和HuffCodeint HuffmanCteate (HuffNode * ht)函数:已知有n 个节点,则哈夫曼树构建需要有2N-1个节点,先输入元素个数n ,然后输入结点值和权重,存储在ht数组的前n个数组元素中。
然后将2n-1个节点的双亲和左右孩子置0;然后在所有节点中,选取双亲为0、权重最小的两个节点m1,m2;用p1\p2表示这两个节点在数组中的位置。
将根为ht[p1]和ht[p2]的两节点合并,成为新节点ht[i]的左右孩子,ht[i]的权重为两个最小权重m1,m2之和;ht[p1]和ht[p2]的双亲指向i;最后一直重复2的步骤,进行n-1次,形成哈夫曼树,当进行n-1次后,产生n-1个节点,依次放入ht数组中。
void Encoding (HuffNode ht[], HuffCode hcd[], int n)函数:从哈夫曼树的结点ht[i]出发,通过双亲找到双亲ht[i],通过ht[f]的左右孩子,可知ht[i]是ht[f]的左孩子还是右孩子,若是左孩子,编码置0;若是右孩子,编码置1,编码存放在数组cd[start]中;然后把ht[f]作为出发点,重复上面过程,直到找到根节点。
因为所生产的编码与要求的编码是相反的,先把编码存入第n 个位置,在生产的存入n-1个位置,重复;用start指向编码在数组cd中的起始位置,start初始值为n,生产一个编码后。
start减一。
void Decoding (HuffNode ht[], HuffCode hcd[], int n) 函数:首先输入电文,存放在cd中,以#号表示结束。
然后,将电文和编码比较,如果为0,转到左孩子,如果为1,转到右孩子,直到叶节点结束,同时输出叶节点的data。
最后,继续重复译码,直到电文结束。
void scanf (HuffNode ht[], HuffCode hcd[], int n) 函数:首先输入需要翻译的译文,存放在cd中,以#号表示结束。
然后,将译文和结点值比较,如果为相同,输出结点值的编码,继续重复翻译,直到译文结束为止。
void print(HuffNode ht[], HuffCode hcd[], int n) 函数:通过记录每个权重的编码个数,然后通过循环,输出哈夫曼树。
void showmenu( )函数:通过printf( )函数显示提示信息。
先定义四个变量、两个结构体数组,通过while ( )函数一直循环,通过switch()函数输入需要执行的项目,然后再所输入的项目中调用相关函数。
5、源代码# include <stdio.h># include <stdlib.h># include<conio.h>typedef char DataType;# define MAXNUM 50typedef struct{DataType data;int weight;int parent;int left;int right;}HuffNode;typedef struct{DataType cd [MAXNUM];int start;}HuffCode;int HuffmanCteate (HuffNode * ht){int i, k, n, m1, m2, p1, p2;printf ("请输入元素个数:");scanf ("%d", &n);for (i=1; i<=n; i++){printf ("第%d个元素的=>\n\t结点值:", i);scanf ("%c", &ht[i].data);printf ("\t 权重:");scanf ("%d", &ht[i].weight);}for (i=1; i<=2*n-1; i++){ht[i].parent = ht[i].left = ht[i].right = 0;}for (i=n+1; i<=(2*n-1); i++){m1 = m2 = 32767;p1 = p2 = 1;for (k=1; k<=i-1; k++)if (ht[k].parent == 0)if (ht[k].weight < m1){m2 = m1;p2 = p1;m1 = ht[k].weight;p1 = k;}else if (ht[k].weight < m2){m2 = ht[k].weight ;p2 = k;}ht[p1].parent = i;ht[p2].parent = i;ht[i].weight = m1 + m2;ht[i].left = p1;ht[i].right = p2;return n;}void Encoding (HuffNode ht[], HuffCode hcd[], int n) {HuffCode d;int i, k, f, c;for (i=1; i<=n; i++){d.start = n+1;c = i;f = ht[i].parent;while (f != 0){if (ht[f].left == c)d.cd[--d.start] = '0';elsed.cd[--d.start] = '1';c = f;f = ht[f].parent;}hcd[i] = d;}printf ("输出哈弗曼编码:\n");for (i=1; i<=n; i++){printf ("%c :", ht[i].data);for (k=hcd[i].start; k<=n; k++)printf ("%c", hcd[i].cd[k]);printf ("\n");}void Decoding (HuffNode ht[], HuffCode hcd[], int n) {int f, m, k;DataType c, ch[200];printf ("请输入电文(0 or 1),以#为结束标志:\n");c = getchar ();k =1;while (c != '#'){ch[k] = c;c = getchar();k = k + 1;}m = k;f = 2 * n - 1;k =1;printf ("输出哈弗曼译码:\n");while (k < m){while (ht[f].left != 0){if (ch[k] == '0')f = ht[f].left ;if (ch[k] == '1')f = ht[f].right ;k++;}printf ("%c", ht[f].data );f = 2 * n - 1;}printf ("\n");}{printf ("******************************\n"); printf ("* 计算机143 王龙王牌冯静*\n"); printf ("******************************\n"); printf ("\n**** 欢迎使用本软件****\n");printf ("\n1-----建立哈弗曼树\n");printf ("2-----编码\n");printf ("3-----译码\n");printf ("4-----印哈夫曼树\n");printf ("5-----译文\n");printf ("6-----退出系统\n\n");printf ("请输入功能序号(请输入1~5数组):"); }void print(HuffNode ht[], HuffCode hcd[], int n) {int i, k, x, y;printf ("输出哈弗曼树为:\n");for (i=1; i<=n; i++){x = 0;for (k=hcd[i].start; k<=n; k++)x++;for (y=0; y<x; y++)printf (" ");printf ("%c", ht[i].data);printf ("\n");}}void scan (HuffNode ht[], HuffCode hcd[], int n) {int f, m, k, i=1;printf ("请输入译文,以#为结束标志:\n");c = getchar ();k =1;while (c != '#'){ch[k] = c;c = getchar();k = k + 1;}m = k;k =1;printf ("输出译文译码:\n");for (k=1; k<m; k++){for (i=1; i<=n; i++){if (ch[k] == ht[i].data){for (f=hcd[i].start; f<=n; f++)printf ("%c", hcd[i].cd[f]);}}}printf ("\n");}int main (){int n, select, flag=0, bug = 0;HuffNode ht[2 * MAXNUM];HuffCode hcd[MAXNUM];while (1){showmenu();scanf ("%d", &select);printf ("\n");if (select != 1 && select != 5 && flag == 0){printf("请先建立哈弗曼树再选择其他功能!\n\n编码已经完成,按任意键继续……\n");getch();system("cls");continue;}flag = 1;switch (select){case 1:n = HuffmanCteate (ht);printf("哈弗曼树已经完成,按任意键继续……\n");getch();system("cls");break;case 2:Encoding (ht, hcd, n);bug = 1;printf("编码已经完成,按任意键继续……\n");getch();system("cls");break;case 3:Decoding (ht, hcd, n);printf("译码已经完成,按任意键继续……\n");getch();break;case 4:if (bug != 1){printf ("请先编码。