用赫夫曼编码完成文件压缩.docx

上传人:b****5 文档编号:7382852 上传时间:2023-01-23 格式:DOCX 页数:20 大小:276.29KB
下载 相关 举报
用赫夫曼编码完成文件压缩.docx_第1页
第1页 / 共20页
用赫夫曼编码完成文件压缩.docx_第2页
第2页 / 共20页
用赫夫曼编码完成文件压缩.docx_第3页
第3页 / 共20页
用赫夫曼编码完成文件压缩.docx_第4页
第4页 / 共20页
用赫夫曼编码完成文件压缩.docx_第5页
第5页 / 共20页
点击查看更多>>
下载资源
资源描述

用赫夫曼编码完成文件压缩.docx

《用赫夫曼编码完成文件压缩.docx》由会员分享,可在线阅读,更多相关《用赫夫曼编码完成文件压缩.docx(20页珍藏版)》请在冰豆网上搜索。

用赫夫曼编码完成文件压缩.docx

用赫夫曼编码完成文件压缩

实验报告

题目:

用赫夫曼编码实现文件压缩

班级:

理科实验四班姓名:

王渭森

学号:

2015201992完成日期:

2016.6.10

1、需求分析

1.现实需求:

1)通信线路中实现信息的最大传送,利用变长编码的方式,可以有效充分利用带宽,实现信息传送前的压缩。

2).在文件保存时,利用哈夫曼编码的方式,压缩文件,可以实现硬盘存储最大的信息量。

2.程序执行的命令包括:

1)读取文件。

2)新建并写入文件。

3)将文件中的字符转换为哈夫曼编码。

4)将哈夫曼编码八位一组专户为十进制,在通过十进制的ASCII码转换为字符。

5)翻译过程现将字符转为01串,再将01串翻译为原来的文件。

3.测试数据

1)

 

2)

 

3)

 

4)

 

5)

新建一个文件并压缩。

2、概要设计

1.串的抽象数据类型定义为:

ADTString{

数据对象:

D={ai|ai∈CharacterSet,i=1,2,...,n,n>=0}

数据关系:

R1={|ai-1,ai∈D,i=1,2,...,n}

基本操作:

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, ∈ H,且存在Dl 上的关系Hl < H;若Dr ≠ Φ,则Dr 中存在惟一的数据元素xr , ∈ H,且存在Dr 上的关系Hr < H; 

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()->CompressFile()->HuffmanCoding()->Select()

->WriteFile()->CoToCh()

->DeCompressFile()->ChToCo(CName);

->translation()

3、调试分析

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串。

4、测试结果

1.

如图,4为余数。

压缩率:

125%

可见,当文件中元素个数小于8时,压缩文件反而会增大。

2.

压缩率:

7/30

3.

压缩率:

9/30。

4.

原文件大小为:

21.2KB

压缩文件大小为11.3KB

压缩率接近百分之五十。

总和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(charCName[])

{

FILE*fp1,*fp2;

charDName[MAXNAME]={0},ch;//存放压缩后的文件名

intBin[7]={0},asc;//八个01一组放入Bin串;二进制对应的ASCII值

inti,j,num=0,r;

printf("请输入你希望得到的压缩后的文件名:

");

gets(DName);

fp1=fopen(CName,"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;

charCName[MAXNAME]={0},ch;

strcpy(CName,"CP");

strcpy(CName+2,FName);//哈夫曼编码文件命名为"'CP'+原文件名"

fp1=fopen(FName,"rb");

fp2=fopen(CName,"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(CName);

}

voidCompressFile(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[],charCName[])

{

FILE*fp1,*fp2;

intr,i,j,Bin[7]={0},asc;

charch;

fp1=fopen(DName,"rb");

strcpy(CName,"RCP");

strcpy(CName+3,DName);

fp2=fopen(CName,"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);

}

voidDecompressFile(HuffmanTreeHT,intk)

{//解压函数

FILE*fp1,*fp2;

charDName[MAXNAME],FName[MAXNAME],CName[MAXNAME]={0},ch;

intr;

printf("请键入需要解压的文件名:

(注意:

文件中的字符权值需与上述相同!

)");

gets(DName);

printf("请输入解压后希望得到的文件名:

");

gets(FName);

printf("解压后的文件名为:

");puts(FName);

ChToCo(DName,CName);

fp1=fopen(CName,"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;

CompressFile(HT,HC,k);

printf("请键入要运行的操作编号:

\n1.结束进程\n2.解压文件\n");

scanf("%d",&flag);

getchar();

if(flag==1){}

elseif(flag==2)

DecompressFile(HT,k);

else

printf("警告:

无此操作项!

");

return0;

}

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

当前位置:首页 > 农林牧渔 > 林学

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

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