数据结构哈夫曼编码.docx

上传人:b****4 文档编号:6210351 上传时间:2023-05-09 格式:DOCX 页数:21 大小:83.13KB
下载 相关 举报
数据结构哈夫曼编码.docx_第1页
第1页 / 共21页
数据结构哈夫曼编码.docx_第2页
第2页 / 共21页
数据结构哈夫曼编码.docx_第3页
第3页 / 共21页
数据结构哈夫曼编码.docx_第4页
第4页 / 共21页
数据结构哈夫曼编码.docx_第5页
第5页 / 共21页
数据结构哈夫曼编码.docx_第6页
第6页 / 共21页
数据结构哈夫曼编码.docx_第7页
第7页 / 共21页
数据结构哈夫曼编码.docx_第8页
第8页 / 共21页
数据结构哈夫曼编码.docx_第9页
第9页 / 共21页
数据结构哈夫曼编码.docx_第10页
第10页 / 共21页
数据结构哈夫曼编码.docx_第11页
第11页 / 共21页
数据结构哈夫曼编码.docx_第12页
第12页 / 共21页
数据结构哈夫曼编码.docx_第13页
第13页 / 共21页
数据结构哈夫曼编码.docx_第14页
第14页 / 共21页
数据结构哈夫曼编码.docx_第15页
第15页 / 共21页
数据结构哈夫曼编码.docx_第16页
第16页 / 共21页
数据结构哈夫曼编码.docx_第17页
第17页 / 共21页
数据结构哈夫曼编码.docx_第18页
第18页 / 共21页
数据结构哈夫曼编码.docx_第19页
第19页 / 共21页
数据结构哈夫曼编码.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

数据结构哈夫曼编码.docx

《数据结构哈夫曼编码.docx》由会员分享,可在线阅读,更多相关《数据结构哈夫曼编码.docx(21页珍藏版)》请在冰点文库上搜索。

数据结构哈夫曼编码.docx

数据结构哈夫曼编码

摘要利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。

这要求在发送端通过一个编码系统对待传输数据预先编码,在接收端将传来的数据进行译码(复原),将所得结果存储到已开辟空间中。

试为这样的信息收发站编写一个哈夫曼码的编/译码系统。

本程序可以对任何大小的字符型文件进行Huffman编码,生成一个编码文件。

并可以在程序运行结束后的任意时间对它解码还原生成字符文件。

即:

先对一条电文进行输入,并实现Huffman编码,然后对Huffman编码生成的代码串进行译码,最后输出电文数字

AbstractUsehoffmanncodewascommunicationcanimprovetheutilizationrateofchannel,shortentheinformationtransmissiontime,reducethetransmissioncost.Thisrequirementinthesendingendthroughacodingsysteminadvancetotransmitdatacoding,inthereceiverwillspreadofthedatadecoding(restoration),willtheresultsofopenspacetostorealready.Tryforsuchinformationsendingandreceivingstationwriteahoffmannyardsofmakeup/decodingsystem.ThisprogramcanonanyofthesizeofthefiletypecharacterHuffmancoding,generatesacodefiles.Andcantherunningoftheapplicationatanytimeaftertheendofthereductionofdecodingitgeneratedcharacterfiles.Namely:

firsttoamessageforinput,andrealizetheHuffmancoding,andthentoHuffmancodinggeneratedcodestringdecode,finallydigitaloutputmessage

关键字哈夫曼编码;哈夫曼译码

KeywordsHoffmanncode;Hoffmanndecode

1设计要求

对输入的一串电文字符实现哈夫曼编码,输出电文字符串。

通常我们把数据压缩的过程称为编码。

电报通信是传递文字的二进制码形式的字符串。

但在信息传递时,总希望总长度能尽可能短,即采用最短码。

假设每种字符在电文中出现的次数为Wi,编码长度为Li,电文中有n种字符,则电文编码总长度为∑WiLi。

若将此对应到二叉树上,Wi为叶结点的权,Li为根结点到叶结点的路径长度。

那么,∑WiLi恰好为二叉树上带权路径长度。

因此,设计电文总长最短的二进制前缀编码,就是以n种字符出现的频率作权,构造一棵哈夫曼树,此构造过程称为哈夫曼编码。

