哈夫曼编码译码

合集下载

哈夫曼编码与译码

哈夫曼编码与译码

哈夫曼编码与译码用哈夫曼树对字符串进行编码译码一、设计思想程序要求:要求每个字符有自己唯一的编码。

将得到的一串利用哈夫曼树对字符串进行编码,字串译成0、1编码后存到一个文件夹中,然后再从这个文件夹中读出这串编码进行解码。

实现方法:输入一串字符,要求字符的区间为大写的26个英文字母,将获得的串字符用计算进行字符统计,统计出现的字符种数以及每种字符出现的次权值的函数(jsquanzhi())数,将该种字符出现的次数作为它的权值。

将出现的字符的权值和该字符依次分别赋给两个结构体HT和HC,利用HT(节点)权值的大小建立哈夫曼树,首先用选择函数select()函数选择两个权值最小的字符作为叶子节点,创建一个新的节点作为这两个叶节点的父节点,被选中的节点给他的HT[i].parent赋值是他下次不再被选中,父节点的权值为,子节点的权值之和。

然后将该将父节点放入筛选区中,再进行选择(被选过的不再被使用),直到所有的节点都被使用,这样一个哈夫曼树就被建立了。

根据每个字符在哈夫曼书中的位置来编译每个字符的0、1密文代码,从叶节点判断该叶节点是其父节点的左右字左字为‘0’,右子为‘1’,在判断父节点是上级父节点的左右子直至根节点,将生成的0、1字符串按所表示的字符倒序存入HC相应的字符的bins[]数组。

重新一个一个字符的读取输入的字符串,按照字符出现的顺序将它转为0、1代码并存到一个txt文件夹中去。

解码时从文件夹中,一个一个字符的读出那串0、1代码赋给一个临时字符串cd[],用该字符串与每个字符的HC[i].bins密文比较,直到与一个字符的密文相同时,译出该字符,将字符存放在临时字符数组tempstr[]中,清空临时字符串继续读取0、1代码进行翻译,直至文件密文结束为止。

于是就得到了原先被加密的那串字符串。

- 1 -用哈夫曼树对字符串进行编码译码二、算法流程图开始获得输入的字符串getstr[],i=0。

判断getstr[i]是否i++; 为26个大写字母否是k=getstr[i]-64;quantemp[k]++( quantemp为int型数组开始值都为0)i++;i=1,j=0否i<27?是结束是 quantemp[i]=i++;0?否j++;str[j]=i+64;quan[j]=quantemp[i];图1计算字符权值及字符种类算法说明:将的的字符串进行字符种类级每种字符出现频率的统计- 2 -用哈夫曼树对字符串进行编码译码开始将所有的几点的父节点和子节点权值赋成0i=1;(num为字符的种类)HT[i].weight=quan[i] i<=num是否i=num+1否i<=2*num-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;i++图2 构建哈夫曼树算法说明:利用选择排序,选择节点权值最小的两个节点,构建一个子树,将该树的根节点再放入选择区,重复该操作,直至用完所有节点完成哈夫曼数的搭建。

哈夫曼编码和译码

哈夫曼编码和译码
11
哈夫曼树的构造算法: 哈夫曼树的构造算法: 个结点的一维数组, (1)初始化哈夫曼树的 )初始化哈夫曼树的2n-1个结点的一维数组, 个结点的一维数组 即将各结点中的各个域均置0; 即将各结点中的各个域均置 ; 个权值存放到一维数组的前n个单元中 (2)读入 个权值存放到一维数组的前 个单元中, )读入n个权值存放到一维数组的前 个单元中, 它们即为初始森林中的n个只含根结点的权值 个只含根结点的权值; 它们即为初始森林中的 个只含根结点的权值; (3)对森林中的二叉树进行合并,产生 个新 )对森林中的二叉树进行合并,产生n-1个新 结点,依次存放到一维数组的第n+1个开始的单元中, 个开始的单元中, 结点,依次存放到一维数组的第 个开始的单元中 在这个过程中要注意对每个结点双亲域, 在这个过程中要注意对每个结点双亲域,左右孩子 域以及权值的修改. 域以及权值的修改.
13
s1=maxval;s2= maxval;/ 设maxval为float类型最大值 ; ;/*设 ;/ 为 类型最大值 */ for(j =1;j<=i;j+ +) ( ; ; ) if (ht[j].parent = =0) /*判断是否为根结点 判断是否为根结点*/ 判断是否为根结点 if (ht[j].weight<s1) { s2=s1;s1= ht[j].weight; p2=p1;p1=j; } ; ; ; ; else if (ht[j].weight <s2) { s2= ht[j].weight; p2=j; } ; ; ht[p1].parent=i;ht[p2].parent=i; ; ; ht[i].lchild =p1;ht[i].rchild=p2; ; ; ht[i].weight= ht[pl].weight+ht[p2].weight; ; } return (ht);} ;

