哈夫曼编码信息论大作业模板.docx
- 文档编号:9221685
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:21
- 大小:254.79KB
哈夫曼编码信息论大作业模板.docx
《哈夫曼编码信息论大作业模板.docx》由会员分享,可在线阅读,更多相关《哈夫曼编码信息论大作业模板.docx(21页珍藏版)》请在冰豆网上搜索。
哈夫曼编码信息论大作业模板
哈夫曼编码
1.前言:
Haffman算法是个简单而高效的贪心算法,主要用来创建最优二叉树.可以在通讯时,对于出现频率较高的字符,用较少的比特数便可以进行通讯.从而节省通讯线路的资源消耗。
该算法在各类数据结构,算法,组合数学,离散数学,图论等主题的书籍中都有所涉及。
故本文不再赘述,本文致力于用Haffman算法实现压缩与解压缩,采用的语言为C语言,编译环境VC++6.0.
下面给出[1]中实现的Haffman树的结构及创建算法,有两点说明:
a) 这里的Haffman树采用的是基于数组的带左右儿子结点及父结点下标作为存储结点
的二叉树形式,这种空间上的消耗带来了算法实现上的便捷。
b) 由于对于最后生成的Haffman树,其所有叶子结点均为从一个内部树扩充出去的,所以,当外部叶子结点数为m个时,内部结点数为m-1.整个Haffman树的需要的结点数为2m-1.
2压缩过程的实现:
压缩过程的流程是清晰而简单的:
1创建Haffman树à2打开需压缩文件à3将需压缩文件中的每个ascii码对应的haffman编码按bit单位输出à4文件压缩结束。
其中,步骤1和步骤3是压缩过程的关键。
a) 步骤1:
这里所要做工作是得到Haffman数中各叶子结点字符出现的频率并进行创建.
统计字符出现的频率可以有很多方法:
如每次创建前扫描被创建的文件,“实时”的生成
各字符的出现频率;或者是创建前即做好统计.本文采用后一种的方案,统计了十篇不同的文章中字符出现的频率。
当前,也可以根据被压缩文件的特性有针对性的进行统计,如要压缩C语言的源文件,则可事先对多篇C语言源文件中出现的字符进行统计,这样,会创建出高度相对较“矮”的Haffman树,从而提高压缩效果。
创建Haffman树的算法前文已有陈述,这里就不再重复了。
b) 步骤3:
将需压缩文件中的每个ascii码对应的haffman编码按bit单位输出.
这是本压缩程序中最关键的部分:
这里涉及“转换”和“输出”两个关键步骤:
“转换”部分大可不必去通过遍历Haffman树来找到每个字符对应的哈夫曼编码,可以将每个Haffman码值及其对应的ascii码存放于如下所示的结构体中:
2.算术编码
(1)算术编码是把一个信源表示为实轴上0和1之间的一个区间,信源集合中的每一个元素都用来缩短这个区间。
(2)设计思想:
其算法的主要算法基本思想:
首先就是构造一个结构体用于存储信源的相关信息(包括信源符号,信源概率,编码的上下限);接着就是初始化信源的相关信息,如初始化编码间隔;利用算术编码的原理构造编码方法,最后实现编码。
(3)调试分析:
此算法主要就是算术编码方法的构造,利用算法中Initial_message()函数初始化以后,根据初始化间隔完成编码序列的编码。
在调试的过程中经常遇到一些小问题,通过一步步的调试以及修改,问题一个的解决了。
同时也遇到比较大的问题,就是编码方法过程的实现,最大的体会就是必须深入理解次编码方法的原理。
(4)流程图
(5)测试结果:
(6)源程序清单:
#include
#include
#include
#defineN4//信源符号的个数
#definen7//要编码的序列长度
structARC
{
charm[N];
floatP[N];
floatLow[N];
floatHigh[N];
floatlow;
floathigh;
}code;
Initial_message()//初始化编码间隔
{
floatF=0;
inti=0,j;
printf("请输入%d个信源符号及其概率!
\n",N);
for(i=0;i { scanf("%c%f",&code.m[i],&code.P[i]); getchar(); } for(j=0;j { code.Low[j]=F; F=F+code.P[j]; code.High[j]=F; } printf("信源符号概率初始编码间隔\n"); for(j=0;j { printf("%c%f[%f,%f)\n",code.m[j],code.P[j],code.Low[j],code.High[j]); } } main() { inti=0; intBcode[10]; charc[n]; char*p=NULL; char*q=NULL; floats,mid; Initial_message(); printf("请输入长度为%d要编码的序列: ",n); scanf("%s",c); p=c; q=code.m; while(q! =NULL)//判定第一个需要编码序列的第一符号所在的间隔 { if(*p==*q) { code.low=code.Low[i]; code.high=code.High[i]; printf("%c\n[%f,%f)\n",code.m[i],code.low,code.high); gotoss; } else { q++; i++; } } ss: p++; while(*p! ='\0')//利用算术编码的方法,求出编码的十进制结果 { intk=0; floatt; floatpt=0; intk1; q=code.m; while(*q! ='\0') { if(*p==*q) { if(k==0) { t=code.high-code.low; code.low=code.low+t*pt; code.high=code.low+t*code.P[k]; printf("%c\n[%f,%f)\n",code.m[k],code.low,code.high); gotoxx; } else { k1=k; while(k1) { t=code.high-code.low; pt=pt+code.P[k1-1]; k1--; } code.low=code.low+t*pt; code.high=code.low+t*code.P[k]; printf("%c\n[%f,%f)\n",code.m[k],code.low,code.high); gotoxx; } } else q++; k++; } xx: p++; } mid=(code.high-code.low)/2+code.low; s=2*mid; for(i=0;i<10;i++)//编码结果 { if(s>1) {Bcode[i]=1; s=s-1; } else { Bcode[i]=0; } s=2*s; printf("%d",Bcode[i]); } printf("\n"); } 3.Huffman编码对英文文本的压缩和解压缩 (1)根据信源压缩编码——Huffman编码的原理,制作对英文文本进行压缩和解压缩的软件。 要求软件有简单的用户界面,软件能够对运行的状态生成报告,分别是: 字符频率统计报告、编码报告、压缩程度信息报告、码表存储空间报告。 (2)设计思想: 首先构造一个结构体用于统计字符频率,然后把统计后的结果当作信源;接着用Haffman编码的方法对其编码,编码后对输入的英语文本进行编码的转换,即用Haffman编码的每一个字符的编码代替输入的英语文本每一字符,输入的英语文本就变成了01代码流,最后利用这01代码流每八位压缩成相对应的字符。 压缩流程: 读取扫描文本文件——〉统计字符频率——〉生成码字——〉保存压缩文件 解压缩流程: 读取扫描压缩文件——〉提取字符频率——〉生成码树——〉保存文本文件 (3)调试分析: 本算法可以分成四个部分即统计字符概率,Huffman编码,压缩文件和解压文件四部分,也就是次算法中函数stati(),函数HCode()和函数compress()的构建,用于压缩后的字符出现了乱码,所以对解压文件这部分难以实现,这也是此算法失败的地方。 经过不断的调试和修改还是只完成统计字符概率,Huffman编码和压缩文件这三部分。 (4)流程图 (5)测试结果: (6)源程序清单: #include #include #defineMaxValue1000//设定权值最大值 #defineMaxBit10//设定的最大编码位数 #defineMaxN1000//设定的最大结点个数 #include"Huffman.h" floatComNum=0;//用于计算压缩后的字符个数 structstatistics//统计字符频率 { chara[100];//出现的字符 doublep[100];//字符出现的概率 inttag[100];//每一个字符出现次数 intnum;//总计出现的字符种类个数 floatn;//总计字符出现的次数 }TJ; charcc[100]; voidraplace(myHaffCode); stati()//统计字符 { FILE*fp; FILE*fp1; charch,filename[10]; inti=0,k; printf("请输入用于保存字符文本的文件名,如file.txt\n"); scanf("%s",filename); getchar(); printf("请输入英语文本: "); gets(cc); fp=fopen(filename,"w+"); fprintf(fp,"%s",cc); fclose(fp); TJ.num=1; TJ.n=0; if((fp1=fopen(filename,"r"))==NULL) { printf("文件无法打开! "); exit(0); } ch=fgetc(fp1); TJ.a[i]=ch; while(ch! =EOF)//统计字符出现的次数,并计算起概率。 { intj; for(j=i;j>=0;j--) { if(TJ.a[j]==ch) { TJ.tag[j]+=1; gotoxx; } } i++; TJ.a[i]=ch; TJ.tag[i]+=1; TJ.num++; xx: ch=fgetc(fp1); TJ.n++; } fclose(fp1); for(k=0;k<=i;k++) { TJ.p[k]=TJ.tag[k]/TJ.n; } printf("\t字符统计\n"); printf("字符出现的次数概率\n"); for(k=0;k<=i;k++) { printf("%c%d%1.10f\n",TJ.a[k],TJ.tag[k],TJ.p[k]); } } HCode()//haffman编码 { inti,j,n=TJ.num; HaffNode*myHaffTree=(HaffNode*)malloc(sizeof(HaffNode)*(2*n+1)); Code*myHaffCode=(Code*)malloc(sizeof(Code)*TJ.num); for(i=0;i { intt=TJ.tag[i]; chart1=TJ.a[i]; for(j=i+1;j { if(t>TJ.tag[j]) { t=TJ.tag[j]; TJ.tag[j]=TJ.tag[i]; TJ.tag[i]=t; t1=TJ.a[j]; TJ.a[j]=TJ.a[i]; TJ.a[i]=t1; } } } Haffman(TJ.tag,n,myHaffTree);//建立叶结点个数为n权值数组为J.tag的哈夫曼树myHaffTree HaffmanCode(myHaffTree,n,myHaffCode);//由n个结点的夫曼树myHaffTree构造哈夫曼编码myHaffCode printf("\tHaffman编码\n"); printf("信源符号权值编码结果\n"); for(i=0;i { printf("%cWeight=%dCode=",TJ.a[i],myHaffCode[i].weight); for(j=myHaffCode[i].start;j printf("%d",myHaffCode[i].bit[j]); printf("\n"); } raplace(myHaffCode); } voidraplace(CodemyHaffCode[])//把英语文本的字母包(括标点符号)用已经用Haffman编码完成的编码结果代替成01代码并存于文件code.txt中 { charch; inti,n,j; FILE*fp1; if((fp1=fopen("code.txt","w+"))==NULL) { printf("文件无法打开! "); exit(0); } n=0; ch=cc[n]; while(ch! ='\0') { for(j=0;j { if(ch==TJ.a[j]) { for(i=myHaffCode[j].start;i fprintf(fp1,"%d",myHaffCode[j].bit[i]); j=TJ.num; } } n++; ch=cc[n]; } fclose(fp1); } voidcompress()//根据保存于code.txt的01代码每八位压缩一次 { FILE*fp1,*fp2; intch; charc; inti=0; intvalue; inta[8]={0}; fp1=fopen("code.txt","r"); fp2=fopen("yasuo.txt","w+");//yasu.txt用于存储压缩后的结果 while(! feof(fp1)) { fscanf(fp1,"%1d",&ch); a[i]=ch; i++; if(i==8) { value=a[0]*128+a[1]*64+a[2]*32+a[3]*16+a[4]*8+a[5]*4+a[6]*2+a[7]; c=value; fprintf(fp2,"%c",c); ComNum++; i=0; } } if(i! =0) { while(i==8) { a[i]=0; i++; } value=a[0]*128+a[1]*64+a[2]*32+a[3]*16+a[4]*8+a[5]*4+a[6]*2+a[7]; c=value; fprintf(fp2,"%c",c); ComNum++; } fclose(fp2); fclose(fp1); } main() { floatp;//用于计算压缩率 printf("\tHuffman编码的对英文文本压缩和解压缩\n"); stati();//统计 HCode();//编码 compress();//压缩 p=((TJ.n-ComNum)/TJ.n); printf("压缩后的结果保存于文件yasuo.txt\n其压缩率为%f\n",p); } 总结: 本次课程设计能够完满的结束,关键在于组员之间有效的分工合作。 我们在一起纠错排错的过程中才真正理解面向对象和模块化设计的思想,每一个模块火气之间的衔接出现问题都有可能导致整个程序的运行失败。 程序中有些代码重复出现,从而减少了空间的利用率和增加了程序代码的杂乱性,特别是文件操作方面,如果可能的话,可以把文件读入、读出分别写成一个函数(就是把文件名作为参数),然后就可以直接调用了。 需要注意数字0,1和字符0,1的区别。 由于自己对操作的不熟练使得本次试验又增加了一些难度,所幸的是最终发现并解决了这样的问题。 由于二维指针和循环程序的推敲不足,使程序调试时费时不少,同时由于自己对操作的不熟练使得本次试验又增加了一些难度,所幸的是最终发现并解决了这样的问题。 经过这次试验,我们收获良多。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 编码 信息论 作业 模板