哈夫曼算法及其应用.docx

上传人:b****4 文档编号:12033491 上传时间:2023-04-16 格式:DOCX 页数:17 大小:133.50KB
下载 相关 举报
哈夫曼算法及其应用.docx_第1页
第1页 / 共17页
哈夫曼算法及其应用.docx_第2页
第2页 / 共17页
哈夫曼算法及其应用.docx_第3页
第3页 / 共17页
哈夫曼算法及其应用.docx_第4页
第4页 / 共17页
哈夫曼算法及其应用.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

哈夫曼算法及其应用.docx

《哈夫曼算法及其应用.docx》由会员分享,可在线阅读,更多相关《哈夫曼算法及其应用.docx(17页珍藏版)》请在冰豆网上搜索。

哈夫曼算法及其应用.docx

哈夫曼算法及其应用

 

哈夫曼算法及其应用

一、问题描述

给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。

哈夫曼编码是一种根据哈夫曼树对文件进行编码的方式。

哈夫曼编码是可变字长编码的一种。

本次课程设计是对一个已建文本文件,统计该文件中各字符频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成原文件。

压缩文件即读文件,统计文件中的字符个数,对文件进行哈夫曼编码和译码,并将编码译码后的字符存储在文件中。

二、基本要求

程序要求实现以下功能:

1.统计文本文件中各字符的出现次数(涉及读文件,统计字符个数);

2.对文件中的字符进行哈夫曼编码,并存储入字符编码文件;

3.根据字符编码文件对文本文件内容进行编码;

4.根据字符编码文件和已编码文件的内容进行译码;

5.能够输出原文、编码表、文本文件编码、译文。

3、测试数据

Initsmedicalliterature,theFoodandDrugAdministrationstatesthathotwatercomfortableenoughforwashinghandsisnothotenoughtokillbacteria,butismoreeffectivethancoldwaterbecauseitremovesoilsfromthehandthatcanharborbacteria.

四、算法思想

1、哈夫曼树建立算法:

1)根据给定的n个权值{W1,W2,W3……Wn}构成n棵二叉树的集合{T1,T2,……Tn},其中Ti中只有一个权值为Wi的根结点,左右子树均为空。

2)在F中选取两棵根结点的权值最小的树作为左、右子树一构造一棵新的二叉树,且置新的二叉树的根结点的权值为左、右子树上根结点的权值之和。

3)在F中删除这两棵中权值最小的树,同时将新得到的二叉树加入F中。

4)重复2)3)直到F中仅剩一棵树为止,这棵树就是哈夫曼树。

2、哈夫曼编码算法:

通过从哈夫曼树根结点开始,对左子树分配代码“1”,右子树分配代码“0”,一直到达叶子结点为止,然后将从树根沿每条路径到达叶子结点的代码排列起来,便得到了哈夫曼编码。

3、对文件字符编码算法:

逐一读取文件中字符,在哈夫曼编码表查找对应字符,读取其编码并写入文件,如此循环直至结束。

4、哈夫曼译码算法:

根据编码用的哈夫曼树,从根结点出发,逐个读入电文中的二进制码;若代码为“1”,则走左子树的根结点,否则走向右子树的根结点;一旦到达叶子结点,便译出代码所对应的字符。

然后又重新从根结点开始继续译码,直到二进制电文结束。

五、模块划分

1.VoidInitHT(HuffmanTT)

初始化Huffman树。

2.VoidSelectMin(HuffmanTT,intn,int&p1,int&p2)

找到权重最小的叶子。

3.VoidLoadHuffmanFile(HuffmanTT)

加载文件。

4.VoidCreatHT(HuffmanTT)

构造Huffman树。

5.VoidCharSetHuffmanEncoding(HuffmanTT,HuffmanCodeH)

根据Huffman树求Huffman编码表。

6.VoidEncodingHuffmanT(HuffmanTT,HuffmanCodeH)

对文件编码。

7.VoidDecdingHuffmanT(HuffmanTT,HuffmanCodeH)

根据Huffman编码、译码。