哈夫曼编码和译码

哈夫曼编码和译码

哈夫曼编码和译码哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便能够用较少的位数来表示出现频率较高的字符。

编码过程中,根据频率最低的字符构建一棵哈夫曼树,将字符的编码表示为树的路径。

而哈夫曼译码则是将经过哈夫曼编码后的数据解码成原始数据的过程。

在给定的文本中,首先需要统计每个字符的出现频率。

然后使用这些频率构建哈夫曼树。

构建哈夫曼树的过程中使用最小堆数据结构,通过不断合并两个最小频率的字符节点来构建树。

合并两个节点的过程中,创建一个新的节点来作为它们的父节点,并将其频率设置为两个子节点频率之和。

在构建树的过程中,赋予左子节点编码为0,右子节点编码为1。

构建完成哈夫曼树后,将每个字符的编码表示为从根节点到该字符节点的路径,例如,向左走的路径可以表示为0,向右走的路径可以表示为1。

为了能够正确译码,需要将字符及其对应的编码存储在一个编码表中。

对于给定的文本数据,应用哈夫曼编码后,会得到一个压缩后的编码字符串。

在哈夫曼译码过程中,从根节点开始遍历编码字符串的每一位,如果是0,则向左子节点移动,如果是1,则向右子节点移动,直到到达叶子节点。

找到叶子节点后,将对应的字符输出,并回到根节点,继续下一位的译码,直到编码字符串结束。

哈夫曼编码可以实现无损压缩,即通过译码过程能够还原出原始数据,而不会丢失任何信息。

它是一种广泛应用于数据压缩领域的有效方法,用于减小数据存储和传输的大小。

在实际应用中,哈夫曼编码被广泛应用于图像、音频和视频等多媒体数据的压缩中。

总结起来,哈夫曼编码是一种用于数据压缩的编码方法,通过根据字符出现的频率对字符进行编码,以便用较少的位数来表示出现频率较高的字符。

哈夫曼译码则是将经过编码后的数据解码成原始数据的过程。

它通过构建哈夫曼树和编码表,实现了高效的数据压缩和解压缩。

哈夫曼编码被广泛应用于数据存储和传输领域,特别是在多媒体数据的压缩中。

哈弗曼树编码译码

