用赫夫曼编码完成文件全资料压缩Word格式文档下载.docx
《用赫夫曼编码完成文件全资料压缩Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《用赫夫曼编码完成文件全资料压缩Word格式文档下载.docx(20页珍藏版)》请在冰豆网上搜索。
数据对象D:
是具有一样特性的元素的集合。
数据关系R:
假设D为空集,如此称为空二叉树;
假设D仅含一个数据元素,如此R为空集,否如此R
=
{H},
H是如下二元关系:
1〕在D中存在唯一的称为根的数据元素root,它在关系H下无前驱;
2〕
假设D
–
{root}
≠
Φ,如此存在D
的一个划分Dl
Dr
,Dl∩Dr
=Φ;
3〕
假设Dl≠Φ,如此Dl
中存在惟一的数据元素x,<
root,
xl>
∈
H,且存在Dl
上的关系Hl
<
H;
假设Dr
Φ,如此Dr
中存在惟一的数据元素xr
,<
xr>
H,且存在Dr
上的关系Hr
4〕〔Dl,{
Hl、}〕是一棵符合本定义的二叉树,称为根root的左子树,〔Dr,{
Hr、}〕是一棵符合本定义的二叉树,称为根root的右子树。
根本操作P:
InitBitree(&
T);
构造空二叉树。
CreateBitree(&
二叉树存在。
按输入格式构造二叉树。
Value(T,
e);
二叉树存在,e是T中某个结点。
返回结点e的值。
Assign(&
T,
&
e,
value);
结点e赋值为value
。
Parent(T,
假设e是T的非根结点,如此返回它的双亲,否如此返回“空〞。
LeftChild(T,
返回e的左孩子。
假设e无左孩子,如此返回“空〞。
RightChild(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<
stdio.h>
stdlib.h>
string.h>
memory.h>
chardata;
intweight;
intparent,lchild,rchild;
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<
w1)
{
s2=s1;
w2=w1;
s1=i;
w1=HT[i].weight;
}
elseif(HT[i].weight<
w2)
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;
=n;
i++,p++,w++,v++)
p->
weight=*w;
lchild=0;
rchild=0;
parent=0;
data=*v;
for(;
=m;
i++,p++)
weight=0;
for(i=n+1;
{//在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;
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]='
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,如此探索左孩子
f=1;
ch=fgetc(fp1);
translation(fp1,fp2,ch,HT,HT[i].lchild,f);
elseif(ch=='
{//假设为1,如此探索左孩子
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的数量
{
num++;
num--;
rewind(fp1);
r=num%8;
//八个一组多余出来的01
fputc(r+'
fp2);
//将多出来的数量的值放在压缩文件第一位
for(j=1;
j<
=r;
j++)
{//后面r位原封不动的将01复制进来
fputc(ch,fp2);
feof(fp1))
i=0;
asc=0;
memset(Bin,0,sizeof(Bin));
while(!
feof(fp1)&
=7)
ch=fgetc(fp1);
Bin[i]=ch-'
i++;
}
if(feof(fp1))break;
for(j=0;
=i-1;
asc=asc*2+Bin[j];
fputc(asc,fp2);
fclose(fp1);
fclose(fp2);
压缩后的文件名为:
puts(DName);
voidWriteFile(HuffmanCodeHC,charFName[],intk,charv[])
{//将被压缩的文件容写入另一个文件
charame[MAXNAME]={0},ch;
strcpy(ame,"
CP"
strcpy(ame+2,FName);
//哈夫曼编码文件命名为"
'
CP'
+原文件名"
fp1=fopen(FName,"
fp2=fopen(ame,"
while
(1)
inti;
for(inti=0;
=k-1;
if(ch==v[i])
fputs(HC[i+1]+1,fp2);
//将赫夫曼编码写入哈夫曼编码文件
CoToCh(ame);
voidpressFile(HuffmanTree&
HC,int&
k)
{//读取文件中的字符,构造哈夫曼曼树,得到每个字符的哈夫曼编码
FILE*fp;
intflag;
charch,v[MAXASCII+1],FName[MAXNAME];
//v存放出现的字符
intcharacter[MAXASCII+1]={0};
//统计每种字符出现的次数
intw[MAXASCII+1];
//w放字符的权值
请键入要运行的操作编号:
\n1.压缩已有的文件\n2.建立新文件,输入容并进展压缩\n"
scanf("
%d"
&
flag);
//选择操作
getchar();
if(flag==1)
请键入需要压缩的文件名:
gets(FName);
fp=fopen(FName,"
r"
elseif(flag==2)
请键入文件容:
\n"
w"
while(ch!
='
\n'
scanf("
%c"
ch);
fputc(ch,fp);
fclose(fp);
else
警告:
无此操作项!
{//逐个读取文件中的字符,数组character对应字符位置上+1
ch=fgetc(fp);
if(feof(fp))break;
character[ch]++;
for(inti=0;
=MAXASCII-1;
{//假设某字符在在文件中出现,如此把它放入v,并把权值计入一样序号的w
if(character[i]!
=0)
v[k]=i;
w[k++]=character[i];
文件中出现的字符与它们的权值:
%c-%d;
v[i],w[i]);
HuffmanCoding(HT,HC,v,w,k);
fclose(fp);
上述字符对应的哈夫曼编码:
for(inti=1;
=k;
puts(HC[i]);
WriteFile(HC,FName,k,v);
voidChToCo(charDName[],charame[])
intr,i,j,Bin[7]={0},asc;
charch;
fp1=fopen(DName,"
RCP"
strcpy(ame+3,DName);
r=fgetc(fp1)-'
asc=(int)ch;
if(asc<
0)asc+=256;
for(i=7;
i>
i--)
Bin[i]=asc%2;
asc=asc/2;
for(i=0;
=7;
fputc(Bin[i]+'
voidDepressFile(HuffmanTreeHT,intk)
{//解压函数
charDName[MAXNAME],FName[MAXNAME],ame[MAXNAME]={0},ch;
intr;
请键入需要解压的文件名:
〔注意:
文件中的字符权值需与上述一样!
〕"
请输入解压后希望得到的文件名:
gets(FName);
解压后的文件名为:
puts(FName);
ChToCo(DName,ame);
fp2=fopen(FName,"
ch=fgetc(fp1);
{//到压缩文件末尾完毕
translation(fp1,fp2,ch,HT,2*k-1,0);
intmain()
HuffmanTreeHT;
HuffmanCodeHC;
intk=0,flag;
pressFile(HT,HC,k);
\n1.完毕进程\n2.解压文件\n"
if(flag==1){}
DepressFile(HT,k);
else
return0;