用赫夫曼编码完成文件全资料压缩.docx
- 文档编号:5518431
- 上传时间:2022-12-18
- 格式:DOCX
- 页数:20
- 大小:264.90KB
用赫夫曼编码完成文件全资料压缩.docx
《用赫夫曼编码完成文件全资料压缩.docx》由会员分享,可在线阅读,更多相关《用赫夫曼编码完成文件全资料压缩.docx(20页珍藏版)》请在冰豆网上搜索。
用赫夫曼编码完成文件全资料压缩
实验报告
题目:
用赫夫曼编码实现文件压缩
班级:
理科实验四班:
王渭森
一、需求分析
1.现实需求:
1〕通信线路中实现信息的最大传送,利用变长编码的方式,可以有效充分利用带宽,实现信息传送前的压缩。
2).在文件保存时,利用哈夫曼编码的方式,压缩文件,可以实现硬盘存储最大的信息量。
2.程序执行的命令包括:
1)读取文件。
2)新建并写入文件。
3)将文件中的字符转换为哈夫曼编码。
4)将哈夫曼编码八位一组专户为十进制,在通过十进制的ASCII码转换为字符。
5)翻译过程现将字符转为01串,再将01串翻译为原来的文件。
1〕
2〕
3〕
4〕
5〕
新建一个文件并压缩。
二、概要设计
1.串的抽象数据类型定义为:
ADTString{
数据对象:
D={ai|ai∈CharacterSet,i=1,2,...,n,n>=0}
数据关系:
R1={
根本操作:
strcpy(String&S1,StringS2)
初始条件:
串S2存在。
操作结果:
由串S2复制得串S1.
strlen(SStringS)
初始条件:
串S存在。
操作结果:
返回S的元素个数,称为串的长度。
}//ADTString
2.二叉树的抽象数据类型定义为:
ADTBinaryTree{
数据对象D:
是具有一样特性的元素的集合。
数据关系R:
假设D为空集,如此称为空二叉树;
假设D仅含一个数据元素,如此R为空集,否如此R = {H}, H是如下二元关系:
1〕在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;
2〕 假设D – {root} ≠ Φ,如此存在D – {root} 的一个划分Dl Dr ,Dl∩Dr =Φ;
3〕 假设Dl≠Φ,如此Dl 中存在惟一的数据元素x,
4〕〔Dl,{ Hl、}〕是一棵符合本定义的二叉树,称为根root的左子树,〔Dr,{ Hr、}〕是一棵符合本定义的二叉树,称为根root的右子树。
根本操作P:
InitBitree(&T);
操作结果:
构造空二叉树。
CreateBitree(&T);
初始条件:
二叉树存在。
操作结果:
按输入格式构造二叉树。
Value(T, e);
初始条件:
二叉树存在,e是T中某个结点。
操作结果:
返回结点e的值。
Assign(&T, &e, value);
初始条件:
二叉树存在,e是T中某个结点。
操作结果:
结点e赋值为value 。
Parent(T, e);
初始条件:
二叉树存在,e是T中某个结点。
操作结果:
假设e是T的非根结点,如此返回它的双亲,否如此返回“空〞。
LeftChild(T, e);
初始条件:
二叉树存在,e是T中某个结点。
操作结果:
返回e的左孩子。
假设e无左孩子,如此返回“空〞。
RightChild(T, e);
初始条件:
二叉树存在,e是T中某个结点。
操作结果:
返回e的右孩子。
假设e无右孩子,如此返回“空〞。
}ADTBinaryTree
3.赫夫曼树和赫夫曼编码的存储表示:
typedefstruct{
chardata;
intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码。
4.函数的调用关系图:
main()->pressFile()->HuffmanCoding()->Select()
->WriteFile()->CoToCh()
->DepressFile()->ChToCo(ame);
->translation()
三、调试分析
1.文件中字符数目可能非常大,不能用一个整的数组来存,所以需要从文件中一个字符一个字符来读取处理。
2.为解决文件中字符出现的不确定性,用数组character[256]来记录相应ASCII的字符出现次数,统计完后,将出现次数非零的字符存在数组v[]中,并将它们的权值存在数组w[]中。
3.在将赫夫曼编码翻译为字符中,translation〔〕中函数的变量ch,在运算中应该变它的对应的值,即为,传参应为char&ch,而不应为charch。
4.将哈夫曼八位一组转为十进制时,01串中个数不一定为8的倍数,先遍历文件,统计01串中元素个数,将该个数除以8的余数拿出来,放入压缩文件的第一位,在依次将等于余数个数的01字符直接放入压缩文件,之后的01串为8的整数倍。
5.读取压缩后的乱码是,可能读出负数,假设读出负数,让这个负数加上256再转化为2进制的01串。
四、测试结果
1.
如图,4为余数。
压缩率:
125%
可见,当文件中元素个数小于8时,压缩文件反而会增大。
2.
压缩率:
7/30
3.
压缩率:
9/30。
4.
压缩率接近百分之五十。
总和2、3、4可见,可见,一样大小的文件,其中元素分布越集中,压缩率越大。
5.
五、附录
源程序文件清单:
#defineMAXWEIGHT2147483647
#defineMAXASCII255
#defineMAXNAME100
#include
#include
#include
#include
typedefstruct{
chardata;
intweight;
intparent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储赫夫曼树
typedefchar**HuffmanCode;//动态分配数组存储赫夫曼编码。
voidSelect(HuffmanTreeHT,intindex,int&s1,int&s2)
{//从序号为1~index的结点中选出两个最小的且没有双亲的结点。
intw1,w2,t,i;
s1=0;s2=0;w1=MAXWEIGHT;w2=MAXWEIGHT;
for(i=1;i<=index;i++)
{
if(HT[i].parent==0)
{
if(HT[i].weight { s2=s1;w2=w1; s1=i;w1=HT[i].weight; } elseif(HT[i].weight { s2=i;w2=HT[i].weight; } } } } intHuffmanCoding(HuffmanTree&HT,HuffmanCode&HC,char*v,int*w,intn) {//v存放需要编码的n个字符,w存放对应的权值, //构造赫夫曼树,并求出n个字符的赫夫曼编码。 if(n==0) {//没有合法字符时 printf("没有需要编码的字符! "); return-1; } if(n==1) {//只有一个合法字符时 HC=(HuffmanCode)malloc((n+1)*sizeof(char*)); HC[1]=(char*)malloc(3*sizeof(char)); HC[1][0]=*v; HC[1][1]='0'; HC[1][2]=0; HT=(HuffmanTree)malloc(2*sizeof(HTNode)); HT[1].parent=0; HT[1].lchild=0; HT[1].rchild=0; HT[1].weight=*w; HT[1].data=*v; return0; } ints1,s2,m,i; m=2*n-1; HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); HuffmanTreep; HT->weight=m; for(p=HT+1,i=1;i<=n;i++,p++,w++,v++) { p->weight=*w; p->lchild=0; p->rchild=0; p->parent=0; p->data=*v; } for(;i<=m;i++,p++) { p->weight=0; p->lchild=0; p->rchild=0; p->parent=0; } for(i=n+1;i<=m;i++) {//在HT[1..i-1]选择parent为0而且weight最小的 //两个结点且weight最小的两个结点,其序号分别 //为s1和s2 Select(HT,i-1,s1,s2); HT[s1].parent=i;HT[s2].parent=i; HT[i].lchild=s1;HT[i].rchild=s2; HT[i].weight=HT[s1].weight+HT[s2].weight; } //---从叶子到根逆向求每个字符的霍夫曼编码--- char*cd; intstart,c,f; 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'; elsecd[--start]='1'; HC[i]=(char*)malloc((n-start+1)*sizeof(char)); strcpy(HC[i]+1,&cd[start]); HC[i][0]=v[i-1-n]; } free(cd); return1; } voidtranslation(FILE*fp1,FILE*fp2,char&ch,HuffmanTreeHT,inti,intf) {//逐字翻译压缩文件中的赫夫曼编码 if(HT[i].lchild==0&&HT[i].rchild==0) {//假设为叶子结点,如此成功翻译一个字符,将它输入到解压文件中 fputc(HT[i].data,fp2); if(f==0)ch=fgetc(fp1); return; } if(ch=='0') {//假设为0,如此探索左孩子 f=1; ch=fgetc(fp1); translation(fp1,fp2,ch,HT,HT[i].lchild,f); } elseif(ch=='1') {//假设为1,如此探索左孩子 f=1; ch=fgetc(fp1); translation(fp1,fp2,ch,HT,HT[i].rchild,f); } } voidCoToCh(charame[]) { FILE*fp1,*fp2; charDName[MAXNAME]={0},ch;//存放压缩后的文件名 intBin[7]={0},asc;//八个01一组放入Bin串;二进制对应的ASCII值 inti,j,num=0,r; printf("请输入你希望得到的压缩后的文件名: "); gets(DName); fp1=fopen(ame,"rb"); fp2=fopen(DName,"wb"); while(! feof(fp1))//计算0,1的数量 { ch=fgetc(fp1); num++; } num--; rewind(fp1); r=num%8;//八个一组多余出来的01 fputc(r+'0',fp2);//将多出来的数量的值放在压缩文件第一位 for(j=1;j<=r;j++) {//后面r位原封不动的将01复制进来 ch=fgetc(fp1); fputc(ch,fp2); } while(! feof(fp1)) { i=0;asc=0; memset(Bin,0,sizeof(Bin)); while(! feof(fp1)&&i<=7) { ch=fgetc(fp1); Bin[i]=ch-'0'; i++; } if(feof(fp1))break; for(j=0;j<=i-1;j++) asc=asc*2+Bin[j]; fputc(asc,fp2); } fclose(fp1);fclose(fp2); printf("压缩后的文件名为: ");puts(DName); } voidWriteFile(HuffmanCodeHC,charFName[],intk,charv[]) {//将被压缩的文件容写入另一个文件 FILE*fp1,*fp2; charame[MAXNAME]={0},ch; strcpy(ame,"CP"); strcpy(ame+2,FName);//哈夫曼编码文件命名为"'CP'+原文件名" fp1=fopen(FName,"rb"); fp2=fopen(ame,"wb"); while (1) { inti; ch=fgetc(fp1); if(feof(fp1))break; for(inti=0;i<=k-1;i++) { if(ch==v[i]) fputs(HC[i+1]+1,fp2);//将赫夫曼编码写入哈夫曼编码文件 } } fclose(fp1);fclose(fp2); CoToCh(ame); } voidpressFile(HuffmanTree&HT,HuffmanCode&HC,int&k) {//读取文件中的字符,构造哈夫曼曼树,得到每个字符的哈夫曼编码 FILE*fp; intflag; charch,v[MAXASCII+1],FName[MAXNAME];//v存放出现的字符 intcharacter[MAXASCII+1]={0};//统计每种字符出现的次数 intw[MAXASCII+1];//w放字符的权值 printf("请键入要运行的操作编号: \n1.压缩已有的文件\n2.建立新文件,输入容并进展压缩\n"); scanf("%d",&flag);//选择操作 getchar(); if(flag==1) { printf("请键入需要压缩的文件名: "); gets(FName); fp=fopen(FName,"r"); } elseif(flag==2) { printf("请键入需要压缩的文件名: "); gets(FName); printf("请键入文件容: \n"); fp=fopen(FName,"w"); while(ch! ='\n') { scanf("%c",&ch); fputc(ch,fp); } fclose(fp); fp=fopen(FName,"r"); } else { printf("警告: 无此操作项! "); return; } while (1) {//逐个读取文件中的字符,数组character对应字符位置上+1 inti; ch=fgetc(fp); if(feof(fp))break; character[ch]++; } for(inti=0;i<=MAXASCII-1;i++) {//假设某字符在在文件中出现,如此把它放入v,并把权值计入一样序号的w if(character[i]! =0) { v[k]=i; w[k++]=character[i]; } } printf("文件中出现的字符与它们的权值: \n"); for(inti=0;i<=k-1;i++) printf("%c-%d;\n",v[i],w[i]); HuffmanCoding(HT,HC,v,w,k); fclose(fp); printf("上述字符对应的哈夫曼编码: \n"); for(inti=1;i<=k;i++) puts(HC[i]); WriteFile(HC,FName,k,v); } voidChToCo(charDName[],charame[]) { FILE*fp1,*fp2; intr,i,j,Bin[7]={0},asc; charch; fp1=fopen(DName,"rb"); strcpy(ame,"RCP"); strcpy(ame+3,DName); fp2=fopen(ame,"wb"); r=fgetc(fp1)-'0'; for(i=1;i<=r;i++) { ch=fgetc(fp1); fputc(ch,fp2); } while (1) { ch=fgetc(fp1); if(feof(fp1))break; asc=(int)ch; if(asc<0)asc+=256; for(i=7;i>=0;i--) { Bin[i]=asc%2; asc=asc/2; } for(i=0;i<=7;i++) fputc(Bin[i]+'0',fp2); } fclose(fp1);fclose(fp2); } voidDepressFile(HuffmanTreeHT,intk) {//解压函数 FILE*fp1,*fp2; charDName[MAXNAME],FName[MAXNAME],ame[MAXNAME]={0},ch; intr; printf("请键入需要解压的文件名: 〔注意: 文件中的字符权值需与上述一样! 〕"); gets(DName); printf("请输入解压后希望得到的文件名: "); gets(FName); printf("解压后的文件名为: ");puts(FName); ChToCo(DName,ame); fp1=fopen(ame,"rb"); fp2=fopen(FName,"wb"); ch=fgetc(fp1); while(! feof(fp1)) {//到压缩文件末尾完毕 translation(fp1,fp2,ch,HT,2*k-1,0); } fclose(fp1);fclose(fp2); } intmain() { HuffmanTreeHT; HuffmanCodeHC; intk=0,flag; pressFile(HT,HC,k); printf("请键入要运行的操作编号: \n1.完毕进程\n2.解压文件\n"); scanf("%d",&flag); getchar(); if(flag==1){} elseif(flag==2) DepressFile(HT,k); else printf("警告: 无此操作项! "); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 用赫夫曼 编码 完成 文件 资料 压缩