哈弗曼树编码译码
{
for (k=hcd[j].start;k<=n;k++)
{
printf("%c",hcd[j].cd[k]);
}
break; //输出完成后跳出当前for循环
}
(5)显示部分源程序:
{
printf("\n");
printf(" ********************************");
printf("\n ** 1---------------显示编码 **");
printf("\n ** 2---------------进行编码 **");
{
int i,k;
printf(" 输出哈夫曼编码:\n");
for (i=0;i<n;i++) //输出data中的所有数据,即A-Z
{
printf(" %c:\t",ht[i].data);
}
}
}
(3)哈弗曼译码
void deHCode(HTNode ht[],HCode hcd[],int n) //译码函数
{
char code[MAXSIZE];
int i,j,l,k,m,x;
scanf("%s",code); //把要进行译码的字符串存入code数组中
printf("\n");
printf(" 请输入选择的编号:");
scanf("%c",&orz);

哈夫曼编码和译码

哈夫曼编码和译码

哈夫曼编码和译码哈夫曼编码和译码是一种常用的数据压缩算法,它通过将出现频率较高的字符用较短的编码表示,从而减小数据的存储空间。

本文将介绍哈夫曼编码和译码的原理和应用。

哈夫曼编码是由美国数学家大卫·哈夫曼于1952年提出的一种编码方法。

它的基本思想是根据字符出现的频率来构建一棵二叉树,出现频率较高的字符位于树的较低层,而出现频率较低的字符位于树的较高层。

通过这种方式,出现频率较高的字符可以用较短的编码表示,而出现频率较低的字符则用较长的编码表示。

具体来说,哈夫曼编码的过程如下:首先,统计待编码的字符出现的频率,并根据频率构建一个字符频率表。

然后,根据字符频率表构建哈夫曼树,其中每个字符对应一个叶子节点,而非叶子节点的权值为其子节点权值之和。

接下来,通过遍历哈夫曼树,给每个字符赋予对应的编码,其中左子树路径上的编码为0,右子树路径上的编码为1。

最后,将编码后的字符序列存储起来,即完成了哈夫曼编码的过程。

哈夫曼译码是哈夫曼编码的逆过程,它通过已知的哈夫曼编码和字符频率表来将编码还原为原始的字符序列。

具体来说,哈夫曼译码的过程如下:首先,根据已知的字符频率表构建哈夫曼树。

然后,从根节点开始,根据编码的0和1进行遍历,直到叶子节点。

每次遍历到叶子节点时,将对应的字符输出,并重新回到根节点,继续下一次遍历,直到所有的编码都被译码为字符。

哈夫曼编码和译码在数据压缩领域有着广泛的应用。

由于哈夫曼编码可以将出现频率较高的字符用较短的编码表示,从而减小了数据的存储空间。

在传输大量文本、图像、音频等数据时,可以使用哈夫曼编码将数据进行压缩,从而减少传输的时间和带宽消耗。

而哈夫曼译码则可以将压缩后的数据还原为原始的数据,保证了数据的完整性和准确性。

除了数据压缩,哈夫曼编码和译码还有其他的应用。

在通信领域,哈夫曼编码可以用于错误检测和纠正,通过添加冗余信息来检测和纠正传输过程中的错误。

在图像和音频处理领域,哈夫曼编码可以用于图像和音频的压缩和解压缩,从而减小存储空间和提高传输效率。

基于哈夫曼编码的编码译码问题

基于哈夫曼编码的编码译码问题

基于哈夫曼编码的编码译码问题基于哈夫曼编码的编码译码问题相关问题:1.哈夫曼编码是什么?如何进行编码和译码?2.哈夫曼编码的原理是什么?3.哈夫曼编码的应用领域有哪些?4.如何生成哈夫曼编码树?5.哈夫曼编码的时间复杂度是多少?6.哈夫曼树的构建方法有哪些?7.哈夫曼编码在数据压缩中的作用是什么?8.哈夫曼编码存在的局限性是什么?9.哈夫曼编码与其他编码方法的比较有哪些特点?10.如何解决哈夫曼编码中的冲突问题?解释说明:1.哈夫曼编码是一种基于字符频率的可变长度编码方法。

它通过将出现频率高的字符用较短的编码来表示,出现频率低的字符用较长的编码来表示,以达到数据压缩的目的。

编码过程中,首先统计字符出现频率,然后构建哈夫曼树,根据树的结构生成编码表,最后对原始数据进行编码。

译码过程中,根据生成的编码表和编码数据,逐位解码还原原始数据。

2.哈夫曼编码的原理是基于贪心算法,通过构建哈夫曼树,将出现频率高的字符放在树的上层,出现频率低的字符放在树的下层,以实现最优的编码效果。

在编码过程中,使用了前缀码的特性,即任何一个编码不能是另一个编码的前缀,从而保证了译码的唯一性。

3.哈夫曼编码广泛应用于数据压缩领域,可以对文本、图像、音频等数据进行压缩和解压缩。

此外,哈夫曼编码也用于数据传输中的差错检测和纠正,以及编码理论的研究等领域。

4.生成哈夫曼编码树的方法主要有两种:静态生成和动态生成。

静态生成是根据给定的字符频率进行构建,而动态生成是根据实际数据的字符频率进行构建。

5.哈夫曼编码的时间复杂度为O(nlogn),其中n为字符的个数。

这是由于在构建哈夫曼树时需要进行n-1次合并操作,每次合并的时间复杂度为O(logn)。

6.哈夫曼树的构建方法主要有两种:霍夫曼算法和优先队列算法。

霍夫曼算法是经典的构建方法,通过反复选择权值最小的两个节点合并构建树,直到所有节点合并为一棵树。

优先队列算法则先将节点插入优先队列中,每次取权值最小的两个节点合并。

哈弗曼编码与译码

哈弗曼编码与译码

一个完整的系统应具有以下功能:(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.测试要求(1) 已知某系统在通信联络中只可能出现八种字符,其频率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。

(2) 用下表给出的字符集和频度的实际统计数据建立赫夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。

3.实现提示(1) 编码结果以文本方式存储在文件Codefile中。

(2) 用户界面可以设计为“菜单”方式:显示上述功能符号,再加上“Q”,表示退出运行Quit。

请用户键入一个选择功能符。

此功能执行完毕后再显示此菜单,直至某次用户选择了“Q”为止。

(3) 在程序的一次执行过程中,第一次执行I,D或C命令之后,赫夫曼树已经在存了,不必再读入。

每次执行中不一定执行I命令,因为文件hfmTree可能早已建好。

#include <string.h>#include <stdio.h>#include <stdlib.h>#include <malloc.h>typedef struct {char letter;float wt;}hfm,*hfmlist;//*************************全局变量************************************ unsigned int s1,s2,n;char choose;int DEPTH=0;char a[20];//***************Huffman树和Huffman编码的存储表示********************** typedef struct{unsigned int weight;unsigned int code;unsigned int parent,lchild,rchild;}HTNode, *HuffmanTree; //动态分配数组存储Huffman树typedef char * *HuffmanCode; //动态分配数组存储Huffman编码表//***************************初始化Huffman树***************************void select(HuffmanTree HT,int l){int a,b,c,j;s1=s2=1;a=b=1000;for(j=1;j<=l;j++){if(HT[j].code==0){c=HT[j].weight;if(c<a){b=a;a=c;s2=s1;s1=j;}else if(c<b){b=c;s2=j;}}//if}//forHT[s1].code=HT[s2].code=1;}//selectvoid HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC, hfmlist HL,unsigned int n){ //w存放n个权值(均>0),构造Huffman树HT,并求出n个字符的Huffman编码HC. unsigned int i,f,start,c,m;char*cd;if (n<=1) return;m =2*n-1;HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));for(i=1;i<=m;++i){HT[i].weight=HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].cod e=0;}for(i=1;i<=n;++i)HT[i].weight=HL[i].wt;for (i=n+1;i<=m;++i){select(HT,i-1);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;for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)if (HT[f].lchild==c) cd[--start]='0';else cd[--start]='1';HC[i]=(char*)malloc((n-start)*sizeof(char));strcpy(HC[i],cd+start);}free(cd);}//*************************文件操作*****************************void save (char *p){FILE *fp;int i;printf("input the name:");if((fp=fopen(gets(a),"w+"))==NULL){printf("cannot open the file!\n");exit(0);}//iffor(i=0;p[i]!='\0';i++){if(fwrite(p+i,sizeof(char),1,fp)!=1){//fwrite函数写数据块printf("File write error!\n");exit(0);}//if}//forfclose(fp);}//save//************************编码与译码操作********************************** void Decoding(HuffmanTree HT,hfmlist HL,char*size,int n)//这个函数是用来译码的 {int i,j,k;char p[130];printf("请输入需要译码的代码:");gets(p);//接受需要译码的字符串i=2*n-1;k=0;for(j=0;p[j]!='\0';j++){if(p[j]=='0'){ if(HT[i].lchild!=0)i=HT[i].lchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}else{ if(HT[i].rchild!=0)i=HT[i].rchild;else{ size[k++]=HL[i].letter;i=2*n-1;j--;}}}//forif( p[j-1]=='0')size[k++]=HL[i].letter;else size[k++]=HL[i].letter;size[k]='\0';}//decodingvoid Encoding(HuffmanCode HC,hfmlist HL,char *coding,int n){ int i,j,t,k=0;char p[100];printf("请再次输入需要编码的文本:");gets(p);for(i=0;p[i]!='\0';i++){if((p[i]>='A'&&p[i]<='Z')||p[i]==' ')for(j=1;j<=n;j++)if(p[i]==HL[j].letter)for(t=0;HC[j][t]!='\0';t++)coding[k++]=HC[j][t];}//forcoding[k]='\0';}//encoding//************************打印操作**************************** void Print(FILE *fp1,FILE *fp2){//将文件fp1中的代码以紧凑格式显示在终端上,每行50个代码//同时将此字符形式的编码文件写入文件fp2中char c[200];int i;fgets(c,200,fp1);for(i=0;c[i]=='0'||c[i]=='1';i++){printf("%c",c[i]);fprintf(fp2,"%c",c[i]);if((i+1)/50*50==(i+1)){printf("\n");fprintf(fp2,"\n");}}//forprintf("\n");}//Printvoid PreOrderTraverse(HuffmanTree HT,int k,FILE *fp){//先序遍历并打印树,结果存放于fp中,k为根结点的下标int i;for(i=1;i<=DEPTH-1;i++)fprintf(fp," ");for(;i<=DEPTH;i++)fprintf(fp,"|------");fprintf(fp,"%d\n",HT[k].weight);if(HT[k].lchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].lchild,fp);DEPTH--;}if(HT[k].rchild!=0){DEPTH++;PreOrderTraverse(HT,HT[k].rchild,fp);DEPTH--;}if(HT[k].lchild==0&&HT[k].rchild==0)return;return;} //PreOrderTraversevoid TreePrinting(HuffmanTree HT,int n,FILE *fp){//打印树HT,结果存于文件fp中,n为树的叶子结点数int i,k;for(i=1;i<=2*n;i++)if(HT[i].parent==0){k=i;break;}//寻找根结点PreOrderTraverse(HT,k,fp);return;}//TreePrinting//**************************主函数*********************************int main(){FILE *fp1,*fp2,*fp3,*fp4,*fp5;HuffmanTree HT;HuffmanCode HC;hfmlist HL;unsigned int i,n;char *b,c[100],cha,ch;b=(char *)malloc(100*sizeof(char));printf("请选择操作:\n");printf("i:初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");b=(char *)malloc(100*sizeof(char));HL=(hfmlist)malloc(30*sizeof(hfm));//存储字符与权值,线性表长30printf("\n");printf("选择操作(i,e,d,p,t,q):");ch=getchar();getchar();printf("\n");do{switch(ch){case 'i':printf("正在进行初始化……\n");printf("输入字符长度:");scanf("%d",&n);getchar();printf("\n");HC=(HuffmanCode)malloc((n+1)*sizeof(char));HT=(HuffmanTree)malloc((2*n)*sizeof(HTNode));for(i=1;i<=n;i++){printf("请输入第%d个字符及权值(格式:字符权值):",i);scanf("%c %f",&(HL+i)->letter, &(HL+i)->wt);getchar();}//forif((fp5=fopen("hfmTree.txt","w"))==NULL){printf("cannot open file!\n");exit(0);}//iffor(i=1;i<=n;i++){fprintf(fp5,"第%d个字符及权值:\t\t\t",i);fprintf(fp5,"%c %f\n",(HL+i)->letter,(HL+i)->wt);}//forfclose(fp5);HuffmanCoding(HT,HC,HL,n);printf("\n已经将Huffman树存入文件hfmTree.txt中\n\n");printf("初始化完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n\n");break;case 'e':printf("请输入编码,以#结尾:");if((fp2=fopen("ToBeTran.txt","w"))==NULL){printf("cannot open file\n");exit(0);}//ifcha=getchar();while(cha!='#'){fputc(cha,fp2);cha=getchar();}//whilegetchar();fclose(fp2);printf("已经把编码存入文件ToBeTran.txt中\n\n");Encoding(HC,HL,b,n);printf("文本的哈夫曼编码是:");printf("%s\n",b);printf("下面进行保存:");save(b);printf("编码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'd':Decoding(HT,HL,c,n);printf("输入要译码的编码:");printf("正在进行译码……\n");printf("%s\n",c);save(c);printf("已经将结果存入文件%s中\n",a);printf("译码完毕,请选择操作:\n");printf("i:重新初始化(Initialization)\ne:编码(Encoding)\nd:译码(Decoding)\n");printf("p:印代码文件(Print)\nt:印哈夫曼树(Tree printing)\nq:退出(Quit)\n");break;case 'p':for(i=1;i<=n;i++)printf("字符:%c\t\t\t译码:%s\n",HL[i].letter,HC[i]);if((fp1=fopen("CodeFile.txt","w"))==NULL){printf("cannot open the file!\n");exit(0);}//ifif((fp4=fopen("CodeFile.txt","r"))==NULL){printf("cannot open the file!\n");exit(0);}//ifPrint(fp4,fp1);printf("该代码文件已经存在并命名为CodePrin.txt\n"); fclose(fp4);fclose(fp1);break;case 't':printf("打印树存在于文件TreePrin中\n");if((fp3=fopen("TreePrin.txt","w"))==NULL){printf("cannot open file\n");exit(0);}TreePrinting(HT,n,fp3);fclose(fp3);break;case 'q':exit(0);break;default :exit(0);break;}//switchprintf("\n请选择操作(i,e,d,p,t,q):");ch=getchar();getchar();}while(ch!='q');//doreturn 0 ;}//main。

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告

哈夫曼编码译码器实验报告实验名称:哈夫曼编码译码器实验一、实验目的:1.了解哈夫曼编码的原理和应用。

2.实现一个哈夫曼编码的编码和译码器。

3.掌握哈夫曼编码的编码和译码过程。

二、实验原理:哈夫曼编码是一种常用的可变长度编码,用于将字符映射到二进制编码。

根据字符出现的频率,建立一个哈夫曼树,出现频率高的字符编码短,出现频率低的字符编码长。

编码过程中,根据已建立的哈夫曼树,将字符替换为对应的二进制编码。

译码过程中,根据已建立的哈夫曼树,将二进制编码替换为对应的字符。

三、实验步骤:1.构建一个哈夫曼树,根据字符出现的频率排序。

频率高的字符在左子树,频率低的字符在右子树。

2.根据建立的哈夫曼树,生成字符对应的编码表,包括字符和对应的二进制编码。

3.输入一个字符串,根据编码表将字符串编码为二进制序列。

4.输入一个二进制序列,根据编码表将二进制序列译码为字符串。

5.比较编码前后字符串的内容,确保译码正确性。

四、实验结果:1.构建哈夫曼树:-字符出现频率:A(2),B(5),C(1),D(3),E(1) -构建的哈夫曼树如下:12/\/\69/\/\3345/\/\/\/\ABCDE2.生成编码表:-A:00-B:01-C:100-D:101-E:1103.编码过程:4.译码过程:5.比较编码前后字符串的内容,结果正确。

五、实验总结:通过本次实验,我了解了哈夫曼编码的原理和应用,并且实现了一个简单的哈夫曼编码的编码和译码器。

在实验过程中,我充分运用了数据结构中的树的知识,构建了一个哈夫曼树,并生成了编码表。

通过编码和译码过程,我进一步巩固了对树的遍历和节点查找的理解。

实验结果表明,本次哈夫曼编码的编码和译码过程正确无误。

在实验的过程中,我发现哈夫曼编码对于频率较高的字符具有较短的编码,从而实现了对字符串的高效压缩。

同时,哈夫曼编码还可以应用于数据传输和存储中,提高数据的传输效率和存储空间的利用率。

通过本次实验,我不仅掌握了哈夫曼编码的编码和译码过程,还深入了解了其实现原理和应用场景,加深了对数据结构和算法的理解和应用能力。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

哈夫曼编码/译码一、【实验内容】【问题描述】利用哈夫曼编码进行住处通讯可以大大提高信道利用率,缩短住处传输时间,降低成本,但是,这要求在发送端通过一个编码系统将传输的数据预先编码,在接收端通过一个译码系统对传来的数据进行译码(复原),对于双向传输信息的信道,每端都一个完整的编码译码系统,试为这样的住处收发站写一个哈夫曼友的编码译码系统.【基本要求】:一个完整的系统应以下功能:(1) I. 初始化(Initialization)。

从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存放在文件hfmTree中. (2) E. 编码(Encoding)。

利用已建立好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果代码存(传输)到文件CodeFile中.(3) D. 译码(Decoding)。

利用已建好的哈夫曼树,对传输到达的Cod eFile中的数据代码进行译码,将译码结果存入文件TextFile中. (4) P. 印文件代码(Print)。

将文件CodeFile以紧凑格式显示在终端上,每行50个代码。

同时将此字符形式的编码文件写入文件CodePri n中。

(5) T. 印哈夫曼树(TreePrinting)。

将已在内存中的哈夫曼树以直观的方式(树或凹入表的形式)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint中。

测试数据:(1) 利用教科书例6-2中的数据调试程序。

(2) 用下表给出的字符集和频度的计数据建立哈曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”.。

字符 A B C D E F G H I J K L M频数 186 64 13 22 32 103 21 15 47 57 15 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、演示程序以用户与计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令,相应的输入数据(可虑去输入中的非法字符)和运算结果显示在其后。

4、本演示程序中,当用户选择的功能错误时,系统会输出相应的提示。

5、在本系统中,用户可以对任意长的字符串可进行编码/译码。

6、程序执行的命令包括:1) 初始化(I)2) 编码(E)3) 译码(D)4) 印代码文件(P)5) 印哈夫曼树(T)6) 退出(Q)7、测试数据:(1)利用教科书例6-2中的数据调试程序。

