实验5huffman编码.docx
《实验5huffman编码.docx》由会员分享,可在线阅读,更多相关《实验5huffman编码.docx(22页珍藏版)》请在冰豆网上搜索。
实验5huffman编码
深圳大学实验报告
课程名称:
算法设计与分析
实验项目名称:
Huffman编码
学院:
专业:
指导教师:
报告人:
学号:
班级:
实验时刻:
2017年11月26日
实验报告提交时刻:
2017年12月6日
教务部制
实验目的与要求:
一、实验目的:
(1)掌握Huffman编码。
(2)掌握文档压缩的基本原理和应用
二、分组:
一人一组
三、内容:
1.以字母(Character)为基础的压缩
1.文本解析:
将cacm.all文件分解成一个个的字母
2.字频统计:
统计每个字母出现的词频
3.Huffman编码:
根据Huffman编码的原理,对每个字母进行编码。
给出一个编码字典。
4.文档压缩:
根据Huffman编码,压缩文件。
5.文档还原:
对压缩后的文档进行解压缩。
2.比较
比较不同的压缩方法的效率
字母压缩
Rar压缩
时间效率
压缩效率
(选做)以字母压缩为基础的算法除了可以对文本文件进行压缩外,还可以对二进制文件进行压缩,比如对图像、视频、可执行文件的压缩。
自己找一些这类二进制文件,比较压缩算法对不同文件的压缩效率。
字母压缩
Rar压缩
BPM图像时间效率
BPM图像压缩效率
JPG图像时间效率
JPG图像压缩效率
EXE文件时间效率
EXE文件压缩效率
AVI文件时间效率
AVI文件压缩效率
RMBV文件时间效率
RMBV文件压缩效率
MPEG文件时间效率
MPEG文件压缩效率
MP3文件时间效率
MP3文件压缩效率
四:
提交内容
1.源程序
2.实验报告
3.压缩后的文档
4.词频统计表和Huffman编码表:
类似下面的表格(下表中的数据只是示例,以实际生成的数据为准)
字母
词频
Huffman编码(二进制)
a
1150000
00
b
980000
011
五.其他注意事项
以Huffman编码为基础的压缩文件应该以二进制的方式来存储,这就涉及到文件的读写操作中的“以文本方式打开文件”“以二进制方式打开文件”这两种不同的方式。
建议详细参考C语言中关于文件的读写这部分内容。
方法、步骤:
一.实验思路:
1.霍夫曼编码原理
假如给定字符串如下。
图一:
增广路径示意图
统计字符种类及每种字符出现的个数。
图二:
统计结果
每次选取权值最小的两个节点构建二叉树。
图三:
构建二叉树
置其根结点的权值为其左右子树权值之和。
图四:
构建设置父节点
删除表中两个已经添加过的叶子节点,将根节点置入表中,并回到第一步。
图五:
删除节点
注:
规定左节点小于右节点,当权值相等时比较字符在ASCII表中顺序。
图六:
构建霍夫曼表
重复上述步骤即可。
如果为二进制文件则用二进制打开并读取,每五位一组。
2.压缩率和压缩时间
字母压缩
Rar压缩
时间效率
259ms
0ms
压缩效率
62.2634%
25.84%
3.改进方法
问题:
要构造编码树必须提前统计符号出现概率,必须先进行扫描。
扫描要进行两次,第一遍统计符号出现概率,第二遍进行编码。
这里我们采用自适应的霍夫曼编码。
随着符号的统计也动态进行,同一个符号的编码可能发生改变。
霍夫曼编码方法不唯一。
因为编码时的0和1是任意给的,在两个符号有相同概率时的编码过程不唯一。
这些问题使解码需要编码树的结构,因此需要降低哈弗曼树的存储空间。
而范式霍夫曼编码则对于同一层的节点,所有的叶子节点都调整到左边。
然后,对于同一层的叶子节点按照符号顺序从小到大调整。
最后,按照左0右1的方案分配编码。
图七:
构建范式霍夫曼表
范式霍夫曼编码要求相同长度的码字是连续整数的二进制描述。
码字长度最小的第一个编码从0开始。
长度为i第一个码字f(i)必须满足f(i)=2(f(i-1)+1)。
例如,符号:
abcdefghijk...u,码长:
34444444455...5。
根据约定3,即first[3]=0可得到符号a的范式哈夫曼编码为000。
根据约定2,可得到first[4]=2*(first[3]+1)=2,进一步可知b的编码为0010。
由约定1可构造出符号c的编码为0011,由此类推可构造出整个码字空间。
在现实生活中,文章由单词构成,在单词重复率高或长篇幅文章中,按单词压缩效率会更高。
二.程序运行结果截图:
图八:
主程序运行窗口
图九:
文件压缩与解压缩及时间计算
图十:
实际生成的文件
其中:
●源程序:
main.cpp
●文本解析后的文件:
cacm.txt
●压缩后的文档:
encryption.txt
●词频统计表:
count.txt
●Huffman编码表:
code.txt
●解压缩后的文件:
decode.txt
图十一:
解析后的cacm.txt文件
图十二:
哈夫曼编码文件code.txt
图十三:
字频统计文件count.txt
图十三:
压缩后的文件encryption.txt
图十四:
解压缩后的文件deocde.txt
三.总结:
霍夫曼编码通过构建霍夫曼树缩短码长,从而实现对文件的压缩和解压。
四.实验心得
实验过程难免会遇到问题,掌握好的调试技巧能够快速查找出问题的所在,并通过排查,逐一改正程序中存在的问题,不管用什么编译器,都要学会设置适当的断点。
遇到不懂的地方要多查看相关的书籍或者在网上查找资料,这样才能真正学到东西。
实验结论:
霍夫曼编码通过构建霍夫曼树缩短码长,从而实现对文件的压缩和解压。
指导教师批阅意见:
成绩评定:
指导教师签字:
年月日
备注:
注:
1、报告内的项目或内容设置,可依如实际情形加以调整和补充。
2、教师批改学生实验报告时刻应在学生提交实验报告时刻后10日内。
附完整源码:
#include
#include
#include
#include
#include
usingnamespacestd;
constintmaxc=128;
typedeflonglongll;
charfilename[]="cacm.all";
llnum[maxc];
charcode[maxc][maxc];
chartemp[maxc];
structNode
{
boolisleaf;
charc;
lln;
Node*l,*r;
Node()
{
isleaf=false;
c=0;
n=0;
l=r=0;
}
}*o;
voidcount_char()
{
FILE*ffp=NULL;
FILE*fp=NULL;
charc;
//打开cacm.all文件
fp=fopen(filename,"r");
ffp=fopen("cacm.txt","w");
while(fread(&c,sizeof(c),1,fp))
{
num[(int)c]++;
fprintf(ffp,"%c",c);
}
fclose(fp);
fp=fopen("count.txt","w");
for(inti=0;ifprintf(fp,"%d%c%lld\n",i,i,num[i]);
fclose(fp);
fclose(ffp);
}
structcmp
{
booloperator()(Node*a,Node*b)const
{
//因为优先出列判定为!
cmp,所以反向定义实现最小值优先
returna->n>b->n;
}
};
voidget_Huffman_tree()
{
priority_queue,cmp>q;
for(inti=0;i{
Node*node=newNode();
node->isleaf=true;
node->c=i;
node->n=num[i];
q.push(node);
}
while(q.size()>1)
{
Node*x=q.top();
q.pop();
Node*y=q.top();
q.pop();
Node*z=newNode();
z->n=x->n+y->n;
z->l=x;
z->r=y;
q.push(z);
}
o=q.top();
q.pop();
}
voiddfs(Node*cur,intd)
{
if(cur->isleaf)
{
temp[d]=0;
strcpy(code[int(cur->c)],temp);
return;
}
temp[d]='0';
if(cur->l)dfs(cur->l,d+1);
temp[d]='1';
if(cur->r)dfs(cur->r,d+1);
}
voidget_Huffman_code()
{
dfs(o,0);
FILE*fp=NULL;
fp=fopen("code.txt","w");
for(inti=0;ifprintf(fp,"%-3d%c%s\n",i,i,code[i]);
fclose(fp);
}
intcnt;
intnumber;
FILE*ffp=NULL;
voidadd(charc)
{
cnt++;
number<<=1;
number+=c-'0';
if(cnt==32)
{
cnt=0;
fwrite(&number,sizeof(number),1,ffp);
number=0;
}
}
voidflush()
{
while(cnt&&cnt<32)
{
cnt++;
number<<=1;
}
cnt=0;
fwrite(&number,sizeof(number),1,ffp);
number=0;
}
voidencryption()
{
ffp=fopen("encryption.txt","wb");
FILE*fp=NULL;
charc;
fp=fopen(filename,"r");
//while((c=fgetc(fp))!
=EOF)
while(fread(&c,sizeof(c),1,fp))
{
intlen=strlen(code[(int)c]);
for(inti=0;iadd(code[(int)c][i]);
}
flush();
fclose(fp);
fclose(ffp);
}
intNUM;
intCNT;
FILE*FFP=NULL;
intnextd()
{
if(CNT==0)
{
if(fread(&NUM,sizeof(NUM),1,FFP)==0)return2;
CNT=32;
}
CNT--;
return(NUM&(1<>CNT;
}
voiddecode()
{
FFP=fopen("encryption.txt","rb");
FILE*fp=NULL;
fp=fopen("decode.txt","w");
Node*cur=o;
intd;
while((d=nextd())<2)
{
if(d==0)cur=cur->l;
elsecur=cur->r;
if(cur->isleaf)
{
fprintf(fp,"%c",cur->c);
//printf("%c",cur->c);
cur=o;
}
}
fclose(fp);
fclose(FFP);
}
voidprintInfo()
{
cout<<"*****************************************"<cout<<"**"<cout<<"*文本压缩工具*"<cout<<"*作者:
杨立滨*"<cout<<"*源文件:
cacm.all*"<cout<<"**"<cout<<"*****************************************"<}
intgetFileSize(char*file)
{
FILE*fp=NULL;
intnFileLen=0;
fp=fopen(file,"rb");
if(fp==NULL)
{
cout<<"can'topenfile"<return0;
}
fseek(fp,0,SEEK_END);//定位到文件末
nFileLen=ftell(fp);//文件长度
returnnFileLen;
}
intmain()
{
printInfo();
cout<count_char();
cout<get_Huffman_tree();
get_Huffman_code();
cout<doublestart=0,end=0;
start=clock();
encryption();//压缩
end=clock();
cout<<"压缩时间:
"<<(end-start)<<"ms"<intsize1=getFileSize("cacm.txt");
intsize2=getFileSize("encryption.txt");
cout<<"cacm.txt文件大小:
"<cout<<"encryption.txt文件大小:
"<cout<<"压缩率:
"<<1.0*size2/size1*100<<"%"<cout<1:
是2:
否"<inti;
cin>>i;
if(i==1){
cout<decode();//解压缩
}
cout<<"程序结束!
"<return0;
}