哈夫曼程序设计文件压缩.docx
- 文档编号:24123499
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:24
- 大小:239.53KB
哈夫曼程序设计文件压缩.docx
《哈夫曼程序设计文件压缩.docx》由会员分享,可在线阅读,更多相关《哈夫曼程序设计文件压缩.docx(24页珍藏版)》请在冰豆网上搜索。
哈夫曼程序设计文件压缩
数据结构课程设计
设计题目:
基于哈夫曼编码的压缩软件
学生姓名:
贾明周俊张旭
专业班级:
10计科特色班B
******
完成时间:
2012/5/11
信息工程院计算机科学与技术系
安徽新华学院课程设计成绩评定表(本科)
课题名称
基于哈夫曼编码的压缩软件
院系
信息工程学院
年级专业
10计科特色
学号
姓名
组成员分工
成绩
1042157134
贾明
设计及编写程序;修改程序;编写文档
1042157156
张旭
设计及编写程序;修改程序;
负责文档的图片编辑
1042157157
周俊
查找资料,收集信息;设计及调试程序
编写及整理文档
课题设计
目的与
设计意义
1、课题设计目的:
通过运用哈夫曼树的知识编写该压缩与解压软件,能使学生将所学的理论知识应用起来,有效地运用到解决实际问题中去,提高
学生的自身的编程能力,从而达到学以致用的目的。
2、课题设计意义:
通过这次课题实验的程序实践,我们了解额数据结构是本学期开
展的一门学科,学习好这门学科是非常重要的,在以后的程序设计方
面这门学科能给我们很大的帮助。
同时,学习这门学科也是艰辛的,
这不仅需要我们要发挥我们的聪明才志,还需要我们在不断的实践中
领悟。
指导教师:
年月日
第一章课程设计内容
1.应用系统分析,建立该系统的功能模块框图及界面的组织和设计;
2.分析系统中的各个函数及它们之间的关系;
3.根据问题描述,设计系统的结构体及各个函数;
4.设计哈夫曼树的构造算法和哈夫曼编码算法;
5.完成设计的系统各个应用模块;
6.将各个模块整合进行功能测试。
第二章需求分析
1.需求分析目的
为明确软件需求、安排项目规划与进度、组织软件开发与测试,供设计人员、开发
人员参考。
2.项目开发计划
时间
开发内容
5月8日
读取文本文件,并统计文件中字母个数
5月9日
建立哈夫曼树对文件,进行哈夫曼编码
5月10日
压缩与解压缩
3.任务目标
能比较完善的对txt文件进行压缩和解压缩。
4.数据字典
名称:
字符频率
别名:
weight
描述:
读取文本文件,并统计文件中字母个数
定义:
字符频率=字符+数量
名称:
结点
别名:
HTNode
描述:
建立哈夫曼树的叶子和非叶子结点
定义:
结点=数量+字符+双亲结点+左孩子结点+右孩子结点
位置:
编码文件
5.功能划分
压缩
解压缩
第三章概要设计
3.1.哈夫曼压缩软件
1.建立哈夫曼树。
根据哈夫曼编码技术,可以将已经给出的字母的使用频率建立一个哈夫曼树,即以二叉树的形式将英文字母和空格存储。
2.编码。
利用二叉树的遍历知识,左孩子用“0”表示,右孩子用“1”表示,将输入的一组英文句子进行编码。
3.测试和输出。
程序要求的测试的英文句子是:
“knowledgeispower”,输出每一个字母然后给出相应的哈夫曼编码。
本程序输入字母以“#”结束。
4.译码。
本程序要求对已编码的数字能够给以反编码。
3.2..函数调用示意图
第四章调试情况,设计技巧及体会
4.1.测试过程
1运行程序
2压缩文件
3解压文件
4退出
第五章测试结论
◆能较好地对文本文档进行压缩和解压
◆不足的是其它对类型的文件不适用
第六章设计技巧
本软件可对字母、汉字可以实现共同压缩,压缩率在20%以上,压缩后对哈夫曼树进行保存,以便后面解压,对叶子结点只保存其字符、左孩子、右孩子,对非叶子结点保存左孩子和右孩子。
解压时从根结点开始,利用哈夫曼树进行解压,遇到0,找左孩子,遇到1找右孩子,到叶子结点时,输出字符。
第七章心得体会
通过这次课题实验的程序实践,我从中获益匪浅!
数据结构是本学期开展的一门学科,学习好这门学科是非常重要的,在以后的程序设计方面这门学科能给我们很大的帮助。
同时,学习这门学科也是艰辛的,这不仅需要我们要发挥我们的聪明才志,还需要我们在不断的实践中领悟。
这次的程序设计对我们来说无疑是一个检验,从接起课题后,我就一直为实现程序而努力,翻阅相关书籍、在网上查找资料。
通过小组的努力与老师的指导,我对这次实验的原理有了一定的理解,通过参照从网上找到的源程序,终于在其它源程序的基础下写出了本次实验的核心算法,并使其能够正常的运行。
这次课程设计,让我体会到了作为一个编程人员的艰难,一个算法到具体实现,再到应用层面的开发是需要有一段较长的路要走的。
非常感谢在背后一直给我指导的老师和同学,他们的支持和鼓励让我在遇到困难而坚持下来了,让我走到了今天这一步,完成了课程的设计。
今后,我会更加努力的学习专业知识,提高自我的能力。
第八章参考文献
严蔚敏、吴伟民主编.数据结构(C语言版).清华大学出版社,2002
杨秋辉等著.数据结构与算法(C++版).清华大学出版社,2009
金远平著.数据结构(C++描述).清华大学出版社,2005
许卓群等著.数据结构与算法.高等教育出版社,2004
严蔚敏、吴伟民.数据结构习题集(C语言版).清华大学出版社,2002
第九章附录:
源代码
#include
#include
#include
#include
structhead
{
unsignedcharb;//记录字符在数组中的位置
longcount;//字符出现频率(权值)
longparent,lch,rch;//定义哈夫曼树指针变量
charbits[256];//定义存储哈夫曼编码的数组
}
header[512],tmp;
/*压缩*/
voidcompress()
{
charfilename[255],outputfile[255],buf[512];
unsignedcharc;
longi,j,m,n,f;
longmin1,pt1,flength,length1,length2;
doublediv;
FILE*ifp,*ofp;
printf("\t请您输入需要压缩的文件:
");
gets(filename);
ifp=fopen(filename,"rb");
if(ifp==NULL)
{
printf("\n\t文件打开失败!
\n\n");
return;
}
printf("\t请您输入压缩后的文件名:
");
gets(outputfile);
ofp=fopen(strcat(outputfile,".hub"),"wb");
if(ofp==NULL)
{
printf("\n\t压缩文件失败!
\n\n");
return;
}
flength=0;
while(!
feof(ifp))
{
fread(&c,1,1,ifp);
header[c].count++;//字符重复出现频率+1
flength++;//字符出现原文件长度+1
}
flength--;
length1=flength;//原文件长度用作求压缩率的分母
header[c].count--;
for(i=0;i<512;i++)
{
if(header[i].count!
=0)header[i].b=(unsignedchar)i;
/*将每个哈夫曼码值及其对应的ASCII码存放在一维数组header[i]中,
且编码表中的下标和ASCII码满足顺序存放关系*/
elseheader[i].b=0;
header[i].parent=-1;header[i].lch=header[i].rch=-1;//对结点进行初始化
}
for(i=0;i<256;i++)//根据频率(权值)大小,对结点进行排序,选择较小的结点进树
{
for(j=i+1;j<256;j++)
{
if(header[i].count { tmp=header[i]; header[i]=header[j]; header[j]=tmp; } } } for(i=0;i<256;i++)if(header[i].count==0)break; n=i;//外部叶子结点数为n个时,内部结点数为n-1,整个哈夫曼树的需要的结点数为2*n-1. m=2*n-1; for(i=n;i { min1=999999999;//预设的最大权值,即结点出现的最大次数 for(j=0;j { if(header[j].parent! =-1)continue; //parent! =-1说明该结点已存在哈夫曼树中,跳出循环重新选择新结点*/ if(min1>header[j].count) { pt1=j; min1=header[j].count; continue; } } header[i].count=header[pt1].count; header[pt1].parent=i;//依据parent域值(结点层数)确定树中结点之间的关系 header[i].lch=pt1;//计算左分支权值大小 min1=999999999; for(j=0;j { if(header[j].parent! =-1)continue; if(min1>header[j].count) { pt1=j; min1=header[j].count; continue; } } header[i].count+=header[pt1].count; header[i].rch=pt1;//计算右分支权值大小 header[pt1].parent=i; } for(i=0;i { f=i; header[i].bits[0]=0;//根结点编码0 while(header[f].parent! =-1) { j=f; f=header[f].parent; if(header[f].lch==j)//置左分支编码0 { j=strlen(header[i].bits); memmove(header[i].bits+1,header[i].bits,j+1); //依次存储连接“0”“1”编码 header[i].bits[0]='0'; } else//置右分支编码1 { j=strlen(header[i].bits); memmove(header[i].bits+1,header[i].bits,j+1); header[i].bits[0]='1'; } } } fseek(ifp,0,SEEK_SET);//从文件开始位置向前移动0字节,即定位到文件开始位置 fwrite(&flength,sizeof(int),1,ofp); /*用来将数据写入文件流中,参数flength指向欲写入的数据地址, 总共写入的字符数以参数size*int来决定,返回实际写入的int数目1*/ fseek(ofp,8,SEEK_SET); buf[0]=0;//定义缓冲区,它的二进制表示00000000 f=0; pt1=8; /*假设原文件第一个字符是"A",8位2进制为01000001,编码后为0110识别编码第一个'0', 那么我们就可以将其左移一位,看起来没什么变化。 下一个是'1',应该|1,结果00000001 同理4位都做完,应该是00000110,由于字节中的8位并没有全部用完,我们应该继续读下一个字符, 根据编码表继续拼完剩下的4位,如果字符的编码不足4位,还要继续读一个字符, 如果字符编码超过4位,那么我们将把剩下的位信息拼接到一个新的字节里*/ while(! feof(ifp)) { c=fgetc(ifp); f++; for(i=0;i { if(c==header[i].b)break; } strcat(buf,header[i].bits); j=strlen(buf); c=0; while(j>=8)//对哈夫曼编码位操作进行压缩存储 { for(i=0;i<8;i++) { if(buf[i]=='1')c=(c<<1)|1; elsec=c<<1; } fwrite(&c,1,1,ofp); pt1++;//统计压缩后文件的长度 strcpy(buf,buf+8);//一个字节一个字节拼接 j=strlen(buf); } if(f==flength)break; } if(j>0)//对哈夫曼编码位操作进行压缩存储 { strcat(buf,"00000000"); for(i=0;i<8;i++) { if(buf[i]=='1')c=(c<<1)|1; elsec=c<<1; } fwrite(&c,1,1,ofp); pt1++; } fseek(ofp,4,SEEK_SET); fwrite(&pt1,sizeof(long),1,ofp); fseek(ofp,pt1,SEEK_SET); fwrite(&n,sizeof(long),1,ofp); for(i=0;i { fwrite(&(header[i].b),1,1,ofp); c=strlen(header[i].bits); fwrite(&c,1,1,ofp); j=strlen(header[i].bits); if(j%8! =0)//若存储的位数不是8的倍数,则补0 { for(f=j%8;f<8;f++) strcat(header[i].bits,"0"); } while(header[i].bits[0]! =0) { c=0; for(j=0;j<8;j++)//字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接 { if(header[i].bits[j]=='1')c=(c<<1)|1;//|1不改变原位置上的“0”“1”值 elsec=c<<1; } strcpy(header[i].bits,header[i].bits+8);//把字符的编码按原先存储顺序连接 fwrite(&c,1,1,ofp); } } length2=pt1--; div=((double)length1-(double)length2)/(double)length1;//计算文件的压缩率 fclose(ifp); fclose(ofp); printf("\n\t压缩文件成功! \n"); printf("\t压缩率为%f%%\n\n",div*100); return; } /*解压缩*/ voiduncompress() { charfilename[255],outputfile[255],buf[255],bx[255]; unsignedcharc; longi,j,m,n,f,p,l; longflength; FILE*ifp,*ofp; printf("\t请您输入需要解压缩的文件: "); gets(filename); ifp=fopen(strcat(filename,".hub"),"rb"); if(ifp==NULL) { printf("\n\t文件打开失败! \n"); return; } printf("\t请您输入解压缩后的文件名: "); gets(outputfile); ofp=fopen(outputfile,"wb"); if(ofp==NULL) { printf("\n\t解压缩文件失败! \n"); return; } fread(&flength,sizeof(long),1,ifp);//读取原文件长度,对文件进行定位 fread(&f,sizeof(long),1,ifp); fseek(ifp,f,SEEK_SET); fread(&n,sizeof(long),1,ifp); for(i=0;i { fread(&header[i].b,1,1,ifp); fread(&c,1,1,ifp); p=(long)c;//读取原文件字符的权值 header[i].count=p; header[i].bits[0]=0; if(p%8>0)m=p/8+1; elsem=p/8; for(j=0;j { fread(&c,1,1,ifp); f=c; itoa(f,buf,2);//将f转换为二进制表示的字符串 f=strlen(buf); for(l=8;l>f;l--) { strcat(header[i].bits,"0"); } strcat(header[i].bits,buf); } header[i].bits[p]=0; } for(i=0;i { for(j=i+1;j { if(strlen(header[i].bits)>strlen(header[j].bits)) { tmp=header[i]; header[i]=header[j]; header[j]=tmp; } } } p=strlen(header[n-1].bits); fseek(ifp,8,SEEK_SET); m=0; bx[0]=0; while (1)//通过哈夫曼编码的长短,依次解码,从原来的位存储还原到字节存储 { while(strlen(bx)<(unsignedint)p) { fread(&c,1,1,ifp); f=c; itoa(f,buf,2); f=strlen(buf); for(l=8;l>f;l--)//在单字节内对相应位置补0 { strcat(bx,"0"); } strcat(bx,buf); } for(i=0;i { if(memcmp(header[i].bits,bx,header[i].count)==0)break; } strcpy(bx,bx+header[i].count);/*从压缩文件中的按位存储还原到按字节存储字符, 字符位置不改变*/ c=header[i].b; fwrite(&c,1,1,ofp); m++;//统计解压缩后文件的长度 if(m==flength)break;//flength是原文件长度 } fclose(ifp); fclose(ofp); printf("\n\t解压缩文件成功! \n"); if(m==flength)//对解压缩后文件和原文件相同性比较进行判断(根据文件大小) printf("\t解压缩文件与原文件相同! \n\n"); elseprintf("\t解压缩文件与原文件不同! \n\n"); return; } /*主函数*/ intmain() { intc; while (1)//菜单工具栏 { printf("\t_______________________________________________\n"); printf("\n"); printf("\t*压缩、解压缩小工具*\n"); printf("\t_______________________________________________\n"); printf("\t_______________________________________________\n"); printf("\t||\n"); printf("\t|1.压缩|\n"); printf("\t|2.解压缩|\n"); printf("\t|0.退出|\n"); printf("\t|_______________________________________________|\n"); printf("\n"); printf("\t说明: (1)采用哈夫曼编码\n"); printf("\t (2)适用于文本文件\n"); printf("\n"); do//对用户输入进行容错处理 { printf("\n\t*请选择相应功能(0-2): "); c=getch(); printf("%c\n",c); if(c! ='0'&&c! ='1'&&c! ='2') { printf("\t@_@请检查您的输入在0~2之间! \n"); printf("\t请再输入一遍! \n"); } }while(c! ='0'&&c! ='1'&&c! ='2'); if(c=='1')compress();//调用压缩子函数 elseif(c=='2')uncompress();//调用解压缩子函数 else { printf("\t欢迎您再次使用该工具^_^\n"); exit(0);//退出该工具 } system("pause");//任意键继续 system("cls");//清屏 } return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 程序设计 文件 压缩