哈夫曼编码译码器数据结构C语言
- 格式:doc
- 大小:288.18 KB
- 文档页数:9
一、需求分析目前,进行快速远距离通信的主要手段是电报,即将需传送的文字转化成由二级制的字符组成种字符,只需两个字符的串,便可”,它只有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) 字符,或者在输入一个字符后再输入一个数字。
赫夫曼编\译码器摘要本次课程设计过程中我主要根据课本中的实现思想及算法编写程序,体现以课本知识的应用为主,在学习了线性表、栈、队列、二叉树、树和图等结构的基础上,以能够更加熟练的应用所学知识,并能结合一些著名算法来实现对一些实际问题的应用,例如,赫夫曼树等,从而更为深刻理解数据结构的内涵,熟悉它们各自的应用场合及方法。
有些在平时课程中并没有掌握的内容在这次课程设计中都是先通过看课本学懂了,然后再在课程设计中加深印象,实现算法的应用和扩展。
这次课程设计的设计内容主要是通过实际的例子和程序来实现课本中所学习的算法的应用。
程序设计设计语言采用C++,程序运行平台为Windows XP。
赫夫曼编\译码器的主要功能是先建立赫夫曼树,然后利用建好的赫夫曼树生成哈夫曼编码后进行译码。
赫夫曼编译系统分为五个功能模块:原始数据载入,打印编码规则、编码、译码。
以二叉树的应用为基础,包括统计信息,并通过构建赫夫曼树、对信息进行赫夫曼编码,将编码信息等存入文档。
关键字数据结构栈和队列赫夫曼树赫夫曼编码目录1引言 (1)1.1课程设计目的 (1)1.2课程设计背景 (1)1.3课程设计主要内容 (1)2需求分析 (3)3 概要设计 (4)3.1 设计思想 (4)3.2 函数间的关系 (4)3.3数据结构与算法设计 (4)4详细设计 (6)4.1 赫夫曼的主要结构 (6)5 调试分析 (8)6 测试并列出测试结果 (9)6.1 测试方式 (9)6.2 测试结果 (9)7 总结 (13)致谢 (14)参考文献 (14)附录 (15)1 引言当今社会,计算机技术和通信技术已不断发展,处理和传输的数据量越来越庞大。
如何采用有效的数据压缩技术引起了人们的极大重视。
从而产生了哈夫曼编码,它是一种应用广泛且非常有效的数据压缩技术,该技术一般可将数据压缩20%至90%,通常我们将压缩技术称为编码,解压缩过程称为解码。
树状结构简称为树,是一种以分支关系进行定义的层次结构,是十分重要的非线性数据结构,在计算机软件设计方面,有着广泛的应用。
哈夫曼编码译码器哈夫曼编码译码器a)需求分析:一个完整的系统应具有以下功能:(l)I:初始化。
从终端读入字符集大小n,及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree中。
(2)C:编码。
利用已建好的哈夫曼树(如不在内存,则从文件hfmtree 中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
(3)D:编码。
利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。
(4)P:印代码文件。
将文件codefile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件codeprint中。
(5)T:印哈夫曼树。
将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint 中可以根据题目要求把程序划成5个模块,设计成菜单方式,每次执行一个模块后返回菜单。
除了初始化(I)过程外,在每次执行时都经过一次读取磁盘文件数据。
这是为了如果在程序执行后一直没有进行初始化(I)过程,为了能使后面的操作顺利进行,可以通过读取旧的数据来进行工作。
比如:如果程序的工作需要的字符集和权值数据是固定的,只要在安装程序时进行一次初始(I)化操作就可以了。
在再次运行程序时,不管进行那项操作都可以把需要的数据读入到内存。
b)概要设计本程序主要用到了三个算法。
(1)哈夫曼编码在初始化(I)的过程中间,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。
先将输入的字符和权值存放到一个结构体数组中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
(2)串的匹配在编码(D)的过程中间,要对已经编码过的代码译码,可利用循环,将代码中的与哈夫曼编码的长度相同的串与这个哈夫曼编码比较,如果相等就回显并存入文件。
(3)二叉树的遍历在印哈夫曼树(T)的中,因为哈夫曼树也是二叉树,所以就要利用二叉树的先序遍历将哈夫曼树输出c)详细设计构造树的方法如下:初始化:每个字符就是一个结点,字符的频度就是结点的权;1、将结点按频度从小到大排序;2、选取频度最小的两个结点,以它们为儿子,构造出一个新的结点;新结点的权值就是它两个儿子的权值之和;构造之后,从原来的结点序列里删除刚才选出的那两个结点,但同时将新生成的结点加进去;3、如果结点序列里只剩下一个结点,表示构造完毕,退出。
题目:哈夫曼树编码译码院系:信息工程系专业:计算机科学与技术(网络方向)*名:***学号: **********指导教师:赵莹莹刘欣日期: 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接上面的。
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、概要设计(包括选择什么数据结构?数据结构采用哪种存储方式?选择的原因?设计哪些操作?这些操作之间的调用关系等等)选择了线性数据结构,数据结构采用顺序存储方式,选择的原因:结构简单,可以方便调用任何一个数组,无需为结点间的逻辑关系而增加额外的空间。
哈夫曼编码译码器数据结构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语言实现哈夫曼编码哈夫曼编码是一种用于无损数据压缩的熵编码算法。
以下是一个简单的使用C语言实现哈夫曼编码的例子。
这个例子只实现了编码过程,没有实现解码过程。
c复制代码#include<stdio.h>#include<stdlib.h>#include<string.h>// 节点结构体typedef struct Node {char data;int freq;struct Node *left, *right;} Node;// 创建新节点Node* newNode(char data, int freq) {Node* node = (Node*) malloc(sizeof(Node));node->data = data;node->freq = freq;node->left = node->right = NULL;return node;}// 计算前缀和int getSum(Node* root) {if (!root) return0;return root->freq + getSum(root->left) + getSum(root->right);}// 创建哈夫曼树Node* createHuffmanTree(char data[], int freq[], int size) { if (size == 0) return NULL;Node *left = newNode(data[size-1], freq[size-1]);Node *right = createHuffmanTree(data, freq, size-1);Node *top = newNode(0, getSum(right));top->left = left;top->right = right;return top;}// 打印哈夫曼编码void printHuffmanCode(Node* root, int n, char code[]) {if (!root) return;if (root->data != 0) printf("%c: ", root->data);code[n] = root->data;printHuffmanCode(root->left, n+1, code);printHuffmanCode(root->right, n+1, code);}int main() {char data[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};int freq[] = {5, 9, 12, 13, 16, 45};int size = sizeof(data)/sizeof(data[0]);Node* root = createHuffmanTree(data, freq, size);char code[256] = {0}; // 存放哈夫曼编码,初始为空字符串,表示没有编码,对应字符的编码为空字符串。
摘要;哈夫曼编码是根据字符的使用率的高低对字符进行不等长的编码,从而使使用率高的字符占用较少的空间,从而在传输的过程中大大提高了数据的空间传输效率。
本设计采用二叉链表的存储结构,建立哈夫曼树;用递归调用的方式对哈夫曼树的节点进行编码,生成与字符对应的哈夫曼编码。
本设计完全采用C++语言进行编程,并在XCode 6编译器上调试运行通过。
本程序使用中文界面,并有相应的提示信息,便于操作和程序运行。
关键词:哈夫曼树;哈夫曼编码;递归调用;二叉链表AbstractHuffman coding is based on the level of usage of characters ranging from long coding, so that high usage rate of the characters occupy less storage space , in the course of transmission has greatly enhanced the efficiency of data transmission space. This design build the Huffman tree by using Binary Tree storage structure, encoded Huffman tree nodes by recursive calling, and the characters generate the corresponding Huffman coding. The procedure completely write with C++ language and has Chinese explanatory note. What’s more, i t was debugged in XCode 6 debugger and run well. The whole procedure, with Chinese interface and the corresponding tips ,is convenient to run and easy to be operated.Keywords: Huffman Tree; Huffman code; Recursive call; Binary List目录摘要..................................................................................................................... 错误!未定义书签。
赫夫曼编码/译码器(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。
(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FA VORITE”。
字符 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 11.#include<iostream.h>2.#include<stdio.h>3.#include<stdlib.h>4.#include<string.h>5.#include<fstream.h>6.typedef struct{ //赫夫曼树的结构体7.char ch;8.int weight; //权值9.int parent,lchild,rchild;10.}htnode,*hfmtree;11.typedef char **hfmcode;12.13.void Select(hfmtree &HT,int a,int *p1,int *p2) //Select函数,选出HT树到a为止,权值最小且parent为0的2个节点14.{15.int i,j,x,y;16.for(j=1;j<=a;++j){17.if(HT[j].parent==0){18.x=j;19.break;20.}21.}22.for(i=j+1;i<=a;++i){23.if(HT[i].weight<HT[x].weight&&HT[i].parent==0){24.x=i; //选出最小的节点25.}26.}27.for(j=1;j<=a;++j) {28.if(HT[j].parent==0&&x!=j)29.{30.y=j;31.break;32.}33.}34.for(i=j+1;i<=a;++i)35.{36.if(HT[i].weight<HT[y].weight&&HT[i].parent==0&&x!=i)37.{38.y=i; //选出次小的节点39.}40.}41.if(x>y){42.*p1=y;43.*p2=x;44.}45.else46.{47.*p1=x;48.*p2=y;49.}50.}51.void hfmcoding(hfmtree &HT,hfmcode &HC,int n) //构建赫夫曼树HT,并求出n个字符的赫夫曼编码HC52.{53.int i,start,c,f,m,w;54.int p1,p2;55.char *cd,z;56.if(n<=1){57.return;58.}59.m=2*n-1;60.HT=(hfmtree)malloc((m+1)*sizeof(htnode));61.for(i=1;i<=n;++i) //初始化n个叶子结点62.{63.printf("请输入第%d字符信息和权值:",i);64.scanf("%c%d",&z,&w);65.while(getchar()!='\n')66.{67.continue;68.}69.HT[i].ch=z;70.HT[i].weight=w;71.HT[i].parent=0;72.HT[i].lchild=0;73.HT[i].rchild=0;74.}75.76.for(;i<=m;++i) //初始化其余的结点77.{78.HT[i].ch='0';79.HT[i].weight=0;80.HT[i].parent=0;81.HT[i].lchild=0;82.HT[i].rchild=0;83.}84.for(i=n+1;i<=m;++i) //建立赫夫曼树85.{86.Select(HT,i-1,&p1,&p2);87.HT[p1].parent=i;HT[p2].parent=i;88.HT[i].lchild=p1;HT[i].rchild=p2;89.HT[i].weight=HT[p1].weight+HT[p2].weight;90.}91.92.HC=(hfmcode)malloc((n+1)*sizeof(char *));93.cd=(char *)malloc(n*sizeof(char));94.cd[n-1]='\0';95.96.for(i=1;i<=n;++i) //给n个字符编码97.{98.start=n-1;99.for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) 100.{101.if(HT[f].lchild==c)102.{103.cd[--start]='0';104.}105.else106.{107.cd[--start]='1';108.}109.}110.111.HC[i]=(char*)malloc((n-start)*sizeof(char));112.strcpy(HC[i],&cd[start]);113.}114.free(cd);115.}116.117.118.int main(){119.char code[100],h[100],hl[100];120.int n,i,j,k,l;121.ifstream input_file; //文件输入输出流122.ofstream output_file;123.char choice,str[100];124.hfmtree HT;125.hfmcode HC;126.cout<<"\n";127.128.while(choice!='Q'&&choice!='q') //当choice的值不为q且不为Q时循环129.{130.cout<<" "<<"*************************赫夫曼编码/译码器*************************\n";131.cout<<" "<<"1.输入建立"<<" "<<"2.编码"<<" "<<"3.译码"<<" "<<"Q.退出\n";132.cout<<"请输入您要操作的步骤:";133.cin>>choice;134.if(choice=='1') //初始化赫夫曼树135.{136.cout<<"请输入字符个数:";137.cin>>n;138.hfmcoding(HT,HC,n);139.for(i=1;i<=n;++i)140.{141.cout<<HT[i].ch<<":"<<HC[i]<<endl;142.}143.output_file.open("hfmTree.txt");144.if(!output_file){145.cout<<"can't oen file!"<<endl;146.return 1;147.}148.for(i=1;i<=n;i++)149.{150.output_file<<"("<<HT[i].ch<<HC[i]<<")";151.}152.output_file.close();153.cout<<"赫夫曼树已经创建完毕,并且已经放入hfmTree.txt文件中!"<<endl;154.}155.else if(choice=='2') //进行编码,并将字符放入ToBeTran.txt,码值放入CodeFile.txt中156.{157.printf("请输入字符:");158.gets(str);159.output_file.open("ToBeTran.txt");160.if(!output_file)161.{162.cout<<"can't oen file!"<<endl;163.return 1;164.}165.output_file<<str<<endl;166.output_file.close();167.output_file.open("CodeFile.txt");168.if(!output_file){169.cout<<"can't oen file!"<<endl;170.return 1;171.}172.for(i=0;i<strlen(str);i++){173.for(j=0;j<=n;++j)174.{175.if(HT[j].ch==str[i])176.{177.output_file<<HC[j];178.break;179.}180.}181.}182.output_file.close();183.cout<<"\n";184.cout<<"编码完毕,并且已经存入CodeFile.txt文件!\n";185.input_file.open("CodeFile.txt"); //从CodeFile.txt中读入编码,输出在终端186.if(!input_file)187.{188.cout<<"can't oen file!"<<endl;189.return 1;190.}191.input_file>>code;192.cout<<"编码码值为:"<<code<<endl;193.input_file.close();194.}195.else if(choice=='3') //读入CodeFile.txt中的编码进行译码,将译出来的字符放入Textfile.txt中196.{197.input_file.open("CodeFile.txt");198.if(!input_file){199.cout<<"can't oen file!"<<endl;200.return 1;201.}202.input_file>>h;203.input_file.close();204.output_file.open("Textfile.txt");205.if(!output_file)206.{207.cout<<"can't oen file!"<<endl;208.return 1;209.}210.k=0;211.while(h[k]!='\0') //先用编码中的前几个和字符的编码相比较,然后往后移212.{213.for(i=1;i<=n;i++){214.l=k;215.for(j=0;j<strlen(HC[i]);j++,l++){216.hl[j]=h[l];217.}218.hl[j]='\0';219.if(strcmp(HC[i],hl)==0)220.{221.output_file<<HT[i].ch;222.cout<<HT[i].ch;223.k=k+strlen(HC[i]);224.break;225.}226.}227.}228.output_file.close();229.230.cout<<"译码结束,字符已经存入Textfile.txt文件中!"<<endl;231.}232.else if(choice=='Q'||choice=='q') //退出程序233.{234.exit(0);235.}236.else //如果选了选项之外的就让用户重新选择237.{238.cout<<"您没有输入正确的步骤,请重新输入!"<<endl;239.}240.cout<<endl;241.}242.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中。
哈夫曼编码译码器哈夫曼编码译码器a)需求分析:一个完整的系统应具有以下功能:(l)I:初始化。
从终端读入字符集大小n,及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmtree中。
(2)C:编码。
利用已建好的哈夫曼树(如不在内存,则从文件hfmtree 中读入),对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中。
(3)D:编码。
利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入文件textfile中。
(4)P:印代码文件。
将文件codefile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件codeprint中。
(5)T:印哈夫曼树。
将已在内存中的哈夫曼树以直观的方式 (树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint 中可以根据题目要求把程序划成5个模块,设计成菜单方式,每次执行一个模块后返回菜单。
除了初始化(I)过程外,在每次执行时都经过一次读取磁盘文件数据。
这是为了如果在程序执行后一直没有进行初始化(I)过程,为了能使后面的操作顺利进行,可以通过读取旧的数据来进行工作。
比如:如果程序的工作需要的字符集和权值数据是固定的,只要在安装程序时进行一次初始(I)化操作就可以了。
在再次运行程序时,不管进行那项操作都可以把需要的数据读入到内存。
b)概要设计本程序主要用到了三个算法。
(1)哈夫曼编码在初始化(I)的过程中间,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。
先将输入的字符和权值存放到一个结构体数组中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
(2)串的匹配在编码(D)的过程中间,要对已经编码过的代码译码,可利用循环,将代码中的与哈夫曼编码的长度相同的串与这个哈夫曼编码比较,如果相等就回显并存入文件。
(3)二叉树的遍历在印哈夫曼树(T)的中,因为哈夫曼树也是二叉树,所以就要利用二叉树的先序遍历将哈夫曼树输出c)详细设计构造树的方法如下:初始化:每个字符就是一个结点,字符的频度就是结点的权;1、将结点按频度从小到大排序;2、选取频度最小的两个结点,以它们为儿子,构造出一个新的结点;新结点的权值就是它两个儿子的权值之和;构造之后,从原来的结点序列里删除刚才选出的那两个结点,但同时将新生成的结点加进去;3、如果结点序列里只剩下一个结点,表示构造完毕,退出。
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言文档1.引言本文档介绍了一个基于哈夫曼编码的译码器的设计和实现。
哈夫曼编码是一种无损压缩算法,通过对出现频率较高的符号进行较短的编码,来减小数据的存储或传输所需的空间。
2.哈夫曼编码原理在哈夫曼编码中,使用一颗二叉树,将出现频率较高的符号表示为树的较浅的节点,而出现频率较低的符号表示为树的较深的节点。
通过遍历整个二叉树,可以得到每个符号对应的哈夫曼编码。
2.1 创建哈夫曼树首先,根据每个符号的出现频率,创建一颗包含所有符号的节点的最小堆。
然后,根据最小堆的特性,每次从最小堆中选取两个出现频率最低的节点,并合并为一个新节点。
重复这个过程,直到最小堆中只剩下一个节点,即哈夫曼树的根节点。
2.2 哈夫曼编码通过遍历哈夫曼树,可以得到每个符号对应的哈夫曼编码。
在遍历的过程中,左孩子表示编码中的“0”,右孩子表示编码中的“1”。
每次左移一个位,表示向左遍历,每次右移一个位,表示向右遍历。
3.数据结构设计下面介绍了本文档中所使用的各种数据结构和相关函数的设计。
3.1 结构定义```cstruct Node {char symbol。
int frequency。
struct Node leftChild。
struct Node rightChild。
}。
```3.2 方法定义```c// 创建哈夫曼树struct Node createHuffmanTree(char symbols, int frequencies, int size)// 哈夫曼编码表void generateHuffmanTable(struct Node root, char huffmanTable, char currentCode)// 哈夫曼编码char encode(char data, char huffmanTable)// 哈夫曼译码char decode(char encodedData, struct Node root)```4.实现细节在这个章节中,我们将会具体讨论各个方法的实现细节和使用示例。
C语言—哈夫曼树编码器和译码器#include <stdio.h>#include "stdlib.h"#define MAXBIT 10#define MAXVALUE 10000#define MAXLEAF 100#define MAXNODE MAXLEAF*2-1//定义哈夫曼树编码类型typedef struct {char bit[MAXBIT]; //存放叶子结点字符编码过后的二进制编码int start; //存放叶子结点二进制编码在bit[]数组里的起始数组位置int length; //存放二进制编码的位数}HFMCode;//定义哈夫曼树结点类型typedef struct {char data; //编码字符int weight; //哈夫曼树结点的权值int parent; //哈夫曼树结点的父结点int lchild; //哈夫曼树结点的左孩子int rchild; //哈夫曼树结点的右孩子}HFMNode;//构造哈夫曼树void createHFMTree(HFMNode hfmnode[MAXNODE],int n){int i,j,m1,m2,x1,x2;for(i=0;i<2*n-1;i++){hfmnode[i].weight=0;hfmnode[i].parent=-1;hfmnode[i].lchild=-1;hfmnode[i].rchild=-1;}for(i=0;i<n;i++){getchar();printf("请输入第%d片叶子的字符:",i+1);scanf("%c",&hfmnode[i].data);printf("请输入第%d片叶子的权重:",i+1);scanf("%d",&hfmnode[i].weight);}for(i=0;i<n-1;i++){m1=m2=MAXVALUE; //m1和m2分别用来存储叶子结点权值的最小值和次小值x1=x2=0; //x1和x2分别用来存储m1和m2的位置for(j=0;j<n+i;j++){if(hfmnode[j].weight<m1&&hfmnode[j].parent==-1){m2=m1;x2=x1;m1=hfmnode[j].weight;x1=j;}else if(hfmnode[j].weight<m2&&hfmnode[j].parent==-1){m2=hfmnode[j].weight;x2=j;}}hfmnode[x1].parent=n+i;hfmnode[x2].parent=n+i;hfmnode[n+i].weight=hfmnode[x1].weight+hfmnode[x2].weight;//父结点的权重是左孩子和右孩子的权重之和hfmnode[n+i].lchild=x1;hfmnode[n+i].rchild=x2;}}//显示叶子的编码字符和编码字符对应的二进制编码void showCode(HFMCode hfmcode[MAXNODE],HFMNodehfmnode[MAXNODE],int n){int i,j,k,c,p;HFMCode cd;for(i=0;i<n;i++){hfmcode[i].length=0; hfmcode[i].start=0;k=hfmcode[i].start;cd.start=n-1;c=i;p=hfmnode[c].parent;while(p!=-1){if(hfmnode[p].lchild==c) {cd.bit[cd.start]=0;}else{cd.bit[cd.start]=1;}cd.start--;c=p;p=hfmnode[c].parent;}for(j=cd.start+1;j<n;j++) {hfmcode[i].bit[k]=cd.bit[j];k++;hfmcode[i].length++; //length计算存放的二进制编码的位数}}for(i=0;i<n;i++) //输出每个叶子节点的哈夫曼编码{printf("第%d片叶子的编码是:",i+1);printf("%c\t",hfmnode[i].data);for(j=hfmcode[i].start;j<hfmcode[i].length;j++){printf("%d",hfmcode[i].bit[j]);}printf("\n");}}//输入字符串,得到二进制编码void compileCode(char str[],int n,HFMCode hfmcode[MAXLEAF],HFMNode hfmnode[MAXNODE]){int i,j,k;for(i=0;str[i]!='\0';i++){for(j=0;j<n;j++){if(str[i]==hfmnode[j].data){for(k=hfmcode[j].start;k<hfmcode[j].length;k++){printf("%d",hfmcode[j].bit[k]);}}}}printf("\n\n");}//输入二进制编码得到字符串void decompileCode(char num[],int n,HFMCode hfmcode[MAXLEAF],HFMNode hfmnode[MAXNODE]){int i,j;j=2*n-2; //哈夫曼树根结点的位置for(i=0;num[i]!='\0';i++){if(num[i]=='0'){j=hfmnode[j].lchild;}else if(num[i]=='1'){j=hfmnode[j].rchild;}if(j<n) //j大于等于n表示的都是除叶子结点以外的哈夫曼树结点{printf("%c",hfmnode[j].data);j=2*n-2;}}printf("\n");}//主函数void main(){HFMNode hfmnode[MAXNODE];HFMCode hfmcode[MAXLEAF];char str[100]; //存放输入的需要编译的的字符串char num[100]; //存放输入的需要编译的二进制字符串int n; //输入的叶子结点数//哈夫曼编码器printf("-----------------哈弗曼编码器------------------\n"); printf("请输入叶子结点数:");scanf("%d",&n);createHFMTree(hfmnode,n);showCode(hfmcode,hfmnode,n);//哈夫曼译码器printf("-----------------哈夫曼译码器------------------\n"); printf("请输入编码:\n");scanf("%s",str);compileCode(str,n,hfmcode,hfmnode);printf("请输入需要译码的数字:\n");scanf("%s",num);decompileCode(num,n,hfmcode,hfmnode); }。
哈夫曼编码译码器数据结构C语言哈夫曼编码译码器数据结构C语言引言哈夫曼编码是一种用于无损数据压缩的编码方式,它利用出现频率较高的字符使用较短的编码,而出现频率较低的字符使用较长的编码。
通过这种方式可以使得编码后的数据占据较少的存储空间。
本文将介绍如何使用C语言实现一个哈夫曼编码译码器的数据结构。
哈夫曼树哈夫曼树是哈夫曼编码的关键数据结构,它可以通过给定的字符频率构建出一棵树。
在哈夫曼树中,每个字符都有一个对应的叶子节点,而非叶子节点表示编码的中间过程。
具体构建哈夫曼树的步骤如下:1. 统计每个字符的出现频率。
2. 将每个字符及其频率构建成一个节点,并按照频率从小到大排序。
3. 从频率最小的两个节点开始,合并成一个新节点,并将新节点的频率设为两个节点频率之和。
4. 将新节点插入到节点列表中,保持节点列表有序。
5. 重复步骤3和步骤4,直到只剩下一个节点,这个节点就是哈夫曼树的根节点。
编码在构建了哈夫曼树之后,我们可以根据树的结构来进行编码。
对于每个字符,其编码是由根节点到对应叶子节点路径上的边来表示的。
具体编码的步骤如下:1. 从根节点开始,递归遍历哈夫曼树的每个节点。
2. 如果当前节点为叶子节点,记录下从根节点到该叶子节点所经过的路径上的边的取值(0表示左边,1表示右边),得到该字符的编码。
3. 对于每个字符,将其编码存储起来以便后续使用。
译码译码的过程与编码相反,我们可以根据编码来找到对应的字符。
具体译码的步骤如下:1. 从哈夫曼树的根节点开始,逐个读取待译码的数据。
2. 如果读取的数据为0,移动到左子节点;如果读取的数据为1,移动到右子节点。
3. 如果移动到了叶子节点,记录下该叶子节点对应的字符,并回到根节点。
4. 重复步骤2和步骤3,直到读取完毕所有的数据,得到原始的字符序列。
实现下面是一个用C语言实现的哈夫曼编码译码器的数据结构示例:```cinclude <stdio.h>typedef struct Node {char character;int frequency;struct Node left;struct Node right;} Node;typedef struct HuffmanTree {Node root;} HuffmanTree;HuffmanTree buildHuffmanTree(char characters, int frequencies, int size) {// 构建哈夫曼树的代码实现}void encode(HuffmanTree tree, char string, char encodedString) {// 编码的代码实现}void decode(HuffmanTree tree, char encodedString, char decodedString) {// 译码的代码实现}int mn() {// 测试代码}```总结通过本文,我们了解了哈夫曼编码译码器的数据结构及其在C 语言中的实现。
哈夫曼编码译码器数据结构c语言哈夫曼编码译码器数据结构目录1.引言1.背景2.目的3.范围2.哈夫曼编码概述1.哈夫曼树2.哈夫曼编码3.哈夫曼译码3.数据结构设计1.哈夫曼树结构2.编码表结构3.输入数据结构4.输出数据结构4.算法实现1.哈夫曼树构建算法2.编码表算法3.哈夫曼编码算法4.哈夫曼译码算法5.使用示例1.编码示例2.译码示例6.性能分析1.时间复杂度分析2.空间复杂度分析7.风险和限制1.输入数据限制2.输出数据限制3.算法限制8.附录1.示例代码2.测试数据3.参考文献1.引言1.1 背景哈夫曼编码是一种经典的数据压缩算法,通过构建哈夫曼树,将输入的数据进行编码。
哈夫曼编码的特点是可变长度编码,频率高的字符使用短编码,频率低的字符使用长编码。
1.2 目的本文档旨在详细介绍哈夫曼编码译码器的数据结构设计和算法实现,帮助读者理解和使用该编码器。
1.3 范围本文档涵盖了哈夫曼编码和译码的概述,数据结构设计,算法实现,使用示例以及性能分析。
2.哈夫曼编码概述2.1 哈夫曼树哈夫曼树是一种特殊的二叉树,用于构建哈夫曼编码。
它通过合并两个最小频率的节点来构建树,直到所有节点都被合并。
2.2 哈夫曼编码哈夫曼编码是将字符映射为可变长度的二进制码。
频率高的字符使用短码,频率低的字符使用长码。
编码表中保存了每个字符对应的编码。
2.3 哈夫曼译码哈夫曼译码是根据哈夫曼编码,将二进制码转换为原始字符。
3.数据结构设计3.1 哈夫曼树结构哈夫曼树的结构包含一个根节点和左右子节点。
```ctypedef struct huffmanTreeNode {char data; // 节点字符数据int frequency; // 节点字符出现的频率struct huffmanTreeNode left; // 左子节点指针struct huffmanTreeNode right; // 右子节点指针} huffmanTreeNode;```3.2 编码表结构编码表结构用于保存字符和对应编码的映射关系。
一、需求分析目前,进行快速远距离通信的主要手段是电报,即将需传送的文字转化成由二级制的字符组成的字符串。
例如,假设需传送的电文为“ABACCDA ”,它只有4种字符,只需两个字符的串,便可以分辨。
假设A 、B 、C 、D 、的编码分别为00,01,10和11,则上述7个字符的电文便为“00010010101100”,总长14位,对方接受时,可按二位一分进行译码。
当然,在传送电文时,希望总长尽可能地短。
如果对每个字符设计长度不等的编码,且让电文中出现次数较多的字符采用尽可能短的编码,则传送电文的总长便可减少。
如果设计A 、B 、C 、D 的编码分别为0,00,1,01,则上述7个字符的电文可转换成总长为9的字符串“000011010”。
但是,这样的电文无法翻译,例如传送过去的字符串中前4个字符的字串“0000”就可以有很多种译法,或是“AAAA ”或者“BB ”,或者“ABA ”等。
因此,若要设计长短不等的编码,则必须是任一字符的编码都不是另一个字符的编码的前缀,这种编码称作前缀编码。
然而,如何进行前缀编码就是利用哈夫曼树来做,也就有了现在的哈夫曼编码和译码。
二、概要设计利用哈夫曼树编/译码 (一)、建立哈夫曼树 (二)、对哈夫曼树进行编码 (三)、输出对应字符的编码 (四)、译码过程主要代码实现: 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); //译码三、 详细设计(一)、建立哈夫曼树2 3 4 5 * * * 6 7序号:权值: 1 2 3 4 3 6 10 6 图3-1 图(二)、对哈夫曼树进行编码主要代码实现:for(c=i,f=p[i].parent;f!=0;c=f,f=p[f].parent){if(p[f].lchild==c) //左孩子编码为'0'{cd[--start]='0';}else //右孩子编码为'1'{cd[--start]='1';}}(三)、输出对应字符的码(四)、译码过程主要代码实现:if(strcmp(a,hc[i])==0) //比较两个字符串是否相等,相等则输出0 {for(c=2*n-1,j=0;a[j]!='\0';j++) //从根出发,按字符'0'或'1'确定找左孩子或右孩子{if(a[j]=='0') //左孩子{c=p[c].lchild;}else{c=p[c].rchild; //右孩子}}图3-4表3-1从叶子到根逆向求编码从跟到叶子顺向求字符图3-5四、调试分析(一)、数字的输入判断图4-1(二)、字母的输入判断图4-2(三)、程序是否继续进行的判断图4-3五、用户手册(一)、首先根据提示输入初始化数据,提示输入一个数字,请输入一个数a,0<a<9999;提示输入一个字母,则请输入一个字母(a~z)或者(A~Z)中的一个字符;请勿在输入一个数字后再输入一个字符,或者在输入一个字符后再输入一个数字。
(二)在某一界面结束后,会有“请按回车继续下面操作”提示,请按提示进行操作,如输入其他数字则无效,知道输入回车符界面才会跳转。
(三)对界面的操作可以自行选择,在询问是否译码的时候,请按要求进行选择,在一次译码结束后会询问是否继续译码,如需要则输入y或者Y,输入其他字符则退出程序。
六、测试结果(一)、初始化图6-1(二)、建立哈夫曼树(三)、哈夫曼编码(四)、哈夫曼译码(五)、错误判定图6-2图6-3图6-4 图6-5附录:源代码:#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>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 translate(char **hc,code *p,int n);//译码void display(code *p,int n,int m); //输出函数//主函数void main(){int i,n,m;code *ht;printf("字符的数量:\n(请输入一个大于0的数字,输入多个数字则按第一个数字运行)\n");while(scanf("%d",&n)!=1||n<0||n>9999){printf("重新输入:\n");fflush(stdin);}m=2*n-1; //哈夫曼树中没有度为1的结点,故含有m=2n-1个结点ht=(code*)malloc((m+1)*sizeof(code));//动态申请内存for(i=1;i<=n;i++) //对1~n的数进行初始化{printf("输入编码中的字符(请输入一个字母):\n");fflush(stdin);scanf("%c",&ht[i].a);while(!(ht[i].a>'a'||ht[i].a<'z'||ht[i].a>'A'||ht[i].a<'Z')){printf("重新输入:\n");fflush(stdin);scanf("%c",&ht[i].a);//清空输入缓冲区,往往是确保不影响后面数据的读取}printf("输入字符的权值(请输入一个数字):\n");while(scanf("%d",&ht[i].w)!=1||ht[i].w<0||ht[i].w>9999){printf("重新输入:\n");fflush(stdin); //清空输入缓冲区,往往是确保不影响后面数据的读取}ht[i].lchild=0;ht[i].rchild=0;ht[i].parent=0;}for(i=n+1;i<=m;i++) //对n+1~2n-1的数进行初始化{ht[i].a='*';ht[i].w=0;ht[i].lchild=0;ht[i].rchild=0;ht[i].parent=0;}creation(ht,n,m);printf("请按回车进入哈夫曼树对应界面\n");getchar();getchar();system("cls");display(ht,n,m);printf("请按回车进入编码对应界面\n");getchar();system("cls");coding(ht,n);getchar();}void creation(code *ht,int n,int m){int i,j,m1,m2,t1,t2;for(i=n+1;i<=m;i++){j=1; //找到第一个最小值(双亲不为0)while(ht[j].parent!=0) //找到表中第一个没有双亲的结点{j++;}t1=ht[j].w;m1=j;for(j=m1+1;j<=m;j++){if(ht[j].parent==0&&ht[j].w!=0)//条件(ht[j].w!=0)是因为n~2n-1的权值初始值为0{if(ht[j].w<t1){t1=ht[j].w;m1=j;}}}ht[m1].parent=i; //第一个值的双亲为ht[i]ht[i].lchild=m1; //h[i]的的左孩子是最小值的序号j=1; //剩余中找到第二个最小值(双亲不为0)while(ht[j].parent!=0){j++;}t2=ht[j].w;m2=j;for(j=m2+1;j<=m;j++){if(ht[j].parent==0&&ht[j].w!=0){if(ht[j].w<t2){t2=ht[j].w;m2=j;}}}ht[m2].parent=i; //第二个值的双亲为ht[i]ht[i].rchild=m2; //h[i]的的左孩子是最小值的序号ht[i].w=t1+t2; //h[i]的权值是找到的两个值的权值之和}}void coding(code *p,int n){int i,c,f;char **hc; //指针的指针char *cd;char ch;int start;hc=(char**)malloc((n+1)*sizeof(char *)); //分配n个字符编码的头指针向量cd=(char*)malloc(n*sizeof(char)); //分配求编码的工作空间cd[n-1]='\0'; //编码结束符for(i=1;i<=n;i++){start=n-1;for(c=i,f=p[i].parent;f!=0;c=f,f=p[f].parent)//从叶子到根逆向求编码{if(p[f].lchild==c) //左孩子编码为'0'{cd[--start]='0';}else //右孩子编码为'1'{cd[--start]='1';}}hc[i]=(char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间strcpy(hc[i],&cd[start]); //从cd复制编码(串)到hc,&是取地址符,即取首地址,从start位置到'\0'的编码为止。
}free(cd); //释放工作空间printf("\n输出编码后的结果:\n");printf("符号数码\n");for(i=1;i<=n;i++){printf("\n%c %s\n",p[i].a,hc[i]);}printf("是否进行译码操作,是则译码,否则退出程序!\n是(输入y/Y)否(输入其他字符)\n");scanf("%d",&ch);if(ch=='y'||ch=='Y'){translate(hc,p,n);}elseexit(0);}void translate(char **hc,code *p,int n){char a[10],ch;int i,j,c;do{printf("\n\n\n请输入编码:\n");scanf("%s",a); //回车之后会自动生成'\0'for(i=1;i<=n;i++){if(strcmp(a,hc[i])==0) //比较两个字符串是否相等,相等则输出0{for(c=2*n-1,j=0;a[j]!='\0';j++) //从根出发,按字符'0'或'1'确定找左孩子或右孩子{if(a[j]=='0') //左孩子{c=p[c].lchild;}else{c=p[c].rchild; //右孩子}}printf("字符是:\n");printf("%c\n",p[c].a);break;}}if(i>n){printf("编码不存在对应的字符!\n");}printf("是否继续输入?是(输入y或者Y)否(其他)\n");fflush(stdin);scanf("%c",&ch);}while(ch=='y'||ch=='Y');}void display(code *p,int n,int m){int i;printf("\n序号码值权值双亲左孩子右孩子\n");for(i=1;i<=m;i++){printf("%d %c %d %d %d %d\n",i,p[i].a,p[i].w,p[i].parent,p[i].lchild,p[i].rchild);}}设计体会通过这个课程设计,让我对数据结构这门课程有了更深一步的了解,对以后的深造奠定了基础。