实验四-赫夫曼
赫夫曼编码实验报告

实验五哈夫曼树和哈夫曼树编码学院专业班学号姓名一.实习目的1.掌握哈夫曼树的顺序存储方式;2.掌握建立哈夫曼树的方法;3.掌握由哈夫曼树构造哈夫曼编码的方法。
二.实习内容1.建立哈夫曼树的顺序存储结构;2.编程实现构建一棵哈夫曼树。
3.编程实现由哈夫曼树构造出哈夫曼编码三.实习步骤1. 程序代码#include<malloc.h> // malloc()等#include<limits.h> // INT_MAX等#include<stdio.h> //#include<stdlib.h> //#include<string.h>typedef struct{unsigned int weight;unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree; // 动态分配数组存储赫夫曼树typedef char **HuffmanCode; // 动态分配数组存储赫夫曼编码表int min(HuffmanTree t,int i){ // 返回i个结点中权值最小的树的根结点序号,函数select()调用int j,flag;unsigned int k=UINT_MAX; // 取k为不小于可能的值(无符号整型最大值) for(j=1;j<=i;j++)if(t[j].weight<k&&t[j].parent==0) // t[j]是树的根结点k=t[j].weight,flag=j;t[flag].parent=1; // 给选中的根结点的双亲赋1,避免第2次查找该结点return flag;}void select(HuffmanTree t,int i,int &s1,int &s2){ // 在i个结点中选择2个权值最小的树的根结点序号,s1为其中序号小的那个int j;s1=min(t,i);s2=min(t,i);if(s1>s2){j=s1;s1=s2;s2=j;}}void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n) // 算法6.12{ // w存放n个字符的权值(均>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC int m,i,s1,s2,start;unsigned 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=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*));// 分配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 main(){HuffmanTree HT;HuffmanCode HC;int *w,n,i;printf("请输入权值的个数(>1): ");scanf("%d",&n);w=(int*)malloc(n*sizeof(int));printf("请依次输入%d个权值(整型):\n",n);for(i=0;i<=n-1;i++)scanf("%d",w+i);HuffmanCoding(HT,HC,w,n);printf("huffman树存储结构:\n");for( i=1;i<2*n;i++)printf("%4d%4d%4d%4d\n", HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);// 输出哈夫曼树的每个结点的权值、父亲结点序号、左孩子和右孩子序号。
优秀HUFFMAN编码 实验报告

YU
实验二:Huffman编码的实现
实验学时:3
实验类型:(演示、验证、综合、√设计、研究)
实验要求:(√必修、选修)
一、实验目的
理解和掌握huffman编码的基本原理和方法,实现对信源符号的huffman编码。
二、实验内容
1. 理解和掌握huffman编码的基本原理和方法
2. 通过MATLAB编程实现对单信源符号的huffma编码
3. 计算信源的信息熵、平均码长以及编码效率
三、实验原理
1.Huffman编码按信源符号出现的概率而编码,其平均码长最短,所以是最优码。
2.无失真信源编码定理:
对于熵为H(X)的离散无记忆的平稳信源,必存在一种无失真编码,使每符号的平均码长满足不等式:H(S)H(S)?L??1 logrlogr
3.二元Huffman编码:若将编码设计为长度不等的二进制编码,即让待传字符串中出现概率大的字符采用尽可能短的码字,而把长的码字分配给概率小的信源符号。
构造方法如下:
(a)将信源概率分布按大小以递减次序排列;合并两概率最小者,得
到新信源;并分配0/1符号。
(b)新信源若包含两个以上符号返回(a),否则到(c)。
(c)从最后一级向前按顺序写出每信源符号所对应的码字。
四、实验数据源
1.[X?P]:??s1s2s3s4s5X:{0,1} ?0.40.20.20.10.1。
数据结构实验指导书(新版)