(2)用下表给出的字符集和频度的计数据建立哈曼树,并实现以下报文的编码和译码:“THIS PROGRAM IS MY FAVORITE”.。

字符 A B C D E F G H I J K L M频数 186 64 13 22 32 103 21 15 47 571 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 181 16 1二、概要设计为实现上述程序功能,应以指针存储结点。

为此,需要定义一个抽象数据类型。

1. 抽象数据类型定义为:ADT HuffmanTree{数据对象:D={ai| ai∈CharSet,i=1,2,……,n,n≥0}数据关系:R={< ai-1, ai > ai-1, ai∈D, ai-1<ai ,i=2,3,……,n}基本操作P:HuffmanTree(); 构造函数~ HuffmanTree(); 析构函数Initialization(int WeightNum);操作结果:构造哈夫曼树。

Encoder()初始条件:哈夫曼树已存在或者哈夫曼树已存到文件中。

操作结果:对字符串进行编码Decoder();初始条件:哈夫曼树已存在且已编码。

操作结果:对二进制串进行译码Print()初始条件:编码文件已存在。

操作结果:把已保存好的编码文件显示在屏幕TreePrinting()初始条件:哈夫曼树已存在。

操作结果:将已在内存中的哈夫曼树以直观的方式显示在终端上2.本程序包含三个模块:1)主程序模块:void main(){初始化;do{接受命令;处理命令;}while(“命令”=”退出”)}2)、建树模块——实现定义的抽象数据类型3)、编/译码模块——实现字符串的编/译码各模块之间的调用关系如下:主程序模块建树模块编/译码模块三、详细设计程序代码如下// 程序名:HuffmanTree.h// 程序功能:哈夫曼树类的头文件(并用其来实现编/译码) // 作者:刘伟高// 日期:2006.11.27// 版本:1.0//对应类实现文件: HuffmanTree.cpp//对应主程序文件: main.cpp#include<iostream>#include<fstream>#include<string>using namespace std;struct HuffmanNode //定义哈夫曼树各结点{int weight; //存放结点的权值,假设只考虑处理权值为整数的情况int parent; //记录结点父亲位置,-1表示为根结点,否则表示为非根结点int lchild,rchild; //分别存放该结点的左、右孩子的所在单元的编号};class HuffmanTree //建立哈夫曼树类{private:HuffmanNode *Node; //哈夫曼树中结点的存储结构char *Info; //用来保存各字符信息int LeafNum; //树中的叶子结点总数public:HuffmanTree(); //构造函数~HuffmanTree(); //析构函数void Initialization(int WeightNum); //初始化函数:根据Wei ghtNum个权值建立一棵哈夫曼树void Encoder(); //编码函数:利用构造好的哈夫曼树对字符进行编码void Decoder(); //译码函数:对二进制串进行译码void Print(); //印文件函数:把已保存好的编码文件显示在屏幕void TreePrinting(); //印哈夫曼树函数:将已在内存中的哈夫曼树以直观的方式显示在终端上};// 程序名:HuffmanTree.cpp// 程序功能:实现哈夫曼树类的源文件(并用其来实现编/译码) // 作者:刘伟高// 日期:2006.11.27// 版本:1.0#include"HuffmanTree.h"#include<string>using namespace std;/////////////////////////////////////////////////////////////// ///////////////// 构造函数// 函数功能:将结点指针初始化为NULL// 函数参数:无// 参数返回值:无HuffmanTree::HuffmanTree(){Node=NULL; //将树结点初始化为空Info=NULL; //将字符数组初始化为空LeafNum=0; //将叶子数初始化为0}/////////////////////////////////////////////////////////////////// ///////////// 析构函数// 函数功能:将所有结点的空间释放// 函数参数:无// 参数返回值:无HuffmanTree::~HuffmanTree(){delete[] Node; //释放结点空间delete[] Info; //释放字符存储空间}//////////////////////////////////////////////////////////////////////////////// 初始化函数// 函数功能:从终端读入字符集大小n,以及n个字符和n个权值, // 建立哈夫曼树,并将它存放在文件hfmTree中.// 函数参数:int WeightNum表示代码个数// 参数返回值:无void HuffmanTree::Initialization(int WeightNum) //初始化{int i,j,pos1,pos2,max1,max2; //Node=new HuffmanNode[2*WeightNum-1]; //WeightNum 权值对应的哈夫曼树中的结点总数为2*WeightNum-1个Info=new char[2*WeightNum-1];for(i=0;i<WeightNum;i++){cout<<"请输入第"<<i+1<<"个字符值";getchar(); //丢弃字符'\t'与'\n'Info[i]=getchar(); //输入一个字符,主要是考虑输入空格而采用这种形式的getchar();cout<<"请输入该字符的权值或频度";cin>>Node[i].weight; //输入权值Node[i].parent=-1; //为根结点Node[i].lchild=-1; //无左孩子Node[i].rchild=-1; //无右孩子}for(i=WeightNum;i<2*WeightNum-1;i++) //表示需做Weigh tNum-1次合并{pos1=-1;pos2=-1; //分别用来存放当前最小值和次小值的所在单元编号max1=32767; //32767为整型数的最大值max2=32767; //分别用来存放当前找到的最小值和次小值 for(j=0;j<i;j++) //在跟节点中选出权值最小的两个if(Node[j].parent==-1) //是否为根结点if(Node[j].weight<max1) //是否比最小值要小{max2=max1; //原最小值变为次小值max1=Node[j].weight; //存放最小值pos2=pos1; //修改次小值所在单元编号pos1=j; //修改最小值所在单元编号}elseif(Node[j].weight<max2) //比原最小值大但比原次小值要小{max2=Node[j].weight; //存放次小值pos2=j; //修改次小值所在的单元编号}//forNode[pos1].parent=i; //修改父亲位置Node[pos2].parent=i;Node[i].lchild=pos1; //修改儿子位置Node[i].rchild=pos2;Node[i].parent=-1; //表示新结点应该是根结点Node[i].weight=Node[pos1].weight+Node[pos2].weight; } //forLeafNum=WeightNum;char ch;cout<<"是否要替换原来文件(Y/N):";cin>>ch;if(ch=='y'||ch=='Y'){ofstream fop; //以二进制方式打开hfmTree.dat文件,并当重新运行时覆盖原文件fop.open("hfmTree.dat",ios::out|ios::binary|ios::trunc);if(fop.fail()) //文件打开失败cout<<"文件打开失败!\n";fop.write((char*)&WeightNum,sizeof(WeightNum)); //写入WeightNumfor(i=0;i<WeightNum;i++) //把各字符信息写入文件{fop.write((char*)&Info[i],sizeof(Info[i]));flush(cout);}for(i=0;i<2*WeightNum-1;i++) //把个节点内容写入文件 {fop.write((char*)&Node[i],sizeof(Node[i]));flush(cout);}fop.close(); //关闭文件}cout<<"哈夫曼树已构造完成。

相关文档
最新文档