8.VoidPrintHuffmanT(HuffmanTT)

打印Huffman权重表。

9.VoidPrintHuffmanH(HuffmanTT,HuffmanCodeH)

打印Huffman编码表。

10.VoidMainMenue()

主菜单。

提供相关的操作提示。

11.Intmain()

主函数。

用个while循环和switch选择结构进行进行循环交互性操作。

六、数据结构//(ADT)

1、哈夫曼树的存储结构:

typedefstruct{

charch;//字符

intweight;//字符权重

intlchild;//左子

intrchild;//右子

intparent;//双亲

}THNODE;

2、哈夫曼编码表的存储结构:

typedefstruct{

charch;//存储字符

charbits[MAX_C+1];//字符编码位串

}CodeNode;

七、源程序

//Huffman.cpp源代码如下:

#include

#include

#include

#defineMAX_C256//定义最大字符数

#defineMAX_N512//定义最大Huffman节点个数

#defineN50

/*HuffmanTree结构*/

typedefstruct

{charch;//字符

intweight;//字符权重

intlchild;//左子

intrchild;//右子

intparent;//双亲

}THNODE;

typedefTHNODEHuffmanT[MAX_N];

/******Huffman编码表结构*****/

typedefstruct

{charch;//存储字符

charbits[MAX_C+1];//字符编码位串

}CodeNode;

typedefCodeNodeHuffmanCode[MAX_C];

HuffmanCodeH;

/*********全局变量**********/

intn;//指示待编译文件的字长

charfilename[20];

/*初始化Huffman树*/

voidInitHT(HuffmanTT)