设计实现的功能:

(1)哈夫曼树的建立;

(2)哈夫曼编码的生成;(3)对编码文件的译码。

2系统结构图(功能模块图)

图2-1哈夫曼结构图

3详细设计

3.1哈夫曼树的建立

3.1.1哈夫曼树的存储结构描述为:

#defineN50//叶子结点数

#defineM2*N-1//哈夫曼树中结点总数

typedefstruct{

intweight;//叶子结点的权值

intlchild,rchild,parent;//左右孩子及双亲指针

}HTNode;//树中结点类型

typedefHTNodeHuffmanTree[M+1];

3.1.2哈夫曼树的算法:

voidCreateHT(HTNodeht[],intn)//调用输入的数组ht[]和节点数n

{

inti,k,lnode,rnode;

intmin1,min2;

for(i=0;i<2*n-1;i++)

ht[i].parent=ht[i].lchild=ht[i].rchild=-1;//所有结点的相关域置初值-1

for(i=n;i<2*n-1;i++)//构造哈夫曼树

{

min1=min2=32767;//int的范围是-32768—32767

lnode=rnode=-1;//lnode和rnode记录最小权值的两个结点位置

for(k=0;k<=i-1;k++)

{

if(ht[k].parent==-1)//只在尚未构造二叉树的结点中查找

{

if(ht[k].weight

{

min2=min1;rnode=lnode;

min1=ht[k].weight;lnode=k;

}

elseif(ht[k].weight

{

min2=ht[k].weight;rnode=k;

}

}

}

ht[lnode].parent=i;ht[rnode].parent=i;//两个最小节点的父节点是i

ht[i].weight=ht[lnode].weight+ht[rnode].weight;//两个最小节点的父节点权值为两个最小节点权值之和

ht[i].lchild=lnode;ht[i].rchild=rnode;//父节点的左节点和右节点

}

}

3.2哈夫曼编码

voidCreateHCode(HTNodeht[],HCodehcd[],intn)

{

inti,f,c;

HCodehc;

for(i=0;i

{

hc.start=n;c=i;

f=ht[i].parent;

while(f!

=-1)//循序直到树根结点结束循环

{

if(ht[f].lchild==c)//处理左孩子结点

hc.cd[hc.start--]='0';

else//处理右孩子结点

hc.cd[hc.start--]='1';

c=f;f=ht[f].parent;

}

hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符

hcd[i]=hc;

}

}

voidDispHCode(HTNodeht[],HCodehcd[],intn)//输出哈夫曼编码的列表

{

inti,k;

printf("输出哈夫曼编码:

\n");

for(i=0;i

{

printf("%c:

\t",ht[i].data);

for(k=hcd[i].start;k<=n;k++)//输出所有data中数据的编码

{

printf("%c",hcd[i].cd[k]);

}

printf("\n");

}

}

voideditHCode(HTNodeht[],HCodehcd[],intn)//编码函数

{

charstring[MAXSIZE];

inti,j,k;

scanf("%s",string);//把要进行编码的字符串存入string数组中

printf("\n输出编码结果:

\n");

for(i=0;string[i]!

='#';i++)//#为终止标志

{

for(j=0;j

{

if(string[i]==ht[j].data)//循环查找与输入字符相同的编号,相同的就输出这个字符的编码

{

for(k=hcd[j].start;k<=n;k++)

{

printf("%c",hcd[j].cd[k]);

}

break;//输出完成后跳出当前for循环

}

}

}

}

3.3哈夫曼译码

voiddeHCode(HTNodeht[],HCodehcd[],intn)//译码函数

{

charcode[MAXSIZE];

inti,j,l,k,m,x;

scanf("%s",code);//把要进行译码的字符串存入code数组中

while(code[0]!

='#')

for(i=0;i

{

m=0;//m为想同编码个数的计数器

for(k=hcd[i].start,j=0;k<=n;k++,j++)//j为记录所存储这个字符的编码个数

{

if(code[j]==hcd[i].cd[k])//当有相同编码时m值加1

m++;

}

if(m==j)//当输入的字符串与所存储的编码字符串个数相等时则输出这个的data数据

{

printf("%c",ht[i].data);

for(x=0;code[x-1]!

='#';x++)//把已经使用过的code数组里的字符串删除

{

code[x]=code[x+j];

}

}

}

}

3.4主函数

voidmain()

{

intn=26,i;

charorz,back,flag=1;

charstr[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//初始化

intfnum[]={186,64,13,22,32,103,21,15,47,57,1,2,32,20,57,63,15,1,48,51,80,23,8,18,1,16};//初始化

HTNodeht[M];//建立结构体

HCodehcd[N];//建立结构体

for(i=0;i

{

ht[i].data=str[i];

ht[i].weight=fnum[i];

}

while(flag)//菜单函数,当flag为0时跳出循环

3.5显示部分源程序:

{

printf("\n");

printf("********************************");

printf("\n**1---------------显示编码**");

printf("\n**2---------------进行编码**");

printf("\n**3---------------进行译码**");

printf("\n**4---------------退出**\n");

printf("***********************************");

printf("\n");

printf("请输入选择的编号:

");

scanf("%c",&orz);

switch(orz)

{

case'a':

case'A':

system("cls");//清屏函数

CreateHT(ht,n);

CreateHCode(ht,hcd,n);

DispHCode(ht,hcd,n);

printf("\n按任意键返回...");

getch();

system("cls");

break;

case'b':

case'B':

system("cls");

printf("请输入要进行编码的字符串(以#结束):

\n");

editHCode(ht,hcd,n);

printf("\n按任意键返回...");

getch();

system("cls");

break;

case'c':

case'C':

system("cls");

DispHCode(ht,hcd,n);

printf("请输入编码(以#结束):

\n");

deHCode(ht,hcd,n);

printf("\n按任意键返回...");

getch();

system("cls");

break;

case'd':

case'D':

flag=0;

break;

default:

system("cls");

}

}

}

4程序运行结果

进入主菜单

图4-1

选A时的显示结果

图4-2

选B时的显示结果

图4-3

选C时的显示结果

图4-4

5心得体会

通过这次课程设计,我们学习了很多在上课没懂的知识,并对求哈夫曼树及哈夫曼编码/译码的算法有了更加深刻的了解,更巩固了课堂中学习有关于哈夫曼编码的知识,真正学会一种算法了。

我们认识到根据不同的需求,采用不同的数据存储方式,不一定要用栈,二叉树等高级类型,有时用基本的一维数组,只要运用得当,也能达到相同的效果,甚至更佳,就如这次的课程设计,通过用for的多重循环,舍弃多余的循环,提高了程序的运行效率。

这次课程设计,我们在编辑中犯了不应有的错误,设计统计字符和合并时忘记应该怎样保存数据,对文件的操作也很生疏。

在不断分析后明确并改正了错误和疏漏,我们的程序有了更高的质量。

另外,互帮互助让我们的程序设计更加完善。

参考文献

[1]徐孝凯编著,《数据结构课程实验》,清华大学出版2002年第一版

[2]张乃笑编著,《数据结构与算法》,电子工业出版社2004年10月

[3]严蔚敏《数据结构》(C语言版)清华大学出版社

[4]李春葆《数据结构(C语言篇)—习题与解析》(修订版)清华大学出版2002年4月第一版

附录

源程序如下:

#include

#include//要用system函数要调用的头文件

#include//用getch()要调用的头文件

#include

#defineN50//义用N表示50叶节点数

#defineM2*N-1//用M表示节点总数当叶节点数位n时总节点数为2n-1

#defineMAXSIZE100

typedefstruct

{

chardata;//结点值

intweight;//权值

intparent;//双亲结点

intlchild;//左孩子结点

intrchild;//右孩子结点

}HTNode;

typedefstruct

{

charcd[N];//存放哈夫曼码

intstart;//从start开始读cd中的哈夫曼码

}HCode;

voidCreateHT(HTNodeht[],intn)//调用输入的数组ht[],和节点数n

{

inti,k,lnode,rnode;

intmin1,min2;

for(i=0;i<2*n-1;i++)

ht[i].parent=ht[i].lchild=ht[i].rchild=-1;//所有结点的相关域置初值-1

for(i=n;i<2*n-1;i++)//构造哈夫曼树

{

min1=min2=32767;//int的范围是-32768—32767

lnode=rnode=-1;//lnode和rnode记录最小权值的两个结点位置

for(k=0;k<=i-1;k++)

{

if(ht[k].parent==-1)//只在尚未构造二叉树的结点中查找

{

if(ht[k].weight

{

min2=min1;rnode=lnode;

min1=ht[k].weight;lnode=k;

}

elseif(ht[k].weight

{

min2=ht[k].weight;rnode=k;

}

}

}

ht[lnode].parent=i;ht[rnode].parent=i;//两个最小节点的父节点是i

ht[i].weight=ht[lnode].weight+ht[rnode].weight;//两个最小节点的父节点权值为两个最小节点权值之和

ht[i].lchild=lnode;ht[i].rchild=rnode;//父节点的左节点和右节点

}

}

voidCreateHCode(HTNodeht[],HCodehcd[],intn)

{

inti,f,c;

HCodehc;

for(i=0;i

{

hc.start=n;c=i;

f=ht[i].parent;

while(f!

=-1)//循序直到树根结点结束循环

{

if(ht[f].lchild==c)//处理左孩子结点

hc.cd[hc.start--]='0';

else//处理右孩子结点

hc.cd[hc.start--]='1';

c=f;f=ht[f].parent;

}

hc.start++;//start指向哈夫曼编码hc.cd[]中最开始字符

hcd[i]=hc;

}

}

voidDispHCode(HTNodeht[],HCodehcd[],intn)//输出哈夫曼编码的列表

{

inti,k;

printf("输出哈夫曼编码:

\n");

for(i=0;i

{

printf("%c:

\t",ht[i].data);

for(k=hcd[i].start;k<=n;k++)//输出所有data中数据的编码

{

printf("%c",hcd[i].cd[k]);

}

printf("\n");

}

}

voideditHCode(HTNodeht[],HCodehcd[],intn)//编码函数

{

charstring[MAXSIZE];

inti,j,k;

scanf("%s",string);//把要进行编码的字符串存入string数组中

printf("\n输出编码结果:

\n");

for(i=0;string[i]!

='#';i++)//#为终止标志

{

for(j=0;j

{

if(string[i]==ht[j].data)//循环查找与输入字符相同的编号,相同的就输出这个字符的编码

{

for(k=hcd[j].start;k<=n;k++)

{

printf("%c",hcd[j].cd[k]);

}

break;//输出完成后跳出当前for循环

}

}

}

}

voiddeHCode(HTNodeht[],HCodehcd[],intn)//译码函数

{

charcode[MAXSIZE];

inti,j,l,k,m,x;

scanf("%s",code);//把要进行译码的字符串存入code数组中

while(code[0]!

='#')

for(i=0;i

{

m=0;//m为想同编码个数的计数器

for(k=hcd[i].start,j=0;k<=n;k++,j++)//j为记录所存储这个字符的编码个数

{

if(code[j]==hcd[i].cd[k])//当有相同编码时m值加1

m++;

}

if(m==j)//当输入的字符串与所存储的编码字符串个数相等时则输出这个的data数据

{

printf("%c",ht[i].data);

for(x=0;code[x-1]!

='#';x++)//把已经使用过的code数组里的字符串删除

{

code[x]=code[x+j];

}

}

}

}

voidmain()

{

intn=26,i;

charorz,back,flag=1;

charstr[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//初始化

intfnum[]={186,64,13,22,32,103,21,15,47,57,1,2,32,20,57,63,15,1,48,51,80,23,8,18,1,16};//初始化

HTNodeht[M];//建立结构体

HCodehcd[N];//建立结构体

for(i=0;i

{

ht[i].data=str[i];

ht[i].weight=fnum[i];

}

while(flag)//菜单函数,当flag为0时跳出循环

{

printf("\n");

printf("**************************************");

printf("\n**A---------------显示编码**");

printf("\n**B---------------进行编码**");

printf("\n**C---------------进行译码**");

printf("\n**D---------------退出**\n");

printf("****************************************");

printf("\n");

printf("请输入选择的编号:

");

scanf("%c",&orz);

switch(orz)

{

case'a':

case'A':

system("cls");//清屏函数

CreateHT(ht,n);

CreateHCode(ht,hcd,n);

DispHCode

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2