完整word版哈夫曼编码和译码系统.docx
- 文档编号:29274431
- 上传时间:2023-07-21
- 格式:DOCX
- 页数:20
- 大小:256.21KB
完整word版哈夫曼编码和译码系统.docx
《完整word版哈夫曼编码和译码系统.docx》由会员分享,可在线阅读,更多相关《完整word版哈夫曼编码和译码系统.docx(20页珍藏版)》请在冰豆网上搜索。
完整word版哈夫曼编码和译码系统
通达学院
算法与数据结构程序设计
题目:
哈夫曼编码和译码系统
专业
学生姓名
班级学号
指导教师
指导单位
日期
教师评语
同学出勤率(满勤、较高、一般,较低),学习态度(端正、较端正、一般、较差),程序设计基础(好、较好、一般、较差),演示程序(已经、没有)达到了基本要求,算法设计(好、较好、一般),界面友好程度(好、较好、一般),答辩过程中回答问题(准确、较准确、错误率较高),撰写报告格式(规范、一般)、内容(丰满、简单)、表述(清晰、一般、不清楚),(圆满、较好、基本)完成了课题任务。
教师签名:
年月日
成绩评定
备注
一、题目要求:
题目:
哈夫曼编码和译码系统
基本要求:
(1)能输入字符集和各字符频度建立哈夫曼树;
(2)产生各字符的哈夫曼编码,并进行解码。
提高要求:
(1)能设计出简捷易操作的窗口界面;
(2)编码和译码存储在文件中。
二、需求分析:
2.1基本思想
根据,哈夫曼的定义,一棵二叉树要使其带权路径长度最小,必须使权值越大的叶子结点越靠近根结点,而权值越小的叶子结点越远离根结点.依据这个特点便提出了哈夫曼算法,其基本思想是:
(1)初始化:
由给定的n个权值{w1,w2,…,wn}构造n棵只有一个根结点的二叉树,从而得到一个二叉树集合F={T1,T2,…,Tn};
(2)选取与合并:
在F中选取根结点的权值最小的两棵二叉树分别作为左、右子树构造一颗新的二叉树,这棵新二叉树的根结点的权值为其左、右子树根结点的权值之和;
(3)删除与加入:
在F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到F中;
(4)重复
(2)、(3)两步,当集合F中只剩下一棵二叉树时,这棵二叉树便是哈夫曼树.
2.2存储结构
在由哈夫曼算法构造的哈夫曼树中,非叶子结点的度均为2,根据二叉树的性质可知,具有n个叶子结点的哈夫曼树共有2n-1个结点,其中有n-1个非叶子结点,它们是在n-1次的合并过程中生成的.为了便于选取根结点权值最小的二叉树以及合并操作,设置一个数组HuffmanNode[2n-1]保存哈夫曼树中各结点的信息,数组元素的结点结构如图所示.
weight
parent
lchild
rchild
inf
图哈夫曼树的结点结构
其中:
weight:
权值域,保存该结点的权值;
Lchild:
指针域,保存该结点的左孩子结点在数组中的下标;
Rchild:
指针域,保存该结点的右孩子结点在数组中的下标;
parent:
指针域,保存该结点的双亲结点在数组中的下标.
三、概要设计:
1.我首先创建了两个结构体HTNode和Node,分别来记录哈弗曼树各节点的信息以及叶子节点的信息。
建立六个成员函数,如下图所示:
各功能函数实现如下功能:
1、voidCreateWeight(){......}
作用:
产生叶子结点的字符和权值。
2、voidCreateHuffmanTree(){......}
作用:
创建HuffmanTree。
3、voidCrtHuffmanNodeCode(){......}
作用:
生成叶子结点的编码
4、voidCrtHuffmanCode(){......}
作用:
生成所有字符的编码
5、voidTrsHuffmanTree(){......}
作用:
解码
6、主函数main()
四、详细设计
voidCreateWeight(charch[],int*s,WeightNodeCW,int*p)
其中形参分别表示:
charch[]//存放用户输入的字符串
int*s//字符串ch[]的长度
WeightNodeCW//存放叶子节点的信息
int*p//叶子节点的个数
核心功能:
函数通过定义三个变量i,j,k,来控制三个循环,主要是为了遍历字符串,找出叶子节点的字符与权值信息。
voidCreateHuffmanTree(Huffmanht,WeightNodeCW,intn)
形参表示:
Huffmanht//Huffman的一个对象ht
WeightNodeCW//权值大小
intn//叶子节点的个数
功能描述:
函数先通过两个for循环对哈夫曼树进行初始化,然后在通过一个循环每次找出权值最小的两个节点,进行权值相加。
voidCrtHuffmanNodeCode(Huffmanht,charch[],HuffmanCodeh,WeightNodeweight,intm,intn)
形参表示:
Huffmanht//Huffman的一个对象
charch[]//存放用户输入的字符串
HuffmanCodeh//存放叶子节点的编码
WeightNodeweight//叶子节点的信息(字符与权值)
intm//字符串ch[]的长度
intn//叶子节点的个数
函数功能:
这个函数从每个叶子节点出发,通过比较父类的左孩子的数组下标是否与对应的左孩子下标相同,相同则置0,不同则置1.(从后往前置数)
核心代码:
for(i=1;i<=n;i++)
{
start=n-1;//cd串每次从末尾开始
c=i;
p=ht[i].parent;//p在n+1至2n-1
while(p)//沿父亲方向遍历,直到为0
{
start--;//依次向前置值
if(ht[p].LChild==c)//与左孩子结点在数组中的下标相同,置0
cd[start]='0';
else//与右孩子结点在数组中的下标相同,置1
cd[start]='1';
c=p;
p=ht[p].parent;
}
voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCodehc,WeightNodeweight,intn,intm)
功能描述:
通过循环遍历整个字符串,再通过判断每一个字符串与相应的叶子节点的字符相同,相同的话,则将该叶子节点的编码拷贝到hc[]数组中。
完成所有字符的编码。
核心代码:
for(i=0;i { for(k=1;k<=n;k++)/*从weight[k].c中查找与ch[i]相等的下标K*/ if(ch[i]==weight[k].c) break; hc[i]=(char*)malloc((weight[k].num)*sizeof(char)); strcpy(hc[i],h[k]);//拷贝二进制编码 } } voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm) 功能描述: TrsHuffmanTree(ht,weight,hc,n,m);为该函数的调用 其中: ht,weight,hc,n,m,分别表示哈夫曼对象,叶子节点对象,存放所有字符编码的数组hc,叶子节点的个数n,一起字符串的长度m。 核心代码: while(i { p=2*n-1;//从父亲节点向下遍历直到叶子节点 for(j=0;hc[i][j]! ='\0';j++) { if(hc[i][j]=='0') p=ht[p].LChild; else p=ht[p].RChild; } printf("%c",w[p].c);/*打印原信息*/ i++;} 5、测试数据及其结果分析 当程序运行后,提示用户输入需要编码的字符串,假如我输入: woshiyuanhao 则程序运行后会打印出叶子节点的字符和所对应的权值,如下图所示: 继续按任意键则会打印出所对应的哈夫曼树,如下图所示: 根据所画的哈弗曼数的直观图,可以对照的依次写出每个字符的编码,如下图所示: 输出所有字符的编码: 最后将编码还原成字符串,如下图: 下面是程序运行的全过程: 从中可以看出程序大抵完成了哈夫曼树的编码与解码功能 六、总结 程序分析: 本次哈夫曼编码译码器的课程实验做得还算成功,不仅仅在于程序能够正常运行,实现应有的功能,关键在于过程,在于小组成员的分工合作和一起纠错排错的过程,在完成程序的过程中才能真正理解面向对象和模块化设计的思想,我们不仅仅是说要每人分几个函数,关键在于这些函数代表的是一个个功能模块,任何一个模块出现问题或者模块之间的衔接出现问题都将导致程序运行的失败。 在初始设计的时候,我体会到书写流程图的重要性,只有又一个清晰的设计思路才能事半功倍,分工明确,避免无效劳动或者在错误的编程方向上走弯路,也让大家明白自己在程序设计中的位置和职责。 初始的创建是哈夫曼编码译码系统成功的关键,我在创建的过程当中多次使用树的先根,配合中根遍历操作,输出接点字符或者权重信息,作为检验,对验证和纠错起到了非常大的作用。 在适当的地方调用它们,运行时可以看到验证编写程序的正确性; 通过本次实验,提高了自已调试程序的能力。 充分体会到了在程序执行时的提示性输出的重要性。 编写大一点的程序,应先写出算法,再写程序,一段一段调试;对于没有实现的操作用空操作代替,这样容易找出错误所在。 最忌讳将所有代码写完后再调试,这样若程序有错误,太难找。 附录: 完整程序代码: #include #include #include #defineN100//定义叶子节点最多100个 #defineM2*N-1//所有节点的个数 typedefchar*HuffmanCode[2*M];//haffman编码 typedefstruct { intweight;//权值 intparent;//父节节点 intLChild;//左子节点 intRChild;//右子节点 }HTNode,Huffman[M+1];//huffman树 typedefstructNode { intweight;//叶子结点的权值 charc;//叶子结点 intnum;//叶子结点的二进制码的长度 }WNode,WeightNode[N]; /***产生叶子结点的字符和权值***/ voidCreateWeight(charch[],int*s,WeightNodeCW,int*p) { inti,j,k; inttag; *p=0;//叶子节点个数 //统计字符出现个数,放入CW for(i=0;ch[i]! ='\0';i++) { tag=1; for(j=0;j if(ch[j]==ch[i])//通过判断让相同元素存在同一个数组单元中 { tag=0; break; } if(tag) { CW[++*p].c=ch[i]; CW[*p].weight=1; for(k=i+1;ch[k]! ='\0';k++) if(ch[i]==ch[k]) CW[*p].weight++;//权值累加 } } *s=i;//字符串长度 } /********创建HuffmanTree********/ voidCreateHuffmanTree(Huffmanht,WeightNodew,intn) { inti,j; ints1,s2; //初始化哈夫曼树 for(i=1;i<=n;i++) { ht[i].weight=w[i].weight; ht[i].parent=0; ht[i].LChild=0; ht[i].RChild=0; } for(i=n+1;i<=2*n-1;i++) { ht[i].weight=0; ht[i].parent=0; ht[i].LChild=0; ht[i].RChild=0; } for(i=n+1;i<=2*n-1;i++) { for(j=1;j<=i-1;j++) if(! ht[j].parent) break; s1=j;//找到第一个双亲不为零的结点 for(;j<=i-1;j++) if(! ht[j].parent) s1=ht[s1].weight>ht[j].weight? j: s1; ht[s1].parent=i; ht[i].LChild=s1; for(j=1;j<=i-1;j++) if(! ht[j].parent) break; s2=j;//找到第二个双亲不为零的结点 for(;j<=i-1;j++) if(! ht[j].parent) s2=ht[s2].weight>ht[j].weight? j: s2; ht[s2].parent=i; ht[i].RChild=s2; ht[i].weight=ht[s1].weight+ht[s2].weight;//权值累加 } } /***********叶子结点的编码***********/ voidCrtHuffmanNodeCode(Huffmanht,charch[],HuffmanCodeh,WeightNodeweight,intm,intn) { inti,c,p,start; char*cd; cd=(char*)malloc(n*sizeof(char)); cd[n-1]='\0';//末尾置0 for(i=1;i<=n;i++) { start=n-1;//cd串每次从末尾开始 c=i; p=ht[i].parent;//p在n+1至2n-1 while(p)//沿父亲方向遍历,直到为0 { start--;//依次向前置值 if(ht[p].LChild==c)//与左孩子结点在数组中的下标相同,置0 cd[start]='0'; else//与右孩子结点在数组中的下标相同,置1 cd[start]='1'; c=p; p=ht[p].parent; } weight[i].num=n-start;//二进制码的长度(包含末尾0) h[i]=(char*)malloc((n-start)*sizeof(char)); strcpy(h[i],&cd[start]);//将二进制字符串拷贝到指针数组h中 } free(cd);//释放cd内存 system("pause"); } /*********所有字符的编码*********/ voidCrtHuffmanCode(charch[],HuffmanCodeh,HuffmanCodehc,WeightNodeweight,intn,intm) { inti,k; for(i=0;i { for(k=1;k<=n;k++)/*从weight[k].c中查找与ch[i]相等的下标K*/ if(ch[i]==weight[k].c) break; hc[i]=(char*)malloc((weight[k].num)*sizeof(char)); strcpy(hc[i],h[k]);//拷贝二进制编码 } } /*****解码*****/ voidTrsHuffmanTree(Huffmanht,WeightNodew,HuffmanCodehc,intn,intm) { inti=0,j,p; printf("***解码出的字符串***\n"); while(i { p=2*n-1;//从父亲节点向下遍历直到叶子节点 for(j=0;hc[i][j]! ='\0';j++) { if(hc[i][j]=='0') p=ht[p].LChild; else p=ht[p].RChild; } printf("%c",w[p].c);/*打印原信息*/ i++; } } /*****释放huffman编码内存*****/ voidFreeHuffmanCode(HuffmanCodeh,HuffmanCodehc,intn,intm) { inti; for(i=1;i<=n;i++)//释放叶子结点的编码 free(h[i]); for(i=0;i free(hc[i]); } voidmain() { inti,n=0;/*n为叶子结点的个数*/ intm=0;/*m为字符串ch[]的长度*/ charch[N];/*ch[N]存放输入的字符串*/ Huffmanht;/*Huffman二叉数*/ HuffmanCodeh,hc;/*h存放叶子结点的编码,hc存放所有结点的编码*/ WeightNodeweight;/*存放叶子结点的信息*/ printf("\t******HuffmanCoding******\n"); printf("\t******10002929袁豪******\n"); printf("\t*************************\n"); printf("请输入要编码的字符串: "); gets(ch);/*输入字符串*/ CreateWeight(ch,&m,weight,&n);/*产生叶子结点信息,m为字符串ch[]的长度*/ printf("***叶子节点的字符与权值信息***\nNode"); for(i=1;i<=n;i++)/*输出叶子结点的字符与权值*/ printf("%c",weight[i].c); printf("\nWeight"); for(i=1;i<=n;i++) printf("%d",weight[i].weight); system("pause"); CreateHuffmanTree(ht,weight,n);/*产生Huffman树*/ printf("\n***显示哈夫曼树***\n"); printf("\ti\tweight\tparent\tLChild\tRChild\n"); for(i=1;i<=2*n-1;i++)/*打印Huffman树的信息*/ printf("\t%d\t%d\t%d\t%d\t%d\n",i,ht[i].weight,ht[i].parent,ht[i].LChild,ht[i].RChild)CrtHuffmanNodeCode(ht,ch,h,weight,m,n);/*叶子结点的编码*/ printf("***显示叶子节点编码e***\n");/*打印叶子结点的编码*/ for(i=1;i<=n;i++) { printf("\t%c: ",weight[i].c); printf("%s\n",h[i]); } system("pause"); CrtHuffmanCode(ch,h,hc,weight,n,m);/*所有字符的编码*/ printf("***显示字符串编码***\n");/*打印字符串的编码*/ for(i=0;i printf("%s",hc[i]); system("pause"); TrsHuffmanTree(ht,weight,hc,n,m);/*解码*/ FreeHuffmanCode(h,hc,n,m); system("pause"); }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 完整 word 版哈夫曼 编码 译码 系统