{inti;

for(i=0;i

{T[i].ch='\0';

T[i].weight=0;

T[i].lchild=-1;

T[i].rchild=-1;

T[i].parent=-1;

}

}

/*找到权重最小的叶子*/

voidSelectMin(HuffmanTT,intn,int&p1,int&p2)

{inti;

intj;

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

{

if(T[i].parent==-1&&T[i].weight>0)

{

p1=i;

break;

}

}

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

{

if(T[j].parent==-1&&T[j].weight>0)

{

p2=j;

break;

}

}

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

{

if((T[p1].weight>T[i].weight)&&(T[i].parent==-1)&&(p2!

=i)&&(T[i].weight>0))

p1=i;

}

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

{

if((T[p2].weight>T[j].weight)&&(T[j].parent==-1)&&(p1!

=j)&&(T[j].weight>0))

p2=j;

}

}

/*******加载文件*******/

voidLoadHuffmanFile(HuffmanTT)

{unsignedinti;

intj=0;

charc;

inta[MAX_C];

FILE*fp;

printf("Inputfilename:

");

scanf("%s",filename);

if((fp=fopen(filename,"rb"))==NULL)

{printf("Can'topen%s\n",filename);

exit(0);

}

for(i=0;i

a[i]=0;

fseek(fp,0,SEEK_SET);

while

(1)//(!

feof(fp))

{

fread(&c,sizeof(unsignedchar),1,fp);

if(feof(fp))break;

a[(unsignedint)c]++;

}

fclose(fp);

/*统计输入文件的字符及其权重并存放到树T[]*/

for(i=0;i

{

if(a[i]!

=0)

{

T[j].ch=(unsignedchar)i;

T[j++].weight=(unsignedint)a[i];

}

}

n=j;

}

/*******构造huffam树,T[2*n-1]为其根********/

voidCreatHT(HuffmanTT)

{

inti,p1,p2;

LoadHuffmanFile(T);//加载被编码文件

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

{SelectMin(T,i-1,p1,p2);

T[p1].parent=T[p2].parent=i;

T[i].lchild=p1;

T[i].rchild=p2;

T[i].weight=T[p1].weight+T[p2].weight;

}

}

/*根据HuffmanT求Huffman编码表H*/

voidCharSetHuffmanEncoding(HuffmanTT,HuffmanCodeH)

{intc;//指示T中孩子的位置

intp;//指示T中双亲的位置

inti;

intstart;//指示编码在cd中的位置

charcd[N];//临时存放编码

for(i=0;i

{H[i].ch=T[i].ch;//读入叶子T[i]对应的字符

if(i==0||i==1)start=n;

elsestart=n-i+1;

cd[--start]='\0';//编码起始位置的初值

c=i;//从叶子T[i]开始回溯

while((p=T[c].parent)>=0)//直到回溯到T[c]是树根位置

{cd[--start]=(T[p].lchild==c)?

'0':

'1';

c=p;}

strcpy(H[i].bits,&cd[start]);//复制临时编码到编码表中

}

}

/*对文件编码,将结果保存到codefile.txt中*/

voidEncodingHuffmanT(HuffmanTT,HuffmanCodeH)

{charc;

FILE*in,*fp;

intj,l;

charencodefile[20],temp[MAX_C];

if((in=fopen(filename,"rb"))==NULL)

{printf("Read%sfail!

\n",encodefile);

exit

(1);}

CharSetHuffmanEncoding(T,H);

printf("Inputencodefilename:

");

gets(encodefile);

if((fp=fopen(encodefile,"wb"))==NULL)

{printf("Write%sfail!

\n",encodefile);

exit

(1);}

fread(&c,sizeof(unsignedchar),1,in);

fwrite(&c,sizeof(unsignedchar),1,fp);

fseek(in,0,SEEK_SET);

fseek(fp,0,SEEK_SET);

while

(1)//(!

feof(in))

{fread(&c,sizeof(unsignedchar),1,in);

if(feof(in))break;

for(j=0;j

{if(c==H[j].ch)

{l=0;

while(H[j].bits[l]!

='\0')

{temp[l]=H[j].bits[l];

l++;}

intm=0;

while(l--)

{fwrite(&temp[m++],sizeof(unsignedchar),1,fp);}

}

}

}

fclose(fp);

printf("Encodingfilehassavedinto%s!

\n",encodefile);

}

/*根据Huffman编码、译码*/

voidDecodingHuffmanT(HuffmanTT,HuffmanCodeH)

{inti;//指示Huffmantree叶子个数

FILE*fp,*fp1;

charch,ch1[20],ch2[20];

printf("Inputencodefilename:

");

scanf("%s",ch1);

printf("Inputdecodefilename:

");

scanf("%s",ch2);

fp=fopen(ch1,"rb");

fp1=fopen(ch2,"wb");

//根据Huffman树对Huffman编码译码

i=2*n-2;

fseek(fp,0L,SEEK_SET);

fseek(fp1,0L,SEEK_SET);

while(!

feof(fp))

{fread(&ch,sizeof(unsignedchar),1,fp);

if(ch=='0')//若编码为o,则找此结点的左子树;

i=T[i].lchild;

if(ch=='1')//若编码为1,则找此结点的右子树;

i=T[i].rchild;

if(i

{fwrite(&T[i].ch,sizeof(unsignedchar),1,fp1);

i=2*n-2;

}

}

fclose(fp);

fclose(fp1);

printf("Decodingaccomplished!

\nTheresulthassaveinput%s.\n",ch2);

getchar();

}

/*打印Huffman权重表*/

voidPrintHuffmanT(HuffmanTT)

{inti;

FILE*fp;

if((fp=fopen("treeprint.txt","wb"))==NULL)

{printf("Opentreeprint.txtfail!

\n");

exit

(1);

}

printf("\nLeaf&weightoftheHuffmantreeisbelow:

\n");

for(i=0;i

{if(i%5==0&&i>0)

printf("\n");

if(T[i].weight>0)

{fprintf(fp,"%c:

%d",T[i].ch,T[i].weight);

printf("%c:

%d",T[i].ch,T[i].weight);

}

}

fclose(fp);

printf("\nLeaf&weightoftheHuffmantreesavedintreeprint.txt\n\n");

}

/*打印Huffman编码表*/

voidPrintHuffmanH(HuffmanTT,HuffmanCodeH)

{inti;

FILE*fp;

CharSetHuffmanEncoding(T,H);

if((fp=fopen("codeprint.txt","wb"))==NULL)

{printf("Opencodeprint.txtfail!

\n");

exit

(1);

}

for(i=0;i

{if(i%10==0&&i>0)printf("\n");

printf("%c:

%s\n",T[i].ch,H[i].bits);

fprintf(fp,"%c:

%s",T[i].ch,H[i].bits);

}

fclose(fp);

printf("\nHuffmantreecodesavedincodeprint.txt!

\n\n");

}

/*主菜单*/

voidMainMenue()

{fflush(stdin);

printf("\n**********************MainMenue**************************\n");

printf("****\n");

printf("**1.Loadtobedealtfile.**\n");

printf("**2.ShowHuffmancodelist.**\n");

printf("**3.ShowHuffmanweightlist.**\n");

printf("**4.EncodingHuffmanfile.**\n");

printf("**5.DecodingHuffmanfile.**\n");

printf("**6.Exit.**\n");

printf("****\n");

printf("************************************************************\n");

}

/*主函数开始*/

intmain()

{

intflag=1;

charch[10];

HuffmanTT;//定义Huffman树

HuffmanCodeH;//定义Huffman编码表

InitHT(T);//初始化Huffman树

while(flag)

{MainMenue();

printf("Pleaseinputyourchoice(1~6):

");

gets(ch);

switch(ch[0])

{

case'1':

CreatHT(T);break;

case'2':

PrintHuffmanH(T,H);break;

case'3':

PrintHuffmanT(T);break;

case'4':

EncodingHuffmanT(T,H);break;

case'5':

DecodingHuffmanT(T,H);break;

case'6':

exit

(1);

default:

printf("Inputerror!

\n");break;

}

}

return0;

}

八、测试情况

程序的测试结果如下:

建立哈夫曼树、打印编码表正确。

打印权重表正确。

哈夫曼编码正确。

哈夫曼译码正确,退出正确。

九、参考文献

1、严蔚敏,《数据结构C语言》,清华大学出版社。

2、谭浩强,《c语言程序设计》,清华大学出版社。

小结

课程设计是《数据结构》课程教学必不可缺的一个重要环节,是培养学生综合运用所学知识,发现、提出、分析和解决实际问题,锻炼实践能力的重要环节。

同时可加深学生对该课程所学内容的进一步的理解与巩固,是将计算机课程与实际问题相联接的关键步骤。

通过课程设计,能够提高分析问题、解决问题,从而运用所学知识解决实际问题的能力。

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

当求解一个算法时,不是拿到问题就不加思索地做,而是首先要先对它有个大概的了解,接着再详细地分析每一步怎么做,无论自己以前是否有处理过相似的问题,只要按照以上的步骤,必定会顺利地做出来。

这次课程设计是我们大三来做的第一次了,我在编辑中犯了不应有的错误,如设计统计字符和合并时忘记应该怎样保存保存数据,在其他同学的帮助下明确并改正了错误和疏漏,使我们的程序有了更高的质量。

在设计过程中逐渐积累了一些基本的经验,所以做到后来逐渐顺利,但也还是会遇到一些这样或那样的问题,通过本次课程设计,进一步适应团队合作开发规模稍大的程序,体会个人开发与团队开发的利弊,加强团队协作与团队内的沟通,表达能力。

感受对本专业说学习的多门课程知识进行综合应用,将多门课程的知识融合贯通。

同时通过这次设计也获得一些编程经验:

编程时要认真,出现错误要及时找出并改正,遇到问题要去查相关的资料。

反复的调试程序,把各个注意的问题要想到;同时要形成自己的调试程序的风格,从每个细节出发,不放过每个知识点。

另外,要注意符号的使用。

本次课程设计虽然实现了哈夫曼编码/译码等要求,但由于时间等各方面原因,仍有一些问题没有解决,例如一些要求输入判断时判断不严格、操作界面不够美观等,总体上还有待改进。

1)

2)

3)

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

当前位置:首页 > 表格模板 > 调查报告

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1