霍夫曼树 算法课程设计.docx
- 文档编号:5225140
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:14
- 大小:123.16KB
霍夫曼树 算法课程设计.docx
《霍夫曼树 算法课程设计.docx》由会员分享,可在线阅读,更多相关《霍夫曼树 算法课程设计.docx(14页珍藏版)》请在冰豆网上搜索。
霍夫曼树算法课程设计
算法设计与分析
课程设计报告
设计题目:
HuffmanCodes
专业信息与计算科学
班级2009级1班
学生孙某某郑某
学号0918010709180109
指导教师莫某某某某
起止时间2011/12/19~2011/12/30
算法设计分析
平时表现
程序演示
综合成绩
2011年12月
实验题目哈夫曼编码
一、问题描述:
ProblemE
DanMcAmbiisamemberofacrackcounter-espionageteamandhasrecentlyobtainedthepartialcontentsofafilecontaininginformationvitaltohisnation!
ˉsinterests.ThefilehadbeencompressedusingHuffmanencoding.Unfortunately,thepartofthefilethatDanhasshowsonlytheHuffmancodesthemselves,notthecompressedinformation.SinceHuffmancodesarebasedonthefrequenciesofthecharactersintheoriginalmessage,Dan!
ˉsbossthinksthatsomeinformationmightbeobtainedifDancanreversetheHuffmanencodingprocessandobtainthecharacterfrequenciesfromtheHuffmancodes.Dan!
ˉsgutreactiontothisisthatanygivensetofcodescouldbeobtainedfromawidevarietyoffrequencydistributions,buthisbossisnotimpressedwiththisreasonedanalysis.SoDanhascometoyoutogetmoredefinitiveprooftotakebacktohisboss.
Huffmanencodingisanoptimaldatacompressionmethodifyouknowinadvancetherelativefrequenciesoflettersinthetexttobecompressed.ThemethodworksbyfirstconstructingaHuffmantreeasfollows.Startwithaforestoftrees,eachtreeasinglenodecontainingacharacterfromthetextanditsfrequency(thecharactervalueisusedonlyintheleavesoftheresultingtree).Eachstepoftheconstructionalgorithmtakesthetwotreeswiththelowestfrequencyvalues(choosingarbitrarilyifthereareties),andreplacesthemwithanewtreeformedbyjoiningthetwotreesastheleftandrightsubtreesofanewrootnode.Thefrequencyvalueofthenewrootisthesumofthefrequenciesofthetwosubtrees.Thisprocedurerepeatsuntilonlyonetreeisleft.Anexampleofthisisshownbelow,assumingwehaveafilewithonly5characters¨CA,B,C,DandE¨Cwithfrequencies10%,14%,31%,25%and20%,respectively.
AfteryouhaveconstructedaHuffmantree,assigntheHuffmancodestothecharactersasfollows.Labeleachleftbranchofthetreewitha0andeachrightbranchwitha1.ReadingdownfromtheroottoeachcharactergivestheHuffmancodeforthatcharacter.ThetreeaboveresultsinthefollowingHuffmancodes:
A-010,B-011,C-11,D-10andE-00.
Forthepurposeofthisproblem,thetreewiththelowerfrequencyalwaysbecomestheleftsubtreeofthenewtree.Ifbothtreeshavethesamefrequencies,eitherofthetwotreescanbechosenastheleftsubtree.Notethatthismeansthatforsomefrequencydistributions,thereareseveralvalidHuffmanencodings.
ThesameHuffmanencodingcanbeobtainedfromseveraldifferentfrequencydistributions:
change14%to13%and31%to32%,andyoustillgetthesametreeandthusthesamecodes.DanwantsyoutowriteaprogramtodeterminethetotalnumberofdistinctwaysyoucouldgetagivenHuffmanencoding,assumingthatallpercentagesarepositiveintegers.Notethattwofrequencydistributionsthatdifferonlyintheorderingoftheirpercentages(forexample30%70%foronedistributionand70%30%foranother)arenotdistinct.
Input
Theinputconsistsofseveraltestcases.Eachtestcaseconsistsofasinglelinestartingwithapositiveintegern(2n20),whichisthenumberofdifferentcharactersinthecompresseddocument,followedbynbinarystringsgivingtheHuffmanencodingofeachcharacter.YoumayassumethatthesestringsareindeedaHuffmanencodingofsomefrequencydistribution(thoughunderouradditionalassumptions,itmaystillbethecasethattheansweris0¨Cseethelastsamplecasebelow).
Thelasttestcaseisfollowedbyalinecontainingasinglezero.
Output
Foreachtestcase,printalinecontainingthetestcasenumber(beginningwith1)followedbythenumberofdistinctfrequencydistributionsthatcouldresultinthegivenHuffmancodes.
DanMcAmbi是一个发间谍组织的成员,最近他获得了一个包含着关于他的国家利益的至关重要信息的文件的部分内容。
这份文件已经被用赫夫曼编码压缩。
不幸的是,Dan拥有的部分文件是用赫夫曼编码本身显示的,而不是压缩文件。
由于赫夫曼编码是基于原始信息中代码的频率而编写的,Dan的老板认为如果Dan能够倒转赫夫曼编码的程序并且获得赫夫曼编码中代码的频率,那么就能够获得一些信息。
Dan对这一信息的本能反应就是所有给定的编码能够从广泛的多样的频率分布中获得,但是他的老板并不为这一合理的分析所吸引。
所以Dan想请你帮忙,希望你可以获得更多决定性的证明,让他带回给他的老板。
如果你提前知道被压缩文件中字母的相对概率,那么赫夫曼编码就是一种很理想的文件压缩方法。
这种方法首先通过构造一些赫夫曼树来展开工作。
以森林的树为开始,以森林的树为开始,每棵树的每个单节点都包含了一个文件中的符号以及它的频率(元素的价值只被用在最终树的叶子节点中)构造该算法的每一步就是取两棵最低频率价值的树(如果两棵树的概率相同,那么任意选取),然后用一棵由这两棵树分别作为左右子树的以及新的根节点的树来代替它们。
新的根的频率是两棵子树价值频率总和。
重复的进行这一步骤直到只剩下一棵树为止。
下面是一个例子,假设我们有一个包含五个元素的文件A、B、C、D、E以及它们分别的概率是10%,14%,31%,25%和20%。
在你构造好赫夫曼树之后,给下面的元素分配赫夫曼编码。
用0来标注树的左分支,用1来标注树的右分支。
从树的根来读起,一直到每个分支元素,给出它们的赫夫曼编码。
上面的树的结果如下:
A-010,B-011,C-11,D-10和E-00.
这一问题的目的,低频率的树总是变为新树的左子树。
如果两棵树有相同的频率,那么哪棵都可以被选为左子树。
注意到前面几种概率分布,有几种有根据的赫夫曼编码。
相同的赫夫曼编码能够从不同的频率分布中获得:
变化范围在14%到13%和31%到32%,你也可以从相同的树中得到相同的编码。
Dan希望你能够写一个程序,用它来计算不同路径得到的给定赫夫曼编码的总数,即在哈夫曼树的形态确定的情况下,求出字符集所有可能的频率分布的数目,要求频率百分数的分子必须是整数。
假设所有的百分比都是确定的正整数。
注意到两个不同顺序的相同概率也是不一样的分布(例如30%70%和70%30%是不同的)。
输入:
输入一个测试数据的组合。
每个测试包含一个由正整数n开始的一组数,这些整数n是被压缩文件中不同的元素,还有它们的给定的赫夫曼编码的二元字符串。
你可以假设这些字符确实是一些概率分布的赫夫曼编码(虽然在我们的附加假设之下,仍然会有结果是0的情况,下面的一个简单例子中有此情况)。
最后一个测试结果包含了一个0.
输出:
对于每一个测试,输出一组包含测试数字(以1为开始的)以及求出字符集所有可能的频率分布的数目,要求频率百分数的分子必须是整数。
二、问题分析:
1.哈夫曼树是一种使用前缀编码进行数据压缩的方法,构造方法是每次选取频率最小的两个字符将其合并。
2.哈夫曼树构造时每次参与合并的数不小于任意一个先前参与合并的数。
3.哈夫曼树构造时每次合并产生的数大小不减。
三、概要设计:
存储结构:
哈夫曼树的结点存储结构为双亲孩子存储结构,并包含一个权值域和标志域flag。
双亲孩子存储结构采用仿真指针实现;flag=0时表示该结点尚未加入到哈夫曼树中,flag=1时表示该结点已加入到哈夫曼树中。
哈夫曼树的结点存储结构:
weightflagparentleftChildrightChild
哈夫曼编码的存储结构定义成一个包括存放0和1序列的数组、编码的起始下标和字符权值的存储结构。
存放哈夫曼编码的数组元素结构为:
MaxN
…Bit[start]Bit[0]Bit[1]…Bit[MaxBit-1]
存放哈夫曼编码
四、详细设计:
哈夫曼树的构造算法:
(1)由给定的n个权值{w1,w2,…,wn}构造n棵只有根结点的二叉树,从而得到一个二叉树森林F={T1,T2,…,Tn}。
(2)在二叉树森林F中选取根结点的权值最小和次小的两棵二叉树作为新的二叉树的左右子树构造新的二叉树,新的二叉树的根结点权值为左右子树根结点权值之和。
(3)在二叉树森林F中删除作为新二叉树左右子树的两棵二叉树,将新二叉树加入到二叉树森林F中。
(4)重复步骤
(2)和(3),当二叉树森林F中只剩下一棵二叉树时,这棵二叉树就是所构造的哈夫曼树。
哈夫曼编码的构造算法:
主函数算法:
五、调试分析:
1、哈夫曼树的构造过程:
2、哈夫曼树的结点选择过程:
3、调试结果如下:
六、结果分析:
1、各模块算法的时间复杂度:
哈夫曼树的构造函数:
O(n2)
哈夫曼编码的构造函数:
O(n2)
2、测试结果如下:
七、设计心得体会:
通过本次实验让我们深刻了解了哈夫曼编码中哈夫曼树的构造过程,并学会了更多关于C++的应用知识。
此外,通过这次课程设计,我们收获匪浅,首先由衷感谢老师提供这样一个锻炼自己的机会,感受到学来的知识不只是用来完成试卷的。
一向惯于独立思考的自己学会了积极的同同学、朋友交流,取长补短,共同进步。
课程设计使自己发现考试并不是最重要,最重要的是能运用所学的知识。
在整个课程设计的学习过程中,不再是用学到的知识解题,而是在实际运用时遇到什么学什么,重在把知识应用于实际。
八、参考文献:
[1]许薇,《面向对象的程序设计(C++描述)》,清华大学出版社,2009年。
[2]吴伟民,严蔚敏,《数据结构(C语言版)》,清华大学出版社,2009年。
[3]王晓东,《算法设计与分析(第2版)》,清华大学出版社,2008年。
九、附录(源代码):
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include"iostream.h"
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedefstruct
{
unsignedintweight;
unsignedintflag,parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码表
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
voidSelect(HuffmanTree&HT,inti,int&s1,int&s2)
{//在HT[1..i]中选择parent为0且weight最小的两个结点,
//其序号分别为s1和s2
intk;
for(k=1;k<=i;k++)
if(HT[k].parent==0)
{
s1=k;
break;
}
for(k=1;k<=i;k++)
{
if(HT[k].parent==0)
{
if(HT[s1].weight>HT[k].weight)
s1=k;
}
}
for(k=1;k<=i;k++)
if(HT[k].parent==0&&k!
=s1)
{
s2=k;
break;
}
for(k=1;k<=i;k++)
{
if(HT[k].parent==0&&k!
=s1)
{
if(HT[s2].weight>HT[k].weight)
s2=k;
}
}
}
voidHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,int*w,intn)
{//w存放n个字符的权值(均>0),构造哈夫曼树HT,
//并求出n个字符的哈夫曼编码HC
inti,j,m,s1,s2,start;
char*cd;
unsignedintc,f;
if(n<=1)return;
m=2*n-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用
for(i=1;i<=n;i++)//初始化
{
HT[i].weight=w[i-1];
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
HT[i].flag=0;
}
for(i=n+1;i<=m;i++)//初始化
{
HT[i].weight=0;
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
HT[i].flag=0;
}
//printf("\n哈夫曼树的构造过程如下所示:
\n");
//printf("HT初态:
\n结点weightflagparentlchildrchild");
//for(i=1;i<=m;i++)
/*printf("\n%4d%6d%8d%8d%8d%8d",i,HT[i].weight,HT[i].flag,HT[i].parent,HT[i].lchild,HT[i].rchild);
*/
for(i=n+1;i<=m;i++){//建哈夫曼树
Select(HT,i-1,s1,s2);
if(i==m)
HT[i].flag=1;
HT[s1].parent=i;
HT[s2].parent=i;
HT[s1].flag=HT[s2].flag=1;
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
//printf("\nselect:
s1=%ds2=%d\n",s1,s2);
//printf("结点weightflagparentlchildrchild");
//for(j=1;j<=i;j++)
/*printf("\n%4d%6d%8d%8d%8d%8d",j,HT[j].weight,HT[j].flag,HT[j].parent,HT[j].lchild,HT[j].rchild);
*/
}
cout< //---从叶子到根逆向求每个字符的哈夫曼编码--- 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));//为第i个字符编码分配空间 strcpy(HC[i],&c
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 霍夫曼树 算法课程设计 算法 课程设计