《数据结构和算法》实验指导书实验及学时数分配序号实验名称学时数(小时)1 实验一线性表 42 实验二树和二叉树 23 实验三图 24 实验四查找 25 实验五内部排序 2合计12几点要求:一、上机前:认真预习相关实验内容,提前编写算法程序,上机时检查(未提前编写程序者,扣除平时成绩中实验相关分数)。
二、上机中:在Turbo C或VC6.0环境中,认真调试程序,记录调试过程中的问题、解决方法以及运行结果。
上机时签到;下机时验收签字。
三、下机后:按要求完成实验报告,并及时提交(实验后1周内)。
实验一线性表【实验目的】1、掌握用Turbo c上机调试线性表的基本方法;2、掌握线性表的基本操作,插入、删除、查找以及线性表合并等运算在顺序存储结构和链式存储结构上的运算;3、运用线性表解决线性结构问题。
【实验学时】4 学时【实验类型】设计型【实验内容】1、顺序表的插入、删除操作的实现;2、单链表的插入、删除操作的实现;3、两个线性表合并算法的实现。
(选做)【实验原理】1、当我们在线性表的顺序存储结构上的第i个位置上插入一个元素时,必须先将线性表中第i个元素之后的所有元素依次后移一个位置,以便腾出一个位置,再把新元素插入到该位置。
若是欲删除第i个元素时,也必须把第i个元素之后的所有元素前移一个位置;2、当我们在线性表的链式存储结构上的第i个位置上插入一个元素时,只需先确定第i个元素前一个元素位置,然后修改相应指针将新元素插入即可。
若是欲删除第i个元素时,也必须先确定第i个元素前一个元素位置,然后修改相应指针将该元素删除即可;3、详细原理请参考教材。
【实验步骤】一、用C语言编程实现建立一个顺序表,并在此表中插入一个元素和删除一个元素。
1、通过键盘读取元素建立线性表;(从键盘接受元素个数n以及n个整形数;按一定格式显示所建立的线性表)2、指定一个元素,在此元素之前插入一个新元素;(从键盘接受插入位置i,和要插入的元素值;实现插入;显示插入后的线性表)3、指定一个元素,删除此元素。
实验一-信息熵与图像熵计算-正确

实验一信息熵与图像熵计算(2 学时)一、实验目的1.复习MATLAB的基本命令,熟悉MATLAB下的基本函数;2.复习信息熵基本定义,能够自学图像熵定义和基本概念。
二、实验内容1.能够写出MATLAB源代码,求信源的信息熵;2.根据图像熵基本知识,综合设计出MATLAB程序,求出给定图像的图像熵。
三、实验仪器、设备1.计算机-系统最低配置256M内存、P4 CPU;2.MATLAB编程软件。
四实验流程图五实验数据及结果分析四、实验原理1.MATLAB中数据类型、矩阵运算、图像文件输入与输出知识复习。
2.利用信息论中信息熵概念,求出任意一个离散信源的熵(平均自信息量)。
自信息是一个随机变量,它是指某一信源发出某一消息所含有的信息量。
所发出的消息不同,它们所含有的信息量也就不同。
任何一个消息的自信息量都代表不了信源所包含的平均自信息量。
不能作为整个信源的信息测度,因此定义自信息量的数学期望为信源的平均自信息量:1( ) 1 ( ) [log ] ( ) log ( ) i n i i p a i H E p a p a X 信息熵的意义:信源的信息熵H是从整个信源的统计特性来考虑的。
它是从平均意义上来表征信源的总体特性的。
对于某特定的信源,其信息熵只有一个。
不同的信源因统计特性不同,其熵也不同。
3.学习图像熵基本概念,能够求出图像一维熵和二维熵。
图像熵是一种特征的统计形式,它反映了图像中平均信息量的多少。
图像的一维熵表示图像中灰度分布的聚集特征所包含的信息量,令Pi表示图像中灰度值为i的像素所占的比例,则定义灰度图像的一元灰度熵为:2550 log i i i p p H图像的一维熵可以表示图像灰度分布的聚集特征,却不能反映图像灰度分布的空间特征,为了表征这种空间特征,可以在一维熵的基础上引入能够反映灰度分布空间特征的特征量来组成图像的二维熵。
选择图像的邻域灰度均值作为灰度2分布的空间特征量,与图像的像素灰度组成特征二元组,记为(i,j),其中i表示像素的灰度值(0<=i<=255),j表示邻域灰度(0<=j<=255),2 ( , ) / ij p f i j N上式能反应某像素位置上的灰度值与其周围像素灰度分布的综合特征,其中f(i,j)为特征二元组(i,j)出现的频数,N为图像的尺度,定义离散的图像二维熵为:2550 log ij ij i p p H构造的图像二维熵可以在图像所包含信息量的前提下,突出反映图像中像素位置的灰度信息和像素邻域内灰度分布的综合特征。
哈夫曼树的实验报告1

