哈夫曼编码译码系统
哈夫曼编译码系统
{
k=bt[i].weight;
temp=i;
break;
}
for(i=i+1;i<m;i++)//逐个与其他权值进行比较,并返回在parent为0下权值最小的序号
if(bt[i].weight < k && bt[i].parent == 0)
{
k=bt[i].weight;
{
fscanf(fp,"%c",&c[i]);
if(c[i]=='\n') continue;//读到换行符,跳过,读下一行
fscanf(fp,"%5d",&w[i]);
count++;
i++;
}
fclose(fp);
}
//将内容写入文件
void WriteDataFile(char *fileName)
printf("\t* *\t\n");
printf("\t* **哈夫曼编译码系统** *\t\n");
printf("\t* *\t\n");
printf("\t* *\t\n");
printf("\t* 1.更新哈夫曼编码信息*\t\n");
printf("\t* *\t\n");
printf("\t* 2.显示哈夫曼树及哈夫曼编码*\t\n");
(*s2)=Min(ht,m);
}
//构造哈夫曼树
void CreateHuffmanTree(HuffmanTree *HT,int n)
哈夫曼编码译码系统实验报告,数据结构课程设计报告
v .. . ..安徽大学数据结构课程设计报告项目名称:哈弗曼编/译码系统的设计与实现姓名:鉏飞祥学号:E21414018专业:软件工程完成日期2016/7/4计算机科学与技术学院1 .需求分析1.1问题描述•问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(解码)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站设计一个哈夫曼编译码系统。
1.2基本要求(1)输入的形式和输入值的范围;(2)输出的形式;(3)程序所能达到的功能。
1.基本要求(1)初始化(Initialzation)。
从数据文件DataFile.data中读入字符及每个字符的权值,建立哈夫曼树HuffTree;(2)编码(EnCoding)。
用已建好的哈夫曼树,对文件ToBeTran.data中的文本进行编码形成报文,将报文写在文件Code.txt中;(3)译码(Decoding)。
利用已建好的哈夫曼树,对文件CodeFile.data中的代码进行解码形成原文,结果存入文件Textfile.txt中;(4)输出(Output)。
输出DataFile.data中出现的字符以及各字符出现的频度(或概率);输出ToBeTran.data及其报文Code.txt;输出CodeFile.data及其原文Textfile.txt;2. 概要设计说明本程序中用到的所有抽象数据类型的定义。
主程序的流程以及各程序模块之间的层次(调用)关系。
(1)数据结构哈夫曼树的节点struct huff{int weight;int parent;int l;int r;};哈夫曼编码的存储struct huff *hufftree;(2)程序模块选择1到i-1中parent为0且权值最小的两个下标void Select(struct huff *HT, int n, int &s1, int &s2)构建哈夫曼树:void huffmancoding(struct huff *ht,int *w,int n)对原文进行编码:void code(char *c)根据报文找到原文:void decoding(char *zifu)3. 详细设计核心技术分析:1:构建哈夫曼树及生成哈夫曼编码:根据每个字符权值不同,根据最优二叉树的构建方法,递归生成哈夫曼树,并且用数组存放哈夫曼树。
哈夫曼编码译码系统
《数据结构》课程设计6.5电文的编码和译码姓名: XXX院系: 计算机学院专业: 计算机科学与技术年级: 13级学号: E11314XXX指导教师:XXX2015年10月30 日目录1.课程设计的目的 (3)2.需求分析 (3)3电文的编码和译码的设计 (3)3.1概要设计 (3)3.1.1 主界面设计 (3)3.1.2 存储结构 (4)3.1.3 系统功能设计 (4)3.2详细设计 (4)3.2.1 系统子程序及功能设计 (4)3.2.2 数据类型定义 (6)3.2.3 系统主要子程序详细设计 (7)3.3调试分析 (11)3.4用户手册 (12)4总结 (12)5、程序清单:(见附录) (13)7、程序运行结果 (13)附录1 (18)1.课程设计的目的(1) 熟练使用C 语言编写程序,解决实际问题;(2) 了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力;(3) 初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能;(4) 提高综合运用所学的理论知识和方法独立分析和解决问题的能力。
2.需求分析(1)为信息收发站写一个哈夫曼编/译码系统。
(2)要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
(3)要求可以将哈夫曼树以树状或凹入法打印到屏幕。
3电文的编码和译码的设计3.1概要设计3.1.1 主界面设计图1主界面,如图1所示,包含初始化,编码,译码,代码文件,哈夫曼树五个菜单。
其中,菜单1用来从终端读入n个字符和n个权值,建立哈夫曼树,并将它存于文件中; 菜单2用来利用已建好的哈夫曼树,对文件中或直接输入的正文进行编码,然后将结果存入文件中,如果哈夫曼树不在内存可通过初始化或文件读入到内存;菜单3利用已建好的哈夫曼树将文件中的代码进行译码,译码结果存入文件中,若哈夫曼树不在内存中,处理方式与菜单2相同;菜单4将编码文件以紧凑格式显示在终端上,每行50个代码,同时将此字符形式的编码写入文件中;菜单5将已在内存中的哈夫曼树以凹入法显示在终端上。
哈夫曼编码译码器系统
具体介绍:在本课题中,我们在硬盘E盘中预先建立一个file1.txt文档,在里面编辑一篇文章(大写)。
然后运行程序,调用fileopen()函数读出该文章,显示在界面;再调用jsq()函数对该文章的字符种类进行统计,并对每个字符的出现次数进行统计,并且在界面上显示;然后以每个字符出现次数作为权值,调用ChuffmanTree()函数构建哈夫曼树;并调用print1()和print2()函数将哈夫曼的存储结构的初态和终态进行输出。
然后调用HuffmanEncoding()函数对哈夫曼树进行编码,调用coding()函数将编码写入文件;再调用decode()对编码进行译码,再输出至界面。
至此,整个工作就完成了。
测试数据:例如从文本中读到文章为:IAMASTUDENT。
则效果如下:IAMASTUDENT--------------------------------------HuffmanTree的初态:200010001000100010001000100020001000-000-000-000-000-000-000-000-000--------------------------------------字符A次数:2字符D次数:1字符E次数:1字符I次数:1字符M次数:1字符N次数:1字符S次数:1字符T次数:2字符U次数:1--------------------------------------HuffmanTree的终态:21300110001100011100111001120011200214001130021423215452156731691416810417111271713141101516--------------------------------------译码后的字符串:IAMASTUDENT********************************************************** Press any key to continue文档由风行播放器/暴风影音2014:/整理3系统(项目)设计(1)设计思路及方案本课题是用最优二叉树即哈夫曼树来实现哈夫曼编码译码器的功能。
哈夫曼编码译码器数据结构C语言
哈夫曼编码译码器数据结构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`:编码⒋算法流程⑴字符频率统计算法步骤:⒈初始化频率统计表为空。
⒉读取待编码的数据。
哈夫曼编码译码系统
《数据结构》课程设计——赫夫曼编码/译码器设计指导教师:孙树森、周维达班级:09数媒(2)班学号:E09700227姓名:曾焕凯数据结构课程设计报告书一、实验目的1、提高分析问题、解决问题的能力,进一步巩固数据结构各种原理与方法。
2、熟悉掌握一门计算机语言,可以进行数据算法的设计。
二、实验原理1、哈夫曼树的定义:假设有n 个权值,试构造一颗有n 个叶子节点的二叉树,每个叶子带权值为wi,其中树带权路径最小的二叉树成为哈夫曼树或者最优二叉树;2、哈夫曼树的构造:weight 为输入的频率数组,把其中的值赋给依次建立的HT Node 对象中的data 属性,即每一个HT Node 对应一个输入的频率。
然后根据data 属性按从小到大顺序排序,每次从data 取出两个最小和此次小的HT Node,将他们的data 相加,构造出新的HTNode 作为他们的父节点,指针parent,leftchild,rightchild 赋相应值。
在把这个新的节点插入最小堆。
按此步骤可以构造构造出一棵哈夫曼树。
通过已经构造出的哈夫曼树,自底向上,由频率节点开始向上寻找parent,直到parent 为树的顶点为止。
这样,根据每次向上搜索后,原节点为父节点的左孩子还是右孩子,来记录1 或0,这样,每个频率都会有一个01 编码与之唯一对应,并且任何编码没有前部分是同其他完整编码一样的。
三、实验步骤先统计要压缩编码的文件中的字符字母出现的次数,按字符字母和空格出现的概率对其进行哈夫曼编码。
然后读入要编码的文件,编码后存入另一个文件;接着再调出编码后的文件,并对其进行译码输出,最后存入另一个文件中。
具体步骤:1.初始化,统计文本文件中各字符的个数作为权值,生成哈夫曼树;2.根据符号概率的大小按由大到小顺序对符号进行排序;3.把概率最小的两个符号组成一个节点;4.重复步骤2. 3 ,直到概率和为1;5.从根节点开始到相应于每个符号的“树叶”,概率大的标“0”,概率小的标“1”;6.从根节点开始,对符号进行编码;7.译码时流程逆向进行,从文件中读出哈夫曼树,并利用哈夫曼树将编码序列解码。
哈夫曼编码译码器系统.
目录一、系统开发的背景 (1)二、系统分析与设计 (1)三、系统的设计与实现 (2)(一)设计初始化(Initialization) (2)(二)设计编码(Encoding) (3)(三)设计译码(Decoding) (3)(四)设计印代码文件(Print) (4)(五)设计印哈夫曼树(TreePrinting) (4)四、系统测试 (5)(一)测试main函数 (5)(二)测试编码(Encoding)及译码(Decoding)函数 (5)(三)测试印代码文件(Print)函数 (6)(四)测试相关的根目录 (6)五、总结 (6)六、附件(代码、部分图表) (7)哈夫曼编/译码器系统一、系统开发的背景为了提高信道利用率,缩短信息传输时间,降低传输成本,且在信息发送端通过一个编码系统对待传数据预先编码,在信息接收端将传来的数据进行译码(复原),因此设计哈夫曼编码/译码器系统。
二、系统分析与设计(一)系统功能要求:【任务要求】I:初始化(Initialization)。
从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。
E:编码(Encoding)。
利用以建好的哈夫曼树(如不在内存,则从文件hfmTree 中读入),对文件To Be Tran中的正文进行编码,然后将结果存入文件CodeFile 中。
D:译码(Decoding)。
利用已建好的哈夫曼树将文件Code File中的代码进行译码,结果存入文件Text File中。
P:印代码文件(Print)。
将文件Code File以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件Code Prin中。
T:印哈夫曼树(Tree Printing)。
将已在内存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件Tree Print中。
【测试数据】利用教科书中的数据调试程序。
数据结构实验,哈夫曼编码译码系统
数据结构实验,哈夫曼编码译码系统展开全文1. 实验名称: 二叉树的基本操作及哈夫曼编码译码系统的实现2.实验目的:创建一棵二叉树,实现先序、中序和后序遍历一棵二叉树,计算二叉树结点个数等操作。
哈夫曼编码/译码系统。
3. 实验任务:能成功演示二叉树的有关运算,运算完毕后能成功释放二叉树所有结点占用的系统内存。
4. 实验内容(1)在二叉链表上实现二叉树运算a) 设计递归算法,实现二叉树的基本运算:删除一棵二叉树,求一棵二叉树的高度,求一棵二叉树中叶子结点数,复制一棵二叉树,交换一棵二叉树的左右子树。
b) 设计算法,按自上到下,自左到右的次序,即按层次遍历一棵二叉树。
c) 设计main函数,测试上述每个运算。
d) 提示:队列结构可以辅助进行层次遍历,队列的元素类型是指向二叉树结点的指针类型。
(2)哈夫曼编码和译码系统a) 设计一个菜单可以循环显示B——建树:读入字符集和各字符频度,建立哈夫曼树。
T——遍历:先序和中序遍历二叉树。
E——生成编码:产生每个字符的哈夫曼编码。
C——编码:输入由字符集中字符组成的任意字符串,利用已经生成的哈夫曼编码进行编码,显示编码结果。
D——译码:利用已建成的哈夫曼树进行译码。
X——退出。
b) 提示:修改二叉树结点类BTNode,增加一个指向双亲的parent域,修改二叉树类的函数MakeTree设置该域的值;可以通过遍历哈夫曼树生成每个叶子结点的哈夫曼编码。
5. 概要设计1) 二叉树首先定义结点类BTNode包括对结点的访问,打印,交换结点左右元素等操作。
并将二叉树类BTree声明为友元类。
二叉树类中包含了建树,判断二叉树是否为空,求结点数,求高度,删除,交换左右子树,三种次序遍历及按层次遍历,清空二叉树等函数。
在主函数中调用实现这些功能。
类和类的层次设计主要算法:PreOrder:输出当前结点元素,左右孩子递归调用函数。
InOrder:左孩子递归调用函数,输出当前结点元素,右孩子递归调用。
哈夫曼编码和译码系统(附源代码)
实训报告题目:哈夫曼编码和译码系统院系:专业:姓名:学号:指导教师:日期:一.需求分析•二.概要设计(1)建立哈夫曼树、编码•(2)字符匹配•(3)哈夫曼树遍历• 3三.详细设计及编码实现•3四.流程图(1)总流程图75(2)编码实现流程图・16(3)译码实现流程图・17五.调试分析(1 )计算权值-18(1)生成哈夫曼树,建立编码表• 18 (3)将输入字符编码 19( 4 )输入新的字符串,进行译码 19( 5)输入新的二进制数将其译为字符 20六 . 系统维护 20 七.实验总结 20八. 源代码 21一.需求分析《1》问题描述:在传送电文时,人们总是希望传送时间尽可能短,这就是要求使电文代码长度尽可能短。
利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统能够对待传输数据预先编码,在接收端将传来的数据进行译码。
对于双工信道(即可以双向传输信息的信道),每段都需要一个完整的编/译系统。
所以为这样的信息收发站写一个哈夫曼的编译码系统。
《2》打开一篇英文文章,统计该文章中每个字符出现的次数,然后以它们作为权值,对每一个字符进行编码,编码完成后再对其编码进行译码。
问题补充:1.从硬盘的一个文件里读出一段英语文章。
2.统计这篇文章中的每个字符出现的次数。
3.以字符出现字数作为权值,构建哈夫曼树,并将哈夫曼树的存储结构的初态和终态进行输出。
4.对每个字符进行编码并将所编码写入文件然后对所编码进行编译。
《3》这个哈夫曼编码译码主要是以英文字母输入进行编码与编译,编码译码过程由系统自动完成,人工操作部分就是电文的录入,和编译出来时的读操作。
.概要设计本程序主要用到了三个算法。
(1)哈夫曼树建立、编码在初始化(I)的过程中间,要用输入的字符和权值建立哈夫曼树并求得哈夫曼编码。
先将输入的字符和权值存放到一个结构体数组中,建立哈夫曼树,将计算所得的哈夫曼编码存储到另一个结构体数组中。
哈夫曼编译码系统实验报告
数学与计算机学院数据结构实验报告年级大二学号********* 姓名******* 成绩专业电气信息类(计算机)实验地点主楼402 指导教师实验项目实验日期2010年11月20日一、实验目的和要求通过对简单哈夫曼编/译码系统的设计与实现来熟练掌握树型结构在实际问题中的应用。
此实验可以作为综合实验,阶段性实验时可以选择其中的几个功能来设计和实现。
二、问题描述利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(复原)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发编写一个哈夫曼码的编/译码系统。
三、数据结构设计1、构造哈夫曼树时使用静态链表作为哈夫曼树的存储。
在构造哈夫曼树时,设计一个结构体数组HuffNode保存哈夫曼树中各结点的信息,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,所以数组HuffNode的大小设置为2n-1;描述结点的数据类型为:struct HNodeType{char data; //结点字符int weight;//结点权值int parent;int lchild;int rchild;int level;};2、求哈夫曼树编码时使用一维结构数组HuffCode作为哈夫曼编码信息的存储。
求哈夫曼编码,实质上就是在已建立的哈夫曼树中,从叶子结点开始,沿结点的双亲链域回退到根结点,每回退一步,就走过了哈夫曼树的一个分支,从而得到一位哈夫曼码值,由于一个字符的哈夫曼编码是从根结点到相应叶子结点所经过的路径上各分支所组成的0、1序列,因此先得到的分支代码为所求编码为所求编码的低位码,后得到的分支代码为所求编码的高位码,所以设计如下数据类型:struct HCodeType{int bit[MAXBIT];int start;};3、文件hfmtree.txt、codefile.txt、textfile.txt。
课程设计报告--哈夫曼编码译码系统
2.定义代表森林的数组,在创建哈夫曼树的过程当中保存被选中的字符,即给定报文中出现的字符,模拟哈夫曼树选取和删除左右子树的过程;
3.自底而上地创建哈夫曼树,保存根的地址和每个叶节点的地址,即字符的地址,然后自底而上检索,首尾对换调整为哈夫曼树实现哈弗曼编码;
随着计算机的普遍应用与日益发展,其应用早已不局限于简单的数值运算,而涉及到问题的分析、数据结构框架的设计以及设计最短路线等复杂的非数值处理和操作。算法与数据结构的学习就是为以后利用计算机资源高效地开发非数值处理的计算机程序打下坚实的理论、方法和技术基础。
算法与数据结构旨在分析研究计算机加工的数据对象的特性,以便选择适当的数据结构和存储结构,从而使建立在其上的解决问题的算法达到最优。
4.定义hufnode类型的全局数组hufNode[256],在编码时最为哈夫曼编码对照表的节点,char型c保存字符,int code[100]保存其哈夫曼编码;
5.定义HFM类,主要保存哈夫曼树的根节点指针,但其丰富的功能函数将实现哈夫曼编码译码的工作及其他功能;
函数介绍:
1.void init(signode * sig){……}初始化数组SN[];
数据结构是在整个计算机科学与技术领域上广泛被使用的术语。它用来反映一个数据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。数据结构有逻辑上的数据结构和物理上的数据结构之分。逻辑上的数据结构反映成分数据之间的逻辑关系,而物理上的数据结构反映成分数据在计算机内部的存储安排。数据结构是数据存在的形式。
《数据结构》主要介绍一些最常用的数据结构,阐明各种数据结构内在的逻辑关系,讨论其在计算机中的存储表示,以及在其上进行各种运算时的实现算法,并对算法的效率进行简单的分析和讨论。数据结构是介于数学、计算机软件和计算机硬件之间的一门计算机专业的核心课程,它是计算机程序设计、数据库、操作系统、编译原理及人工智能等的重要基础,广泛的应用于信息学、系统工程等各种领域。
哈夫曼编码译码器
default : printf("%c", p+96);
}
p1 = p; //让p1记住p
p = 59; //这里p要重置为59,因为经过上面的程序p已经变化了,不重置为1则HT[p].lchild!=0||HT[p].rchild!=0所以for语句无法进行!!!!
RedType r[MAXSIZE+1]; //r[0]闲置用作哨兵
int length; //顺序表长度
}SqList;
/**************************************************全局变量*************************************************************/
HuffmanTree HT; //赫夫曼树
HuffmanCode HC; //码值
FILE *fp, *fp1, *fp2;
int a[30] = {0};
float b[30];
void minweight()
{
float Weight = 0;
int i;
for (i = 0 ; i < 30 ; i++)
Weight = Weight + strlen(HC[i+1])*b[i];
printf("最小权值是:%f\n",Weight);
float *w; //权
/****************************************测试解码(可以输入一个不正确的二进制码串)**************************************/
数据结构课程设计哈夫曼编码译码器
题目一: 哈夫曼编码与译码一、任务设计一个运用哈夫曼算法的编码和译码系统, 反复地显示并解决以下项目, 直到选择退出为止。
规定:1) 将权值数据存放在数据文献(文献名为data.txt, 位于执行程序的当前目录中) ;2) 初始化:键盘输入字符集记录字符权值、自定义26个字符和26个权值、记录文献中一篇英文文章中26个字母, 建立哈夫曼树;3) 编码: 运用建好的哈夫曼树生成哈夫曼编码;4) 输出编码(一方面实现屏幕输出, 然后实现文献输出);5)译码(键盘接受编码进行译码、文献读入编码进行译码);6) 界面优化设计。
二、流程图三、代码分解 //头文献 #include<stdio.h> #include<string.h> #include<stdlib.h> #include <conio.h> #define N 1000 #define M 2*N-1 #define MAXcode 6000 //函数声明void count(CHar &ch,HTNode ht[]);void editHCode(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); //编码函数void printyima(HTNode ht[],HCode hcd[],int n,char bianma[]); //译码函数 void creatHT(HTNode ht[],int n);字符集记录符集记录权值 权值 至文献“哈夫曼树。
t xt” 菜单1.从键盘输入字符集进行编码2.从文献读入字符集进行编码1.从键盘输入编码进行译码2.从文献读入编码进行译码0.返回上级菜单 0.返回上级菜单void CreateHCode (HTNode ht[],HCode hcd[],int n);void DispHCode(HTNode ht[],HCode hcd[],int n);void input_key(CHar &ch);void input_file(CHar &ch);void input_cw(HTNode ht[]);void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]); void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]);void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]);void creat_cw();void bianmacaidan();void yimacaidan();void bianmayima();int caidan();//结构体typedef struct{char data;int parent;int weight;int lchild;int rchild;}HTNode;typedef struct{char cd[N];int start;}HCode;typedef struct{char s[N];int num;}CHar;CHar ch;HTNode ht[M];HCode hcd[N];//主函数int main(){int xh;while(1){system("color 1f"); //操作菜单背景颜色 xh=caidan(); //调用菜单函数switch(xh) //switch语句 {case 1:system("cls");creat_cw();break;case 2:system("cls");creatHT(ht,n);break;case 3:system("cls");CreateHCode(ht,hcd,n);DispHCode(ht,hcd,n);break;case 4:system("cls");bianmayima();break;case 0:system("cls");printf("\n\n\n\n\n\n\n\n\n\t\t\t\t感谢使用本系统!\n\n\n\n\n\n\n \t\t\t");exit(0);default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}return 0;}//菜单函数int caidan() //菜单函数模块//{int xh;printf("\n\n\n");printf("\t\t 欢迎使用哈夫曼编码译码系统\n");printf("\t\t \n");printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n");printf("\t\t*= =*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n");printf("\t\t*= 1.建立字符权值=*\n");printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 2.建立并输出哈夫曼树=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 3.生成并查看哈夫曼编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 4.编码与译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*= =*\n"); printf("\t\t*= 0.退出系统=*\n"); printf("\t\t*= =*\n"); printf("\t\t*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d", &xh);return xh; //返回从键盘接受的选项}void bianmayima(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码与译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n");printf("\t\t*= 1.编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianmacaidan();break;case 2:system("cls");yimacaidan();break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void yimacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 译码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入编码进行译码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");yima1(ht,hcd,n,bianma);break;case 2:system("cls");yima2(ht,hcd,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void bianmacaidan(){int xh;while(1){printf("\n\n\n\n\n");printf("\t\t 编码\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.键盘输入字符集编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.文献读入文章编码=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh);switch(xh) //switch语句{case 1:system("cls");bianma1(ht,hcd,ch,n,bianma);break;case 2:system("cls");bianma2(ht,hcd,ch,n,bianma);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}void creat_cw(){int xh2;while(1){printf("\n\n\n\n\n");printf("\t\t 建立字符权值\n"); printf("\t\t \n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 1.从键盘输入字符集进行记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 2.从文献读入字符集记录=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 3.自定义字符权值=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\t\t*= 0.返回上级菜单=*\n"); printf("\t\t*= *=*=*=*=*=*=*=*=*=*=*=*=*=*=* =*\n"); printf("\n\t\t请输入序号进行选择:");scanf("%d",&xh2);switch(xh2) //switch语句{case 1:system("cls");input_key(ch);break;case 2:system("cls");input_file(ch);break;case 3:system("cls");input_cw(ht);break;case 0:system("cls");return;default:system("cls");putchar('\a');printf("\n\t\t输入有误, 请重新输入:\n");break;}}}//建立字符权值模块void input_key(CHar &ch){int i,j=0;char st[N];printf("请输入字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&st[i]);if(st[i]=='#'){st[i]='\0';break;}}strcpy(ch.s,st);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_file(CHar &ch){int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的字符集为:%s\n",ch.s);fclose(fp);count(ch,ht);printf("按任意键返回!");getch();system("cls");return;}void input_cw(HTNode ht[]){int i,w,s,j;char a;printf("要输入的字符总个数是?:");scanf("%d",&s);n=s;printf("请输入字符及其权值:\n");for(i=0;i<s;i++){printf("请输入第%d个字母:",i+1);scanf("%s",&a);ht[i].data=a;printf("请输入其权值:");scanf("%d",&w);ht[i].weight=w;}FILE *fp;if((fp=fopen("data.txt","w"))==0){printf("\n\t\t文献打开失败");return;}printf("\n定义权值成功!\n\n");printf("各字符及其权值为:\n\n");fprintf(fp,"各字符及其权值为:\n");printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<i;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight); }printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);printf("输入完毕, 按任意键返回!");getch();system("cls");return;}//记录字符权值函数void count(CHar &ch,HTNode ht[]){int i,j,m=0;char c[N];int sum[N]={0};for(i=0;ch.s[i]!='\0';i++){for(j=0;j<m;j++)if(ch.s[i]==c[j]||(c[j]>='a'&&c[j]<='z'&&ch.s[i]+32==c[j])) break;if(j<m)sum[j]++;else{if(ch.s[i]>='A'&&ch.s[i]<='Z')c[j]=ch.s[i]+32;else c[j]=ch.s[i];sum[j]++;m++;}}for(i=0;i<m;i++){ht[i].data=c[i];ht[i].weight=sum[i];}n=m;FILE *fp;if((fp=fopen("data.txt","w"))==0) {printf("\n\t\t文献打开失败"); return;}printf("\n记录权值成功!\n\n"); printf("各字符及其权值为:\n\n"); fprintf(fp,"各字符及其权值为:\n"); printf(" 字符\t权值");fprintf(fp," 字符\t权值");for(j=0;j<m;j++){ printf("\n");fprintf(fp,"\n");printf(" %-8c%-8d",ht[j].data,ht[j].weight);fprintf(fp," %-8c%-8d%",ht[j].data,ht[j].weight);}printf("\n");printf("\n字符权值已输出至文献“data.txt”!");fclose(fp);}//构造哈夫曼树void creatHT(HTNode ht[],int n){FILE *fp;if((fp=fopen("哈夫曼树.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,j,k,lnode,rnode;int min1,min2;for (i=0;i<2*n-1;i++)ht[i].parent=ht[i].lchild=ht[i].rchild=-1;for (i=n;i<2*n-1;i++){min1=min2=32767;lnode=rnode=-1;for(k=0;k<=i-1;k++)if(ht[k].parent==-1){if (ht[k].weight<min1){min2=min1;rnode=lnode;min1=ht[k].weight;lnode=k;}else if(ht[k].weight<min2){min2=ht[k].weight;rnode=k;}}ht[lnode].parent=i;ht[rnode].parent=i;ht[i].weight=ht[lnode].weight+ht[rnode].weight;ht[i].lchild=lnode;ht[i].rchild=rnode;}printf("建立huffman树成功!\n");printf("输出huffman树:\n");fprintf(fp,"输出huffman树:\n");printf("\t字符\t权值\t父节点\t 左子节点\t右子节点");fprintf(fp,"\t字符\t权值\t父节点\t 左子节点\t右子节点");for(j=1;j<i;j++){ printf("\n");fprintf(fp,"\n");printf("\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,ht[i]. lchild,ht[j].rchild);fprintf(fp,"\t %-8c%-8d%-10d%-14d%-10d",ht[j].data,ht[j].weight,ht[j].parent,h t[i].lchild,ht[j].rchild);}printf("\n");printf("哈夫曼树已输出至文献“哈夫曼树.txt”!按任意键返回!");fclose(fp);getch();system("cls");return;}//生成哈夫曼编码void CreateHCode (HTNode ht[],HCode hcd[],int n){int i,f,c,j=0;HCode hc;for(i=0;i<n;i++){hc.start=n;c=i;hc.cd[hc.start--]='0';f=ht[i].parent;while(f!=-1){if (ht[f].lchild==c)hc.cd[hc.start--]='0';elsehc.cd[hc.start--]='1';c=f;f=ht[f].parent;}hc.start++;for(j=0;j<hc.start;j++)hc.cd[j]=' ';hcd[i]=hc;}}void DispHCode(HTNode ht[],HCode hcd[],int n) {FILE *fp;if((fp=fopen("哈夫曼编码.txt","w"))==0){printf("\n\t\t文献打开失败");return;}int i,k;int sum=0,m=0,j;printf("输出字符哈夫曼编码:\n"); fputs("输出字符哈夫曼编码:\n",fp); for (i=0;i<n;i++){j=0;printf("%c:\t",ht[i].data);fprintf(fp,"\n%c:\t",ht[i].data);for (k=hcd[i].start;k<=n;k++){printf("%c",hcd[i].cd[k]);j++;fprintf(fp,"%c",hcd[i].cd[k]); }m+=ht[i].weight;sum+=ht[i].weight*j;printf("\n");}printf("\n哈夫曼编码已保存至文献“哈夫曼编码.txt!按任意键返回!”");fclose(fp);getch();system("cls");}//编码函数void bianma1(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]){int i;char str[N];printf("请输入要编码的字符集(以‘#’结束):\n");for(i=0;i<N;i++){scanf("%c",&str[i]);if(str[i]=='#'){str[i]='\0';break;}}strcpy(ch.s,str);ch.num=strlen(str);editHCode(ht,hcd,ch,n,bianma);getch();system("cls");}void bianma2(HTNode ht[],HCode hcd[],CHar &ch,int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&ch.s[i],sizeof(char),1,fp);}ch.num=strlen(ch.s);printf("\n读入成功!\n");printf("文献中的字符集为:\n%s",ch.s);fclose(fp);editHCode(ht,hcd,ch,n,bianma);system("cls");return;}//译码函数void yima1(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;char code[MAXcode];printf("请输入编码进行译码(以‘#’结束):\n");for(i=0;i<MAXcode;i++){scanf("%c",&code[i]);if(code[i]=='#'){code[i]='\0';break;}}strcpy(bianma,code);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");return;}void yima2(HTNode ht[],HCode hcd[],int n,char bianma[]) {int i;FILE*fp;char filename[20];printf("请输入要打开的文献名(*.txt):");scanf("%s",&filename);if((fp=fopen(filename,"r"))==NULL){printf("\n\t\t文献打开失败");return;}for(i=0;!feof(fp);i++){fread(&bianma[i],sizeof(char),1,fp);}printf("读入成功!\n");printf("文献中的编码是:%s\n",bianma);printyima(ht,hcd,n,bianma);printf("\n译码完毕!按任意键返回!");getch();system("cls");}四、调试结果主菜单建立字符权值选择2.从文献读入字符进行记录输入测试文献名“cs.txt”输出个字符权值建立哈夫曼树并输出至文献生成哈夫曼编码并保存至文献编码选择2.从文献读入字符集编码编码结果保存至文献译码选择2.从文献读入编码, 读入上一步的编码译码完毕, 返回!退出系统。
哈夫曼编码译码系统(树应用)
实验三哈夫曼编码/译码系统(树应用)一、实验目的1. 帮助读者复习C++语言程序设计中的知识。
2.哈夫曼树的建立,哈夫曼编码的生成,对编码信息的翻译的熟悉和运用。
[需求分析]利用哈夫曼编码进行通信,可以压缩通信的数据量,提高传输效率,缩短信息的传输时间,还有一定的保密性。
现在要求编写一程序模拟传输过程,实现在发送前将要发送的字符信息进行编码,然后进行发送,接收后将传来的数据进行译码,即将信息还原成发送前的字符信息。
二、实验内容和要求[问题要求]利用哈夫曼编码进行通信,可以压缩通信的数据量,提高传输效率,缩短信息的传输时间,还有一定的保密性。
现在要求编写一程序模拟传输过程,实现在发送前将要发送的字符信息进行编码,然后进行发送,接收后将传来的数据进行译码,即将信息还原成发送前的字符信息。
[问题分析]在本例中设置发送者和接受者两个功能,发送者的功能包括:输入待传送的字符信息;统计字符信息中出现的字符种类数和各字符出现的次数(频率);根据字符的种类数和各自出现的次数建立哈夫曼树;利用以上哈夫曼树求出各字符的哈夫曼编码;将字符信息转换成对应的编码信息进行传送。
接受者的功能包括:接收发送者传送来的编码信息;利用上述哈夫曼树对编码信息进行翻译,即将编码信息还原成发送前的字符信息。
本实验首先从文件中读取数据,然后分析数据对不同的元素依次存入一字符数组并统计其出现的次数并当做其权值,然后根据这些信息建立哈弗曼树,并对各个字符进行哈弗曼编码然后根据各个字符的编码对所有输入的一组字符进行哈弗曼编码。
译码是根据哈弗曼树和接收到的一组编码进行译码操作。
译码也就是对哈弗曼树的遍历三、算法设计首先读入一组字符,然后统计这些字符中不同字符出现的次数,并当做其权值,然后根据不同字符及其权值建立哈弗曼树。
建立哈弗曼树后即可得到这些不同字符的哈弗曼编码,然后即可根据这些哈弗曼编码对那组输入的一串字符进行哈弗曼编码。
译码是根据一组编码翻译成一组字符的操作,其算法就是根据这一串编码来对哈弗曼树进行遍历,每遍历到一个叶子结点即输出一个字符,直至将编码操作完即可完成多编码的翻译操作。
哈夫曼编译码系统的设计与实现
哈夫曼编/译码系统的设计与实现一、实验项目简介:1.问题描述:利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
但是,这要求在发送端通过一个编码系统对待传数据预先编码,在接收端将传来的数据进行译码(解码)。
对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站设计一个哈夫曼编/译码系统。
2.一个完整的系统应具有以下功能:1)初始化(Initialzation)。
从数据文件 DataFile.data 中读入字符及每个字符的权值,建立哈夫曼树HuffTree;2)编码(EnCoding)。
用已建好的哈夫曼树,对文件ToBeTran.data 中的文本进行编码形成报文,将报文写在文件 Code.txt 中;3)译码(Decoding)。
利用已建好的哈夫曼树,对文件CodeFile.data 中的代码进行解码形成原文,结果存入文件 Textfile.txt 中;4)输出(Output)。
输出 DataFile.data 中出现的字符以及各字符出现的频度(或概率);输出 ToBeTran.data 及其报文 Code.txt;输出 CodeFile.data 及其原文 Textfile.txt;要求:所设计的系统应能在程序执行的过程中,根据实际情况(不同的输入)建立DataFile.data、ToBeTran.data 和 CodeFile.data 三个文件,以保证系统的通用性。
二、实验目的:理解哈夫曼树的特征及其应用;在对哈夫曼树进行理解的基础上,构造哈夫曼树,并用构造的哈夫曼树进行编码和译码;通过该实验,使学生对二叉树的构建、遍历等以及哈夫曼编码的应用有更深层次的理解。
实验步骤:实验分 2 次完成第 1 次:完成程序的主框架设计,进行调试,验证其正确性;(2学时)第 2 次:详细设计,进行调试,对运行结果进行分析,完成实验报告。
数据结构课程设计哈夫曼编码译码器
数据结构课程设计哈夫曼编码译码器个节点的权值、父节点、左孩子和右孩子,然后通过选择最小的两个节点合并,构建Huffman树;3:Huffman编码:通过遍历Huffman树,对每个叶子节点进行编码,将编码结果存入新的文件中;4:译码:读取存放Huffman编码的文件,通过遍历Huffman树进行译码,将译码结果存入新的文件中;5:结果验证:比较原文件和译码结果文件的内容是否一致,输出结果;3.函数说明1:CrtHuffmanTree():创建Huffman树;2:HuffmanCoding():对Huffman树进行遍历,生成Huffman编码;3:HuffmanDecoding():对Huffman编码进行译码,生成原文件内容;4:CompareFile():比较原文件和译码结果文件的内容是否一致;五、详细设计1.统计字符频率:定义结构体typedef struct strchar data;char num;str;其中data域存放字符名称,num域存放字符出现频率,读取文件ywq1.txt,通过循环比较将结果赋入S2[128]中;2.创建Huffman树:定义结构体typedef structchar data;int weight;int parent;int lchild;int rchild;HTNode,HuffmanTree[M+1];作为Huffman树存储节点类型,调用CrtHuffmanTree()函数,初始化各个节点的权值、父节点、左孩子和右孩子,然后通过选择最小的两个节点合并,构建Huffman树;3.Huffman编码:通过遍历Huffman树,对每个叶子节点进行编码,将编码结果存入新的文件中;4.译码:读取存放Huffman编码的文件,通过遍历Huffman树进行译码,将译码结果存入新的文件中;5.结果验证:比较原文件和译码结果文件的内容是否一致,输出结果;六、测试1.测试数据测试文件:ywq1.txt(包含英文字母、数字和符号)2.测试结果测试结果正确,能够正确地对文件进行Huffman编码和译码,生成的译码结果文件与原文件内容一致;七、总结通过本次课程设计,我深入了解了Huffman编码/译码器的实现原理和过程,掌握了Huffman树的创建、存储和遍历方法,提高了动手能力,同时也为数据压缩问题提供了一种有效的解决方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
《数据结构》课程设计——赫夫曼编码/译码器设计指导教师:孙树森、周维达班级:09数媒(2)班学号:E09700227姓名:曾焕凯数据结构课程设计报告书一、实验目的1、提高分析问题、解决问题的能力,进一步巩固数据结构各种原理与方法。
2、熟悉掌握一门计算机语言,可以进行数据算法的设计。
二、实验原理1、哈夫曼树的定义:假设有n 个权值,试构造一颗有n 个叶子节点的二叉树,每个叶子带权值为wi,其中树带权路径最小的二叉树成为哈夫曼树或者最优二叉树;2、哈夫曼树的构造:weight 为输入的频率数组,把其中的值赋给依次建立的HT Node 对象中的data 属性,即每一个HT Node 对应一个输入的频率。
然后根据data 属性按从小到大顺序排序,每次从data 取出两个最小和此次小的HT Node,将他们的data 相加,构造出新的HTNode 作为他们的父节点,指针parent,leftchild,rightchild 赋相应值。
在把这个新的节点插入最小堆。
按此步骤可以构造构造出一棵哈夫曼树。
通过已经构造出的哈夫曼树,自底向上,由频率节点开始向上寻找parent,直到parent 为树的顶点为止。
这样,根据每次向上搜索后,原节点为父节点的左孩子还是右孩子,来记录1 或0,这样,每个频率都会有一个01 编码与之唯一对应,并且任何编码没有前部分是同其他完整编码一样的。
三、实验步骤先统计要压缩编码的文件中的字符字母出现的次数,按字符字母和空格出现的概率对其进行哈夫曼编码。
然后读入要编码的文件,编码后存入另一个文件;接着再调出编码后的文件,并对其进行译码输出,最后存入另一个文件中。
具体步骤:1.初始化,统计文本文件中各字符的个数作为权值,生成哈夫曼树;2.根据符号概率的大小按由大到小顺序对符号进行排序;3.把概率最小的两个符号组成一个节点;4.重复步骤2. 3 ,直到概率和为1;5.从根节点开始到相应于每个符号的“树叶”,概率大的标“0”,概率小的标“1”;6.从根节点开始,对符号进行编码;7.译码时流程逆向进行,从文件中读出哈夫曼树,并利用哈夫曼树将编码序列解码。
四、实验结果与分析哈夫曼编码是动态变长编码,临时建立概率统计表和编码树。
概率小的码比较长,概率小的码比较长。
概率大的码短,这样把一篇文件编码后,就会压缩许多。
从树的角度看,哈夫曼编码方式是尽量把短码都利用上。
首先,把一阶节点全都用上,如果码字不够时,然后,再从某个节点伸出若干枝,引出二阶节点作为码字,以此类推,显然所得码长最短,再根据建立的概率统计表合理分布和放置,使其平均码长最短就可以得到最佳码。
实验截图:五、实验心得本次实验结合了之前所学的赫夫曼算法,并利用其原理实现赫夫曼编码/译码系统;实验难度较之前的几次实验有所增加,所以花了比较多的时间来编写,测试代码。
期间参考了网上的一些程序,通过结合分析,了解其他人在实现这个算法时的思想,也借鉴了其中的一些东西,同时加入了自己的想法。
最终完成饿了本次的作业。
通过这次实验,我了解了一个算法到一个可以执行的程序之间还有很多工作需要做,深刻体会到实践出真知的到了,看似简单的算法在实现时却话费了这么多时间,但是这个过程中也让我学到了很多。
六、主要代码Huffman_Tree.h:#ifndef Huffman_Tree_h#define Huffman_Tree_h#endif#include <stdio.h>typedef struct {unsigned int weight;unsigned int parent,lchild,rchild;}HTNode, * HuffmanTree; //存储赫夫曼树的结点类型typedef char * * HuffmanCode; //用于存储字符集中各个字符相应的赫夫曼编码void strcpy(char *S1,char *S2){ //将字符串S2复制到S1int i = 0;while( S2[i] != '\0' ){S1[i] = S2[i];i++;}S1[i] = '\0';}//在HT[1]到HT[t-1]中找出权值最小的两个S1和S2-----------------------------------------------void Select(HuffmanTree HT,int t,int &s1,int &s2){int i = 1;s1 = s2 = 0;HT[0].weight = 50000;while( i <= t ){ //遍历查找权值最小的结点S1if( HT[i].parent == 0 && HT[i].weight < HT[s1].weight )s1 = i;i++;}i = 1;while( i <= t ){ //遍历查找除S1外权值最小的结点S2if( i != s1 && HT[i].parent == 0 && HT[i].weight < HT[s2].weight )s2 = i;i++;}}//根据各个字符的权值构造赫夫曼树HT,将对应的赫夫曼编码存储在HC中------------------------------------------------int HuffmanCoding( HuffmanTree &HT,HuffmanCode &HC,int *w,int n){int s1,s2,m,i,start;unsigned int c,f;HTNode * p;char *cd;if( n <= 1 ) return 0;m = 2 * n - 1; //赫夫曼树的总结点树为mHT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); //申请存储赫夫曼树的空间for(p = HT + 1, i = 1; i <= n; ++i, ++p, ++w){ //将各个叶子结点的weight赋以相应的权值,parent,lchild,rchild均赋为0p->weight = *(w+1);p->parent = p->lchild = p->rchild = 0;}for( ; i <= m; ++i, ++p ){ //将各个非叶子结点的weight,parent,lchild,rchild均赋为0p->weight = p->parent = p->lchild = p->rchild = 0;}for( i = n + 1; i <= m; ++i ){ //构造赫夫曼树,给各个非叶子结点赋值Select(HT, i - 1, s1, s2);HT[s1].parent = i; 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 *)); //用于存储指向存储各个字符相应赫夫曼编码的字符数组的指针cd = (char *)malloc(n * sizeof(char)); //分配工作所需空间cd[n - 1] = '\0'; //编码结束符for( i = 1; i <= n; ++i) //逐个字符求赫夫曼编码{start = n -1; //编码在数组cd[]中的最前位置//从叶子到根逆向求编码,初始值;停止条件;一次循环后对上一个节点做循环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[]数组的start位置到n-1位置复制给HC[i]}free(cd); //释放空间return 1;}Test.cpp:#include <stdio.h>#include <stdlib.h>#include "Huffman_Tree.h"#define Yes 1 //当程序已经调用过初始化赫夫曼树的InitHuff_T()函数,或已从htfTree文件读取过,则将Init_Mode置为Yes,否则为No#define No 0void InitHuff_T( HuffmanTree &HT, HuffmanCode &HC, char ch[],int &n ){ //初始化赫夫曼数,要求用户输入字符和相应权值int i = 1,w[100],temp,j;char a[20]; //数字转字符时,用于储存赫夫曼编码FILE *save;printf("请输入编码字符集的大小:");scanf("%d",&n); //获取用户输入的字符集个数while( i <= n ){ //获取用户输入的字符和相应权值,分别存储在ch[]和w[]数组中printf("请输入第%d个字符和该字符的权值:",i);fflush(stdin); //刷新标准输入缓冲区,把输入缓冲区里的东西丢弃scanf("%c%d",&ch[i],&w[i]);i++;}ch[i] = '\0';//哈夫曼树保存--------------------------------------------------------------------------------------------HuffmanCoding(HT,HC,w,n); //根据用户的输入,生成赫夫曼数及各个字符相应的赫夫曼编码,分别存在HT树和HC中if(( save = fopen("hfmTree.TXT","w")) == NULL ){ //打开用于存储赫夫曼树的文件printf("Open file fail......\n");exit(0);}temp = n; //将字符集大小转换成字符形式写入到文件hfmTree.TXT中j = 0;while( temp != 0 ){//计算数字位数temp = temp / 10;j++;}temp = n; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,save);printf("%d\n",n); //向屏幕输出字符集大小nfputc('\n',save); //换行for( i = 1; i <= n; i++ ){ //分别向文件和屏幕输出各个字符和相应的赫夫曼编码fputc(ch[i],save); printf("%c\t",ch[i]); //字符fputc('\t',save);fputs(HC[i],save); printf("%s\n",HC[i]); //编码fputc('\n',save);}for(i = 1; i <= 2 * n - 1; i++ ){ //将赫夫曼树各个结点的parent,lchild,rchild分别写入到文件中temp = HT[i].parent; //将i结点的parent转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,save);fputc(' ',save);}else{j = 0; //计算HT[i].parent数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].parent; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,save);fputc(' ',save);}temp = HT[i].lchild; //将i结点的lchild转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,save);fputc(' ',save);}else{j = 0; //计算HT[i].lchild数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].lchild; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,save);fputc(' ',save);}temp = HT[i].rchild; //将i结点的rchild转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,save);fputc('\n',save);}else{j = 0; //计算HT[i].lchild数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].rchild; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,save);fputc('\n',save);}}fclose(save);}//编码,并将所得编码存储到文件-----------------------------------void Encoding(HuffmanTree &HT, HuffmanCode &HC, char ch[]){ FILE *ToBeTran,*CodeFile;int i;char c;if(( ToBeTran = fopen("T oBeTran.TXT","r")) == NULL ){printf("Open file fail......\n");exit(0);}if(( CodeFile = fopen("CodeFile.TXT","w")) == NULL ){printf("Open file fail......\n");exit(0);}c = fgetc(ToBeTran); //从文件读取一个字符while( c != EOF ){ //对文件中的各个字符进行编码,直至文件结尾i = 1;while( c != ch[i] && ch[i] != '\0' ) //在ch[]数组中查找从文件读取的字符i++;if(ch[i] == '\0'){ //未找到,c不在ch[]数组中,c无法被识别,退出printf("字符%c无法识别\n",c);exit(0);}fputs(HC[i],CodeFile); //若找到,则将c相应的赫夫曼编码写入到文件中printf("%s",HC[i]); //将c相应的赫夫曼编码输出到屏幕c = fgetc(ToBeTran); //读入文件中的下一个字符}printf("\n");fclose(T oBeTran);fclose(CodeFile);}//译码,翻译成相应的字符表示,并存储到文件------------------------------int p,i = 1;void Decoding(HuffmanTree &HT, char ch[] , int n){char code[1000],c;p = 2 * n - 1; //n为叶子数量,2*n-1即为根节点的节点号FILE *CodeFile,*TextFile;if(( CodeFile = fopen("CodeFile.TXT","r")) == NULL ){printf("Open file fail......\n");exit(0);}if(( TextFile = fopen("TextFile.TXT","w")) == NULL ){printf("Open file fail......\n");exit(0);}c = fgetc(CodeFile);while( c != EOF ){ //从文件读取字符,存储在code[]数组中code[i] = c;i++;c = fgetc(CodeFile);}code[i] = '\0';i = 1;while ( code[i] != '\0' && p != 0 ){ //对数组code[]中的赫夫曼编码进行译码,p储存节点号if ( code[i] == '0' )p=HT[p].lchild; //进入左分支elsep = HT[p].rchild; //进入右分支if (!HT[p].lchild&& !HT[p].rchild){ //不再有叶子节点时(进入叶子结点)fputc(ch[p],TextFile); //将相应的字符写入到文件中printf("%c",ch[p]); //将相应的字符输出到屏幕p = 2 * n - 1; //重新从树根出发进行译码}i++;}printf("\n");}//从文件读取赫夫曼树-------------------------------------------------------------------------------------void ReadHuff_T( HuffmanTree &HT, HuffmanCode &HC, char ch[], int &n){FILE *hfmTree;char c[100],ch1;int i,j,t;if(( hfmTree = fopen("hfmTree.TXT","r")) == NULL ){ //打开存有赫夫曼树信息的文件printf("Open file fail......\n");exit(0);}fgets(c,10,hfmTree); //获取赫夫曼树叶子结点个数(字符串)i = 0; //将字符串形式转换成整数形式while( c[i] != '\n' )i++;n = 0;for( j = 0; j < i; j++ )n = 10 * n + c[j] - '0'; //求出叶子结点数nHC = (HuffmanCode)malloc((n + 1) * sizeof(char *)); //申请HC空间HT = (HuffmanTree)malloc((2 * n) * sizeof(HTNode)); //申请赫夫曼树存储空间i = 1;while( i <= n ){ch[i] = fgetc(hfmTree); //读取字符集中的一个字符HC[i] = (char *)malloc((10)*sizeof(char)); //申请用于存储读取到的字符集中的字符的赫夫曼编码的空间fgetc(hfmTree); //将‘\t’读取并输出ch1 = fgetc(hfmTree); //读取赫夫曼编码,存储在相应的HC[i][]数组里int j = 0;while( ch1 != '\n' ){HC[i][j] = ch1;j++;ch1 = fgetc(hfmTree);}HC[i][j] = '\0';i++;}ch[i] = '\0';i = 0;while( i < 2 * n - 1 ){ //读取赫夫曼树的各个结点的parent,lchild,rchild.并赋值到赫夫曼树HT中ch1 = fgetc(hfmTree); //读取parent的字符串形式,存储在c[]中,并将其转换成整数形式,赋给HT[i].parentj = 0;while( ch1 != ' ' ){ //遇到空格前将读取的字符都保存在c[]中c[j] = ch1;j++;ch1 = fgetc(hfmTree);}HT[i+1].parent = 0; //初始化for( t = 0; t < j; t++ ) //字符转整型HT[i+1].parent = 10 * HT[i+1].parent + c[t] - '0';ch1 = fgetc(hfmTree); //读取lchild的字符串形式,并将其转换成整数形式,赋给HT[i].lchild j = 0;while( ch1 != ' ' ){ //遇到空格前将读取的字符都保存在c[]中c[j] = ch1;j++;ch1 = fgetc(hfmTree);}HT[i+1].lchild = 0; //初始化for( t = 0; t < j; t++ ) //字符转整型HT[i+1].lchild = 10 * HT[i+1].lchild + c[t] - '0';ch1 = fgetc(hfmTree); //读取rchild的字符串形式,并将其转换成整数形式,赋给HT[i].rchild j = 0;while( ch1 != '\n' ){ //换行前将读取的字符都保存在c[]中c[j] = ch1;j++;ch1 = fgetc(hfmTree);}HT[i+1].rchild = 0; //初始化for( t = 0; t < j; t++ ) //字符转整型HT[i+1].rchild = 10 * HT[i+1].rchild + c[t] - '0';i++;}}//显示规定格式编码,并将所得编码存储到文件-----------------------------------void CodePrin(){FILE *CodePrin,*CodeFile;char c;int prin[200];int k=0;if(( CodeFile = fopen("CodeFile.TXT","r")) == NULL ){printf("Open file fail......\n");exit(0);}if(( CodePrin = fopen("CodePrin.TXT","w")) == NULL ){printf("Open file fail......\n");exit(0);}c = fgetc(CodeFile); //从文件读取一个字符while( c != EOF ){ //对文件中的各个字符进行编码,直至文件结尾if(c=='1') prin[k]=1;else prin[k]=0;fputc(c,CodePrin); //将c相应的赫夫曼编码写入到文件中printf("%d",prin[k]); //将c相应的赫夫曼编码输出到屏幕c = fgetc(CodeFile); //读入文件中的下一个字符k++;if(k%50==0){ //50个字符时,换行printf("\n");fputc('\n',CodePrin);}}printf("\n");fclose(CodePrin);fclose(CodeFile);}//显示并打印赫夫曼树----------------------------------------------------------------void TreePrint(HuffmanTree &HT, int n) {FILE *TreePrint;char a[20];int temp;int j;if(( TreePrint = fopen("TreePrint.TXT","w")) == NULL ){ //打开用于存储赫夫曼树的文件printf("Open file fail......\n");exit(0);}for(i = 1; i <= 2 * n - 1; i++ ){ //将赫夫曼树各个结点的parent,lchild,rchild分别显示printf("%d ",HT[i].parent);printf("%d ",HT[i].lchild);printf("%d",HT[i].rchild);printf("\n");temp = HT[i].parent; //将i结点的parent转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,TreePrint);fputc(' ',TreePrint);}else{j = 0; //计算HT[i].parent数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].parent; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,TreePrint);fputc(' ',TreePrint);}temp = HT[i].lchild; //将i结点的lchild转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,TreePrint);fputc(' ',TreePrint);}else{j = 0; //计算HT[i].lchild数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].lchild; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,TreePrint);fputc(' ',TreePrint);}temp = HT[i].rchild; //将i结点的rchild转换成字符并写入到文件中if(temp == 0){fputc(temp + 48,TreePrint);fputc('\n',TreePrint);}else{j = 0; //计算HT[i].lchild数字位数while( temp != 0 ){temp = temp / 10;j++;}temp = HT[i].rchild; //数字转字符a[j] = '\0';while( temp != 0 ){a[j - 1] = (char)(temp % 10 + 48);temp = temp / 10;j--;}fputs(a,TreePrint);fputc('\n',TreePrint);}}fclose(TreePrint);}//主函数----------------------------------------------------------------------int main(){HuffmanTree HT;HuffmanCode HC;char ch[100]; //用于存储字符集int n,Init_Mode = No; //n为字符集的大小,Init_Mode = No 表示内存中没有赫夫曼树的信息char mode; //让用户选择不同的操作printf("请输入你要选择的功能(命令需要大写)\n");printf("I -- 初始化 E -- 编码\n");printf("D -- 译码P -- 显示并打印编码\n");printf("T -- 显示并打印赫夫曼树Q -- 退出程序\n");scanf("%c",&mode); //获得用户选择的操作while( mode != 'Q' ){ //当用户输入不为Q时,执行相应操作switch(mode){case 'I' :InitHuff_T(HT,HC,ch,n);Init_Mode = Yes;break;case 'E' :if( No == Init_Mode )ReadHuff_T(HT,HC,ch,n);Encoding(HT,HC,ch);Init_Mode = Yes;break;case 'D' :if( No == Init_Mode )ReadHuff_T(HT,HC,ch,n);Decoding(HT,ch,n);Init_Mode = Yes;break;case 'P' :CodePrin();break;case 'T' :if( No == Init_Mode )ReadHuff_T(HT,HC,ch,n);TreePrint(HT,n);Init_Mode = Yes;break;default :printf("您的输入有错,请重新选择.\n");}printf("请输入你要选择的功能\n");printf("I -- 初始化 E -- 编码\n");printf("D -- 译码P -- 显示并打印编码\n"); printf("T -- 显示并打印赫夫曼树Q -- 退出程序\n");fflush(stdin);scanf("%c",&mode); //继续选择相应的操作,直至用户选择退出}return 0;}成绩评定表。