哈夫曼树程序设计.docx
- 文档编号:30377944
- 上传时间:2023-08-14
- 格式:DOCX
- 页数:25
- 大小:77.83KB
哈夫曼树程序设计.docx
《哈夫曼树程序设计.docx》由会员分享,可在线阅读,更多相关《哈夫曼树程序设计.docx(25页珍藏版)》请在冰豆网上搜索。
哈夫曼树程序设计
课程设计报告
(2012--2013年度第2学期)
实验名称:
数据结构与算法
题目:
电报压缩/解压缩系统
院系:
--------------------------
班级:
-------------------
学号:
----------------
学生姓名:
-------
指导教师:
--------
设计周数:
1周
成绩:
日期:
2013年7月11日
一、课程设计的目的与要求
1.目的:
应用数据结构和算法来设计相应的程序,培养学生问题求解模块的框架设计和详细设计、相关程序实现和调试能力,完成创新能力和实践能力的训练。
2.要求:
用高级程序设计语言C编码,用VC++开发平台调试
二、设计正文
(一)课程设计题目
电报压缩/解压缩系统
(二)需求分析
(1)报文中含有中英文字符;
(2)原始报文、压缩报文和解压报文都采用文件存储;
(三)概要设计
本程序包含9个函数:
①主函数main();
②菜单函数menu();
③初始化链表函数initDLink();
④查找及插入新的数据函数search();
⑤数据处理及统计函数settle();
⑥求哈夫曼编码函数huf_code();
⑦创建哈夫曼树函数creatHufTree();
⑧压缩函数compress();
⑨解压函数uncompress();
各函数间关系如下:
(四)详细设计
(1)系统功能结构框图
(2)数据类型定义
1)typedefstructdataNode
{
charc[3];//用来存储每个汉字字符或英文字符
intweight;//用来存储出现的权值
structdataNode*next;//指向下一个的指针
}DNode,*DLink;//结点类型和指针类型
2)typedefstructhufm
{
chardata[3];//用来存储汉字字符或者英文字符
intweight;//用来存储字符出现的权值
intparent,lch,rch;//父亲节点及左孩子右孩子
}NodeHufm,*HufTree;//哈夫曼树类型及其指针类型
3)typedefstructHCodeNode
{
charbits[26];//用来存储哈夫曼编码
}HCodeNode,*HufCode;//哈夫曼编码类型及其指针类型
(3)基本操作
1)intmenu();
功能:
清空界面,显示选择操作界面;
参数:
无。
2)intinitDLink(DLink&D);
功能:
初始化链表,采用带头结点的;
参数:
D:
为带头结点的链表的头指针。
3)intsearch(chare[],DLink&D,int&n);
功能:
查找是否存在传进来的字符串,若果有权值加1如果没有创建并使权值初值为1;
参数:
e:
为要查找的字符串首地址,D:
为链表的头指针;n:
链表上节点的个数也就是字符的个数。
统计n的大小是为以后算法实现打基础
4)intsettle(FILE*ifp,DLink&D,int&flength,int&n);
功能:
从文件中读取数据,统计字符种类及其出现的权值并完成文本大小及字符个数的统计;
参数:
ifp:
读入的文件指针;D:
链表的头指针;flength:
文件的大小;n:
字符的个数。
函数调用search函数统计出n,此函数中统计出flength,下面的算法需要n与flength,而在此函数中可以顺便得到它们。
5)voidhuf_code(HufCode&hcd,HufTreeht,intn);
功能:
根据传进来的哈夫曼树及字符个数求出对应的哈夫曼编码;
参数:
hcd:
动态申请空间存储哈夫曼编码的数组名,每一个元素为字符串数据类型;ht:
动态申请空间存储哈夫曼树的数组名,每个元素为一个结构体数据类型,元素包括数据,权值,父亲左孩子及右孩子;n:
字符个数。
根据是左孩子为0右孩子为1的规定得到哈夫曼编码。
6)voidcreatHufTree(HufTree&ht,FILE*ifp,int&n,int&flength);
功能:
通过从文件中读取信息创建哈夫曼树,并给调用它的函数统计出n与flength;
参数:
ht:
存储了哈夫曼树的信息。
Ifp:
为文件指针,从那里面得到数据进行统计来创建哈夫曼树。
n为字符个数,flength为文件大小。
7)intcompress(FILE*ifp,FILE*ofp)
功能:
传进来读取的文件指针以及压缩后保存文件的文件指针,对源文件进行压缩。
参数:
ifp:
要压缩的文件指针;ofp:
压缩后要保存的文件指针。
8)intuncompress(FILE*ifp,FILE*ofp);
功能:
将ifp所指向的文件进行解压,然后保存到ofp所指向的文件中。
参数:
ifp:
要解压的文件指针;ofp:
解压后后要保存的文件指针。
(五)测试结果
1.选择1,输入要压缩的文件名及压缩后要保存的文件名进行压缩
图1:
输入要压缩的文件名及压缩后要保存的文件名
2.选择2,进行解压文件。
输入要解压的文件名和解压后保存的文件名,进行解压
图2:
输入要解压的文件名和解压后保存的文件名
三、课程设计总结或结论
1.完成的工作:
(1)输入要压缩的文件名及压缩后要保存的文件名实现了压缩。
(2)输入要解压的文件名及解压后要保存的文件名实现了解压。
(3)压缩率介于百分之四十到五十之间,解压采用复原哈夫曼树的方法能够快速实现解压
2.未完成的工作:
无
3.所需做的改进:
寻找更好的压缩算法实现压缩进一步提升。
四、参考文献
五、代码
#include
#include
#include
#include
typedefstructdataNode
{
charc[3];
intweight;
structdataNode*next;
}DNode,*DLink;
typedefstructhufm
{
chardata[3];
intweight;
intparent,lch,rch;
}NodeHufm,*HufTree;
typedefstructHCodeNode
{
charbits[26];
}HCodeNode,*HufCode;
/*对初始文件进行统计,分析*/
intinitDLink(DLink&D)
{
DLinkp=newDNode;
if(p==NULL)return0;
p->next=NULL;
D=p;
return1;
}
intsearch(chare[],DLink&D,int&n)
{
DLinkp=D->next;
while(p)
{
if(strcmp(p->c,e)==0)
{
p->weight++;
return1;
}
p=p->next;
}
p=newDNode;
if(p==NULL)return0;
n++;
strcpy(p->c,e);
p->weight=1;
p->next=D->next;
D->next=p;
return1;
}
intsettle(FILE*ifp,DLink&D,int&flength,int&n)
{
DLinkp;
inte;
unsignedcharc;
chardata[3];
data[2]=0;//赋予结束标志
flength=0;
initDLink(D);
fread(&c,1,1,ifp);//读取文件时注意,先读取一个,完成后再读取一个,避免eof假出,从而不会多读
flength++;
while(!
feof(ifp))
{
e=(int)c;
if(e>127)
{
data[0]=c;
fread(&c,1,1,ifp);
data[1]=c;
flength++;
}
else
{
data[0]=c;
data[1]=0;
}
search(data,D,n);
fread(&c,1,1,ifp);
flength++;
}
flength--;//计算文件的字节长度
/*flength--原因是因为到最后时,文件不能读取返回-1,此时flength又++*/
return1;
}
voidhuf_code(HufCode&hcd,HufTreeht,intn)//n是用来控制循环次数,求出每个节点编码
{
inti;
intindex,t;
char*code=newchar[26];
intc_parent;
for(i=0;i { code[25]='\0'; index=24; t=i; c_parent=ht[i].parent; while(c_parent! =-1) { if(ht[c_parent].lch==t) code[index]='0'; else code[index]='1'; index--; t=c_parent; c_parent=ht[c_parent].parent; } strcpy(hcd[i].bits,&code[index+1]); } } voidcreatHufTree(HufTree&ht,FILE*ifp,int&n,int&flength)//此处n为节点数 { DLinkD,p; inti,j,s; ints1,s2; longMIN1,MIN2; /*创建之前,进行文件数据的整理*/ settle(ifp,D,flength,n); /*有了n之后对哈夫曼树进行申请空间*/ ht=newNodeHufm[2*n-1]; /*对哈夫曼树进行初始数据*/ for(i=0;i<2*n-1;i++) { ht[i].lch=ht[i].rch=ht[i].parent=-1; ht[i].weight=0; } p=D->next; i=0; while(p) { strcpy(ht[i].data,p->c); ht[i].weight=p->weight; p=p->next; i++; } //找两个最小的 for(i=n;i<2*n-1;i++) { MIN1=10000000;MIN2=10000000; s1=s2=1000000; for(j=0;j { //ht[j].parent==-1找最小的 if(ht[j].parent! =-1)continue;//选完后的点parent不为-1 if(MIN2>ht[j].weight) { MIN1=MIN2; s1=s2; MIN2=ht[j].weight; s2=j; continue; } else if(ht[j].weight { MIN1=ht[j].weight; s1=j; } } //建立新的节点,从n(下标)开始 ht[i].weight=ht[s1].weight+ht[s2].weight; ht[i].lch=s1;ht[i].rch=s2; ht[s1].parent=i; ht[s2].parent=i; } } intcompress(FILE*ifp,FILE*ofp) { HufTreeht; HufCodehcd; intn=0;//总字节数 intflength=0;//文件大小 longf_count,h_read; unsignedcharc; chardata[3]; data[2]=0;//用来保存节点字符 charcode[100];//用来暂时存放编码 inti,j; /*将n,flength传进去,是为了将获得它,为以后压缩解压做准备*/ creatHufTree(ht,ifp,n,flength); /*此处对哈弗曼编码动态申请空间*/ hcd=newHCodeNode[n]; huf_code(hcd,ht,n); code[0]=0; h_read=0; f_count=8;//用来记录压缩后文件的大小 /*进行压缩*/ fseek(ifp,0,SEEK_SET);//将文件指针移到距离文件开始出0个字节出 fseek(ofp,8,SEEK_SET);//将文件指针移到距离文件开始出8个字节出 c=fgetc(ifp); while(! feof(ifp)) { h_read++;//计算已经读取的字节数 if(c>127) { data[0]=c; fread(&c,1,1,ifp); h_read++;//计算已经读取的字节数 data[1]=c; } else { data[0]=c; data[1]=0; } for(i=0;i if(strcmp(ht[i].data,data)==0)break;//找到其下标 strcat(code,hcd[i].bits);//将编码存到code中 j=strlen(code);//计算编码的位数 c=0; /*---------------------------------------------------*/ while(j>=8)//如果j大于8则进行安位存取进去剩下小于8的读下一个补到后面 { for(i=0;i<8;i++) { if(code[i]=='1')c=(c<<1)|1;//一位一位的进行写入 elsec=c<<1; } fwrite(&c,1,1,ofp); f_count++;//写入一个字节,进行加1 strcpy(code,code+8);//将code+8后的字符串放到code中 j=strlen(code); } if(h_read==flength)break; c=fgetc(ifp); } /*处理最后一个不满8位的*/ if(j>0)//j大于0,说明有剩余的 { strcat(code,"00000000");//不够补0 for(i=0;i<8;i++) { if(code[i]=='1')c=(c<<1)|1; elsec=c<<1; } fwrite(&c,1,1,ofp); f_count++; } fseek(ofp,0,SEEK_SET);//将文件指针移到文件开始出 fwrite(&flength,sizeof(long),1,ofp);//将原文件的大小放到文件中 fwrite(&f_count,sizeof(long),1,ofp);//将压缩后文件的大小放到文件中 fseek(ofp,f_count,SEEK_SET);//将文件指针移到末尾 fwrite(&n,sizeof(long),1,ofp);//将出现的文件的中共有多少个字节数放到文件末尾 /*接下来将文件中节点信息,及出现频率放到文件中*/ for(i=0;i { /*将每一个节点及其权值放到文件末尾*/ c=ht[i].data[0]; if(c>127) { fwrite(&ht[i].data[0],1,1,ofp); fwrite(&ht[i].data[1],1,1,ofp); } else fwrite(&ht[i].data[0],1,1,ofp); fwrite(&(ht[i].weight),4,1,ofp);//将节点的权值放进去 } fclose(ifp); fclose(ofp); printf("文件压缩成功! \n"); return1; } voiduncompress(FILE*ifp,FILE*ofp) { HufTreeht; chardata[3]; data[2]=0; charex; intcount; unsignedcharc,t,z; longi,j,m,n,p,l; inte;//用于转换用 longf,flength; intindex; fread(&flength,sizeof(long),1,ifp);//读原文件大小 fread(&f,sizeof(long),1,ifp);//读压缩后文件大小 fseek(ifp,f,SEEK_SET);//将文件指针移到文件压缩后的大小出,读其下一数据 fread(&n,sizeof(long),1,ifp);//将文件字节数读出来 /*将字节数读出来后进行对哈夫曼树存储空间动态申请*/ ht=newNodeHufm[2*n-1]; /*初始化哈夫曼树*/ for(i=0;i<2*n-1;i++) { ht[i].lch=ht[i].rch=ht[i].parent=-1; ht[i].weight=0; } /*读出每个字节的数据*/ for(i=0;i { fread(&c,1,1,ifp); if(c>127) { ht[i].data[0]=c; fread(&c,1,1,ifp); ht[i].data[1]=c; ht[i].data[2]=0; } else { ht[i].data[0]=c; ht[i].data[1]=0; } fread(&(ht[i].weight),4,1,ifp);//读出编码长度 } /*恢复哈夫曼树*/ intMIN1,MIN2,s1,s2; for(i=n;i<2*n-1;i++) { MIN1=10000000;MIN2=10000000; s1=s2=1000000; for(j=0;j { //ht[j].parent==-1找最小的 if(ht[j].parent! =-1)continue;//选完后的点parent不为-1 if(MIN2>ht[j].weight) { MIN1=MIN2; s1=s2; MIN2=ht[j].weight; s2=j; continue; } else if(ht[j].weight { MIN1=ht[j].weight; s1=j; } } ht[i].weight=ht[s1].weight+ht[s2].weight; ht[i].lch=s1;ht[i].rch=s2; ht[s1].parent=i; ht[s2].parent=i; } /*开始解压文件*/ fseek(ifp,8,SEEK_SET);//将文件指针移到开始字节8出 m=0;//用来计数,表示到原文件大小时结束 count=0;//计数表示压缩后的文件大小 index=2*n-2;//就是最后一个,根节点 while (1) { fread(&c,1,1,ifp);//读一个字节 count++; for(i=0;i<8;i++) { if(ht[index].lch==-1) { t=(unsignedchar)ht[index].data[0]; if(127>=t) { z=ht[index].data[0]; fwrite(&z,1,1,ofp); m++; } else { m=m+2; z=ht[index].data[0]; fwrite(&z,1,1,ofp); z=ht[index].data[1]; fwrite(&z,1,1,ofp); } index=2*n-2; } if(m==flength)break;//m记录翻译的数据个数,如果等于最开始文件大小便说明已经翻译完了 if(c>127) index=ht[index].rch; else index=ht[index].lch; c=c<<1; } if(count==f-8)break;//m记录翻译的数据个数,如果等于最开始文件大小便说明已经翻译完了 } fclose(ifp); fclose(ofp); printf("文件解压成功! \n"); } intmenu() { intn,yn; while (1) { system("cls"); printf("1.压缩文件2.解压文件3.退出\n"); printf("************************************\n"); printf("请选择: "); scanf("%d",&n); getchar(); if(n>=1&&n<=3) returnn; else { printf("选择错误! \n"); getch(); } } } voidmain() { FILE*ifp,*ofp; charf1[50],f2[50]; intn; while (1) { n=menu(); switch(n) { case1: printf("要压缩的文件名: ");
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼树 程序设计