哈夫曼树的实验报告1一、需求分析1、本演示程序实现Haffman编/译码器的作用,目的是为信息收发站提供一个编/译系统,从而使信息收发站利用Haffman编码进行通讯,力求达到提高信道利用率,缩短时间,降低成本等目标。
系统要实现的两个基本功能就是:①对需要传送的数据预先编码;②对从接收端接收的数据进行译码;2、本演示程序需要在终端上读入n个字符(字符型)及其权值(整形),用于建立Huffman树,存储在文件hfmanTree.txt中;如果用户觉得不够清晰还可以打印以凹入表形式显示的Huffman树;3、本演示程序根据建好的Huffman树,对文件的文本进行编码,结果存入文件CodeFile中;然后利用建好的Huffman树将文件CodeFile中的代码进行译码,结果存入文件TextFile中;最后在屏幕上显示代码(每行50个),同时显示对CodeFile中代码翻译后的结果;4、本演示程序将综合使用C++和C语言;5、测试数据:(1)教材例6-2中数据:8个字符,概率分别是0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,可将其的权值看为5,29,7,8,14,23,3,11(2)用下表给出的字符集和频度的实际统计数据建立Haffman树,并实现以下报文的编码和一、概要设计1、设定哈夫曼树的抽象数据类型定义ADT Huffmantree{数据对象:D={a i| a i∈Charset,i=1,2,3,……n,n≥0}数据关系:R1={< a i-1, a i >| a i-1, a i∈D, i=2,3,……n}基本操作:Initialization(&HT,&HC,w,n,ch)操作结果:根据n个字符及其它们的权值w[i],建立Huffman树HT,用字符数组ch[i]作为中间存储变量,最后字符编码存到HC中;Encodeing(n)操作结果:根据建好的Huffman树,对文件进行编码,编码结果存入到文件CodeFile 中Decodeing(HT,n)操作结果:根据已经编译好的包含n个字符的Huffman树HT,将文件的代码进行翻译,结果存入文件T extFile中} ADT Huffmantree1)主程序模块void main(){输入信息,初始化;选择需要的操作;生成Huffman树;执行对应的模块程序;输出结果;}2)编码模块——根据建成的Huffman树对文件进行编码;3)译码模块——根据相关的Huffman树对编码进行翻译;各模块的调用关系如图所示二、详细设计1、树类型定义typedef struct {unsigned int weight; //权值char ch1; //储存输入的字符unsigned int parent,lchild,rchild;}HTNode,*HuffmanTree;2、编码类型定义typedef char **HuffmanCode;哈夫曼编译器的基本操作设置如下Initialization(HuffmanTree &HT,HuffmanCode &HC,int *w,int &n,char *ch) //根据输入的n个字符及其它们的权值w[i],建立Huffman树HT,用字符数组ch[i]作为中间存储变量存储编码,最后转存到HC中;Encodeing(int n)//根据建好的包含n个字符的Huffman树,对文件进行编码,编码结果存入到文件CodeFile中Decodeing(HuffmanTree HT,int n)//根据已经编译好的包含n个字符的Huffman树HT,对文件的代码进行翻译,结果存入文件TextFile中基本操作操作的算法主函数及其他函数的算法void select(HuffmanTree HT,int n,int &s1,int &s2){ //依次比较,从哈夫曼树的中parent为0的节点中选择出两个权值最小的if(!HT[i].parent&&!HT[S1]&&!HT[S2]){if(HT[i].weight<ht[s1].weight){< p="">s2=s1; s1=i;}else if(HT[i].weight<ht[s2].weight&&i!=s1)< p=""> s2=i;}3、函数的调用关系图三、调试分析Encodeing Decoding Print PrintTreeInitialization1、本次实习作业最大的难点就是文件的读和写,这需要充分考虑到文件里面的格式,例如空格,换行等等,由于不熟悉C++语言和C语言的文件的输入和输出,给编程带来了很大的麻烦;2、原本计划将文本中的换行格式也进行编码,也由于设计函数比较复杂,而最终放弃;3、一开始考虑打印哈夫曼树的凹入表时是顺向思维,希望通过指针的顺序变迁来实现打印,但问题是从根结点到叶子结点的指针不是顺序存储的,所以未能成功,后来查找相关资料,最终利用递归的方法解决问题;4、程序中的数组均采用了动态分配的方法定义,力求达到减少空间的浪费;5、时间的复杂度主要是由查树这个步骤决定,因为无论是编码还是译码都需要对Huffman树进行查找和核对,但考虑到英文字母和空格也就是27个字符,影响不是很大;6、程序无论在屏幕显示还有文件存储方面都达到了不错的效果;7、程序不足的地方就是在文件文本格式方面处理得还是不够,或许可以通过模仿WORD的实现来改善。
哈夫曼编译码器课程设计报告(完整版)

.. .XXX学院本科数据结构课程设计总结报告设计题目:实验一、哈夫曼编/译码器学生:XXX系别:XXX专业:XXX班级:XXX学号:XXX指导教师:XXX XXX2012年6 月21日xxx学院课程设计任务书题目一、赫夫曼编译码器专业、班级xxx学号xxx xxx主要容、基本要求、主要参考资料等:1. 主要容利用哈夫曼编码进行信息通信可大大提高信道利用率,缩短信息传输时间,降低传输成本。
要求在发送端通过一个编码系统对待传数据预先编码;在接收端将传来的数据进行译码(复原)。
对于双工信道(既可以双向传输信息的信道),每端都需要一个完整的编/译码系统。
试为这样的信息收发站写一个哈夫曼的编/译码系统。
2. 基本要求系统应具有以下功能:(1)C:编码(Coding)。
对文件tobetrans中的正文进行编码,然后将结果存入文件codefile中,将以此建好的哈夫曼树存入文件HuffmanTree中(2)D:解码(Decoding)。
利用已建好的哈夫曼树将文件codefile中的代码进行译码,结果存入textfile中。
(3)P:打印代码文件(Print)。
将文件codefile以紧凑格式显示在终端上,每行50个代码。
同时将此字符形式的编码文件写入文件codeprint中。
(4)T:打印哈夫曼树(Tree Printing)。
将已在存中的哈夫曼树以直观的方式(树或凹入表形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件treeprint 中。
3. 参考资料:数据结构(C语言版)严蔚敏、吴伟民编著;数据结构标准教程胡超、闫宝玉编著完成期限:2012年6月21 日指导教师签名:课程负责人签名:2012年6月21 日一、设计题目(任选其一)实验一、哈夫曼编/译码器二、实验目的1巩固和加深对数据结构的理解,提高综合运用本课程所学知识的能力;2 深化对算法课程中基本概念、理论和方法的理解;3 巩固构造赫夫曼树的算法;4 设计试验用程序实验赫夫曼树的构造。
(完整word版)数据结构哈夫曼编码与译码

《数据结构》课程设计说明书题目哈夫曼编码与译码学号1267159206姓名张燕斌指导教师康懿日期2014.01。
02任务书目录第一章需求分析 (5)第二章总体设计 (6)第三章抽象数据类型定义 (7)3。
1 LinkList抽象数据类型的设计 (7)3.2 HuffmanTree抽象数据的设计 (7)第四章详细设计..。
...。
..。
....。
.....。
.。
.。
..。
.。
....。
.。
..。
..。
.。
.。
.。
.。
..。
....。
....。
.。
..。
...。
...。
7第五章测试 (10)第六章总结 (11)附录:程序代码 (12)第一章需求分析哈夫曼编码是一种编码方式,以哈夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
哈弗曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。
赫夫曼编码的应用很广泛,利用赫夫曼树求得的用于通信的二进制编码称为赫夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是赫夫曼编码。
哈弗曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串。
第二章总体设计(1)输入一个字符串用结构体链表存储字符串中出现的不同字符及其出现的次数。
(2)定义赫夫曼数的结点结构体,把不同的字符及其在字符串中出现的次数作为叶子结点的元素及其权值,统计叶子结点的个数n,开辟可以存储2*n个结点的顺序表,来赫夫曼树的各个结点,然后按照一定的规则构造赫夫曼树。
(3)开辟一个可以存储叶子结点元素及指向存储其赫夫曼编码链表的指针的顺序表,然后从叶子结点开始向上访问,是左孩子的把“0”接进链表是右孩子的把“1”接进链表,直到根结点,然后把叶子结点的元素及存储其赫夫曼链表的头指针读入顺序表,直到把所有的叶子结点的元素及指向存储其赫夫曼编码链表的头指针读入顺序表,这样得到的赫夫曼编码是倒序的。
赫夫曼树实验报告

赫夫曼树实验报告赫夫曼树实验报告引言:赫夫曼树是一种用于数据压缩的重要算法,它通过构建一棵二叉树来实现对数据的编码和解码。
本次实验旨在通过实际操作,深入了解赫夫曼树的原理和应用,并验证其在数据压缩中的有效性。
一、实验背景数据压缩在现代信息技术中起着至关重要的作用。
随着数据量的不断增加,如何有效地压缩数据成为了一个迫切的问题。
赫夫曼树作为一种经典的数据压缩算法,具有较高的压缩比和较快的解压速度,因此备受关注。
二、实验目的1. 了解赫夫曼树的原理和构建方法;2. 掌握赫夫曼编码的过程和步骤;3. 验证赫夫曼树在数据压缩中的有效性。
三、实验过程1. 构建赫夫曼树首先,我们需要统计待压缩数据中各个字符的出现频率。
然后,按照频率从小到大的顺序,将字符构建成一棵二叉树。
具体构建方法为:每次选取频率最低的两个字符,将它们作为左右子节点,生成一个新的节点,该节点的频率为左右子节点频率之和。
重复此过程,直到所有字符都被构建成树的节点。
2. 进行赫夫曼编码在赫夫曼树构建完成后,我们需要对每个字符进行编码。
编码的规则是:向左走为0,向右走为1。
从根节点开始,对每个字符进行路径搜索,直到找到对应的叶子节点,记录下路径上的0和1,即为该字符的编码。
3. 数据压缩与解压缩利用赫夫曼编码,我们可以对待压缩数据进行压缩。
将每个字符替换为对应的编码后,将所有编码拼接起来,即可得到压缩后的数据。
解压缩则是将编码根据赫夫曼树进行反向解码,得到原始数据。
四、实验结果通过实验,我们将不同类型的数据进行了压缩和解压缩,并与原始数据进行了对比。
结果表明,赫夫曼树在数据压缩中表现出色,能够显著减小数据的大小,同时保持数据的完整性。
五、实验总结赫夫曼树作为一种高效的数据压缩算法,具有广泛的应用前景。
通过本次实验,我们深入了解了赫夫曼树的原理和构建方法,并验证了其在数据压缩中的有效性。
赫夫曼树的应用不仅可以提高数据传输的效率,还可以节省存储空间,对于大数据时代的到来具有重要意义。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验四-赫夫曼目录1.概述 (1)1.1问题描述 (1)2.现状分析 (1)3.系统分析 (2)4.1系统功能模块图 (3)5.1赫夫曼树的存储结构定义 (4)5.2赫夫曼算法及其实现 (5)5.3统计字符串中字符的种类以及各类字符的个数 (5)5.4赫夫曼编译码系统功能模块 (6)6.主要代码结构 (7)6.1定义赫夫曼编码类型如下 (7)6.2赫夫曼编码算法 (7)6.3建立正文的编码文件 (8)7.主要代码段分析 (9)7.1赫夫曼编码的结构定义 (9)7.2赫夫曼编码算法 (10)8.运行与测试 (11)8.1 测试数据及结果 (11)9.总结和心得 (12)参考文献 (13)10.附:源代码 (13)1.概述1.1问题描述利用赫夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。
这要求在发送端通过一个编码系统对待传输数据预先编码,对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编码系统。
2.现状分析在当今信息爆炸时代,如何采用有效的数据压缩技术节省数据文件的存储空间和计算机网络的传送时间已越来越引起人们的重视,赫夫曼编码正是一种应用广泛且非常有效的数据压缩技术。
赫夫曼编码是一种编码方式,以赫夫曼树—即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。
赫夫曼编码使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。
赫夫曼编码的应用很广泛,利用赫夫曼树求得的用于通信的二进制编码称为赫夫曼编码。
树中从根到每个叶子都有一条路径,对路径上的各分支约定:指向左子树的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是赫夫曼编码。
赫夫曼译码输入字符串可以把它编译成二进制代码,输入二进制代码时可以编译成字符串.赫夫曼编码是已被证明的一种有效的熵编码方式, 在诸如文本、图像、视频压缩及通信、密码等信息压缩编码标准中被广泛使用。
目前广泛应用的许多其他高效数据压缩算法。
3.系统分析利用二叉树结构实现赫夫曼编/解码器。
基本要求:1、初始化:能够对输入的任意长度的字符串进行统计,统计每个字符的频度,并建立赫夫曼树。
2、建立编码表(CreateTable):利用已经建好的赫夫曼树进行编码,并将每个字符的编码输出。
3、编码(Encoding):根据编码表对输入的字符串进行编码,并将编码后的字符串输出。
4、译码(Decoding):利用已经建好的赫夫曼树对编码后的字符串进行译码,并输出译码结果。
4.概要设计4.1系统功能模块图赫夫曼编\译码器的主要功能是先建立赫夫曼树,然后利用建好的赫夫曼树生成赫夫曼编码后进行译码。
在数据通信中,经常需要将传送的文字转换成由二进制字符0、1组成的二进制串,称之为编码。
构造一棵赫夫曼树,规定赫夫曼树中的左分之代表0,右分支代表1,则从根节点到每个叶子节点所经过的路径分支组成的0和1的序列便为该节点对应字符的编码,称之为赫夫曼编码。
最简单的二进制编码方式是等长编码。
若采用不等长编码,让出现频率高的字符具有较短的编码,让出现频率低的字符具有较长的编码,这样可能缩短传送电文的总长度。
赫夫曼树课用于构造使电文的编码总长最短的编码方案。
4.1系统功能模块图5.详细设计5.1赫夫曼树的存储结构定义 #define n 100//叶子结点数#define m 2*n-1//赫夫曼树中结点总数typedef struct{int weight;//权值int lchild,rchild,parent;//左右孩子及双亲指针}HTNode;//树中结点类型 赫夫曼编码类型及相关建立赫生成赫夫赫夫曼typedef HTNode HuffmanTree[m+1];//零号单元不用5.2赫夫曼算法及其实现①根据给定的n 个权值{w1, w2 ,···wn }, 构成n 棵二叉树的集F={T1,T2 ,···Tn }, 其中每棵二叉树Ti 中只有一个带权为wi 的根结点,其左右子树均空。
②在F 中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树, 且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
③在F 中删除这两棵树, 同时将新得到的二叉树加入F 中。
④重复②和③, 直到F 只含一棵树为止, 这棵树便是赫夫曼树。
5.3统计字符串中字符的种类以及各类字符的个数该算法的主要实现思想是:先定义一个含有26个元素的临时整型数组,用来存储各种字母出现的次数。
因为大写字母与小写字母相差64位,所以在算法中我们可以使用字母减去64作为统计数组的下标对号入座。
在统计和保存过程中,我们用一个循环来判断先前统计的各类字符是否为零,若不为零,则将其存入一个数组对应得元素中,同时将其对应的字符也存入另一个数组元素中。
5.4赫夫曼编译码系统功能模块( 1)赫夫曼建树模块 : 根据输入的字符和频率, 完成赫夫曼树的构造, 并根据赫夫曼树求赫夫曼编码。
( 2)编码模块: 读取文本文件进行编码, 编码结果存入到新文件。
( 3)译码模块: 读取编码文件并解码, 打开存储编码的文件, 根据所读取的编码文件中的每字符,利用赫夫曼树进行解码。
( 4)输出模块: 将解码后的每个字母写入到一个新的文件中。
6.主要代码结构6.1定义赫夫曼编码类型如下typedef struct{char ch;//存放编码的字符char bits[n+1];//存放编码的位置int start;//编码起始位置}CodeNode;typedef CodeNode HuffmanCode[n];6.2赫夫曼编码算法void HuffmanEncoding(HuffmanTree HT,HuffmanCode HC){int c,p,i;char cd[n];int start;cd[num]='\0';for(i=1;i<=num;i++){start=num;c=i;while((p=HT[c].parent)>0){cd[--start]=(HT[p].lchild==c) ?'0':'1';c=p;}strcpy(HC[i].bits,&cd[start]);HC[i].len=num-start;}}6.3建立正文的编码文件建立正文的编码文件的基本思想是:将要编码的字符串中的字符逐一与预先生成赫夫曼树是保存的字符编码对照表进行比较,找到之后,对该字符的编码写入代码文件,直至所有的字符处理完为止。
具体实现算法如下:void coding(HuffmanCode HC,char*str){int i,j;FILE *fp;fp=fopen("codefile.txt","w");while(*str){for(i=1;i<=num;i++)if(HC[i].ch==*str){for(j=0;j<HC[i].len;j++)fputc(HC[i].bits[j],fp);break;}str++;}fclose(fp);}7.主要代码段分析赫夫曼编码可以用于通信技术,它的定义是树从根结点到每个叶子结点的路径上的各分支进行约定,指向左子树对的分支表示“0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为和各个叶子对应的字符的编码,这就是赫夫曼编码。
7.1赫夫曼编码的结构定义typedef struct{char ch;//存放编码的字符char bits[n+1];//存放编码的位置int start;//编码起始位置}CodeNode;typedef CodeNode HuffmanCode[n];7.2赫夫曼编码算法void HuffmanEncoding(HuffmanTree HT,HuffmanCode HC){//根据赫夫曼树HT求赫夫曼编码HCint c,p,i;//c和p分别指示HT中孩子和双亲的位置char cd[n];//临时存放编码串int start;//指示编码在cd中起始位置cd[num]='\0';//最后一位放上结束符for(i=1;i<=num;i++){start=num;//起始位置c=i;//从叶子结点HT[i]开始上溯while((p=HT[c].parent)>0)//直至上溯到HT[c]是树根为止{//若HT[c]是HT[p]的左孩子,则生成0;否则生成代码1cd[--start]=(HT[p].lchild==c) ?'0':'1';c=p;}strcpy(HC[i].bits,&cd[start]);HC[i].len=num-start;}}8.运行与测试8.1 测试数据及结果输入:NO MAN CAN DO TWO THINGS AT ONCE,得出结果:9.总结和心得通过这次课程设计,我们学习了很多在上课没懂的知识,并对求赫夫曼树及赫夫曼编码/译码的算法有了更加深刻的了解。
更巩固了课堂中学习有关于赫夫曼编码的知识.参考文献[1] 《数据结构课程设计》-----苏仕华等编著[2] 《数据结构(C语言版)》-----严蔚敏吴伟民编著[3] 《C程序设计(第三版)》------谭浩强著10.附:源代码#include <stdio.h>#include <string.h>/*(1)类型及相关变量的定义*/#define n 100// 叶子结点数#define m 2*n-1//赫夫曼树中的结点总数typedef struct {char ch;char bits[9];//存放编码位串int len;//编码长度}CodeNode;typedef CodeNode HuffmanCode[n+1];typedef struct {int weight;//权值int lchild,rchild,parent;//左右孩子及双亲指针}HTNode;//树中的结点类型typedef HTNode HuffmanTree[m+1];//0号单元不可用int num;//字母类型的个数/*(2)建立赫夫曼树的三个函数*/void select(HuffmanTree T,int k,int *s1,int *s2){//在HT[1……k]中选择parent为0且权值最小的两个根结点,其序号分别为S1和S2int i,j;int min1=100;for(i=1;i<=k;i++)//查找s1if(T[i].weight<min1 && T[i].parent==0){j=i;min1=T[i].weight;}(*s1)=j;min1=32767;for(i=1;i<=k;i++)//查找s2,不和s1相同if(T[i].weight<min1 && T[i].parent==0 && i!=(*s1)){j=i;min1=T[i].weight;}(*s2)=j;}int jsq(char *s,int cnt[],char str[]){//统计各字符串中各种字母的个数以及字符的种类char *p;int i,j,k;int temp[27];for(i=1;i<=26;i++)temp[i]=0;for(p=s;*p!='\0';p++){//统计各种字符个数if(*p>='A' && *p<='Z') {k=*p-64;temp[k]++;}}j=0;for(i=1,j=0;i<=26;i++)//统计有多少种字符if(temp[i]!=0) {j++;str[j]=i+64;//将对应的数组送到数组中cnt[j]=temp[i];//存入对应数组的权值}return j;}void ChuffmanTree(HuffmanTree HT,HuffmanCode HC,int cnt[],char str[]) {//构造赫夫曼树HTint i,s1,s2;for(i=1;i<=2*num-1;i++)//初始化HT,左右孩子,双亲,权值都为0{ HT[i].lchild=0; HT[i].rchild=0;HT[i].parent=0; HT[i].weight=0;}for(i=1;i<=num;i++)//输入num个叶节点的权值HT[i].weight=cnt[i];for(i=num+1;i<=2*num-1;i++)//从numd后面开始新建结点存放新生成的父结点{select(HT,i-1,&s1,&s2);//在HT[1……i-1]中选择parent为0且权值最小的两个根结点,其序号分别为s1和s2HT[s1].parent=i;HT[s2].parent=i;//将s1和s2的parent赋值HT[i].lchild=s1; HT[i].rchild=s2;//新结点的左右孩子HT[i].weight=HT[s1].weight+ HT[s2].weight;//新结点的权值}for(i=0;i<=num;i++)//输入字符集中的字符HC[i].ch=str[i];i=1;while(i<=num)printf("字符 %c,次数为: %d\n",HC[i].ch,cnt[i++]);}/*(3)生成赫夫曼编码文件的两个函数*/void HuffmanEncoding(HuffmanTree HT, HuffmanCode HC){//根据赫夫曼树HT求赫夫曼编码表HCint c,p,i;//c和p分别指示T中孩子和双亲的位置char cd[n];//临时存放编码串int start;//指示编码在cd中的起始位置cd[num]='\0';//最后一位放上串结束符for(i=1;i<=num;i++){start=num;//初始位置c=i;//从叶子节点T[i]开始上溯while((p=HT[c].parent)>0)//直至上溯到HT[c]是树根为止{//若T[c]是T[p]的做孩子,则生成0;否则生成代码1cd[--start]=(HT[p].lchild==c) ? '0' : '1';//cd数组用来存放每一个字母对应的01编码,c=p;}//end of whilestrcpy(HC[i].bits,&cd[start]);//将cd数组中德01代码复制到i结点中 /*printf("字符 %c:",HC[i].ch);for(j=start;cd[j]!=0;j++)printf("%c",cd[j]);printf("\n");*/HC[i].len=num-start;}//end of for}void coding(HuffmanCode HC,char *str){//对str 所代表的字符串进行编码,并写入文件int i,j;FILE *fp;fp=fopen("codefile.txt","w");while(*str) {for(i=1;i<=num;i++)if(HC[i].ch==*str){for(j=0;j<HC[i].len;j++){fputc(HC[i].bits[j],fp);}break;}str++;}fclose(fp);}/*(4)电码的译文*/char * decode(HuffmanCode HC){//代码文件coodfile.txt的译码*菡枫*FILE *fp;char str[254];//假设原文本文件不超过254个字符char *p;static char cd[n+1];int i,j,k=0,cjs;fp=fopen("codefile.txt","r");//读文件/*printf("编码后的文件为:\n");*/while(!feof(fp)){ cjs=0;for(i=0;i<num && cjs==0 && !feof(fp);i++){cd[i]=' ';cd[i+1]='\0';cd[i]=fgetc(fp);/*printf("%c",cd[i]);//打印出编码后的二进制码*/for(j=1;j<=num;j++)if(strcmp(HC[j].bits,cd)==0)//查找所有的字母的对应的编码,如果有相同的则将该字母放入str中{str[k]=HC[j].ch;k++;cjs=1;break;}}}/*printf("\n");*/str[k]='\0';p=str;return p;}void main(){char st[254],*s,str[27];int cn[27];HuffmanTree HT;HuffmanCode HC;printf("输入需要编码的字符串(假设均为大写字母): \n");gets(st);num=jsq(st,cn,str);//统计字符的种类及各类字符出现的频率ChuffmanTree(HT,HC,cn,str);//建立赫夫曼树HuffmanEncoding(HT,HC);//生成赫夫曼编码coding(HC,st);//建立电文赫夫曼编码文件s=decode(HC);//读编码文件译码printf("译码后的字符串: \n");printf("%s\n",s); //输出译码后字符串}。