huffman编码与解码实现文件压缩与解压缩文档格式.docx
- 文档编号:16192623
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:14
- 大小:172.78KB
huffman编码与解码实现文件压缩与解压缩文档格式.docx
《huffman编码与解码实现文件压缩与解压缩文档格式.docx》由会员分享,可在线阅读,更多相关《huffman编码与解码实现文件压缩与解压缩文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
;
//输出文件未翻开的标志
exit(0);
}
cout<
读入的文件中的内容为:
endl;
while((c=infile.get())!
=EOF)//EOF是文件结束的标志
cout<
(2)计所出现的字符个数
voidchar_add(charc)
{huff[count].data=c;
huff[count++].count++;
//个数增加}
(3)计每个字符出现的频率:
boolchar_judge(charc)
{for(inti=1;
i<
=count;
i++)
if(huff[i].data==c){huff[i].count++;
returntrue;
//如果出现过,出现的频数加1
returnfalse;
2.构造huffman树
解决了上述问题,接下来要考虑的是怎样去构造huffman树的问题,进行huffman编码,对文件进行压缩。
为了构造huffman树,我将每个字符出现的频率赋予huffman树中叶子结点的权值,从而构造huffman树,也即先查找两个权值最小的结点,合并为新的结点,并将新的结点存入数组中,继续比拟合并,最后形成huffman树。
利用构造好的huffman树,进行编码:
设需要编码的字符集合为{d1,d2,……,dn},各个字符在电文中出现的次数集合为{w1,w2,……,wn},以d1,d2,……,dn作为叶结点,以w1,w2,……,wn作为各叶子结点的权值构造一棵二叉树,规定HUFFMAN树中的左孩子结点为0,右孩子结点为1,那么从根结点到每个叶结点所经过的分支对应的0和1组成的序列便为该结点对应字符的编码。
这样的代码总长度最短的不等长编码就为HUFFMAN编码。
4.文件压缩问题
采用不等长编码,让出现频率高的字符具有较短的编码,让出现频率低的字符具有较长的编码,这样就能对文件进行压缩。
在计算机存储中,是以二进制来存储的,本来每个字符将占据8位,而通过huffman编码后,一个字符在计算机存储中,将占据的位数少于8位,这样将大大减少存储空间,从而实现对文件的压缩。
5.读入压缩文件,并对其解压。
对如何读取压缩文件,采用的方法大致和开始相同,在此不赘述。
为解压,利用构造好的huffman树,再根据读取的huffman编码文件,在huffman树中查找叶子结点,查找到叶子结点,放入另一个文本文档中,并输出。
其具体查找过程是从根结点开始,根据读入的二进制编码〔huffman1.txt中〕及生成的huffman树,查找叶子结点,当读到的是“0〞时,从左孩子结点继续查找,当读到“1〞时,那么从右孩子结点继续查找,直到找到叶子结点,其判断语句是看一个结点的左右孩子是否为空,如果是那么是,叶子结点找到,输入文件〔huffman2.txt〕中,如果不是那么继续查找,直到所有编码全部读完。
6.计算压缩比例
算法如下:
voidevaluating()
{floaty1;
y1=bitecount/8/remcount*100;
压缩比例是:
y1<
%"
三、详细设计和编码
核心算法---huffman算法:
〔1〕根据给定的n个权值{w1,w2,……,wn}构成n棵二叉树的集合F={T1,T2,……,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均空。
〔2〕在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左右子树上根结点的权值之和。
〔3〕在F中删除这两棵树,同时将所得到的二叉树参加F中。
〔4〕重复〔2〕和〔3〕,直到F只含一棵树为止。
这棵树便是huffman树。
huffman树可用于构造代码总长度最短的编码方案。
为了详细说明这个问题,特以下面例子来说明:
有四个叶子结点A,B,C,D,分别带权为9,4,5,2,可以构成许多种不同的带权二叉树,但各个带权二叉树的WPL〔树的带权路径长度〕不同,要想由n个带权叶子结点所构成的二叉树中,满二叉树或完全二叉树不一定是最优树。
权值越大的结点离根越近的二叉树才是最优二叉树〔huffman树〕。
按照上面的算法,那么可按照下面图的构造过程生成huffman树。
Huffman树产生流程:
以一例说明
Huffman编码流程:
Huffman解码流程:
四、上机调试
开始考虑问题是,要对文件进行压缩,如何才能到达比拟好的效果,那就是huffman编码是采用等长编码还是采用不等长问题,采用不等长编码要防止译码的二义性或多义性。
假设用0表示字符D,用01表示字符C那么当接受到编码串“…01…〞,并译到字符0时,是立即译出对应的字符D,还是接着与下一个字符1一起译为对应的字符C,这就产生了二义性。
因此,假设对某一个字符集进行不等长编码,那么要求字符集合中任一个字符的编码都不能是其他字符编码的前缀。
符合此要求的编码叫做前缀编码。
显然等长编码是前缀编码,这从等长编码所对应的编码二叉树也可以直接看出,任何一个叶子结点都不可能是其它叶子结点的双亲,也就是说,只有当一个结点是另一个结点的双亲时,该结点的字符编码才会是另一个结点的字符编码的前缀。
为了使不等长编码为前缀编码,可用该字符集中的每个字符作为叶子结点生成一棵编码二叉树,为了获得文件的最短长度,特将每个字符的出现频率作为字符结点的权值赋予该结点上,求出此树的最小带权路径长度就等于文件的最短长度。
因此,对文件进行压缩,就可以转化字符集中的所有字符作为叶子结点,字符出现的频率作为权值所产生的huffman树的问题。
根本思路大致有了后,接下来是对程序的编写工作,程序初步形成后,对其测试,发现了一些变量还没有声明的错误,对遗漏的变量进行了声明后,再次调试,发现一个比拟大的问题,就是字符都能读入,但是不能进行编码,也即不能构造huffman树,最后经过检查发现原来是结点方面存在问题,最后参加sum=2*count-1;
语句,问题得到解决。
〔该语句的作用是:
例如提供了3个权值不同的结点,现在要构造huffman树,那就需要5个结点。
〕
五、用户使用说明
用户运行本程序前,首先要在起工程文件下建立一个名字为Huffman.txt文本文档,再运行本程序后,第一步,按任意键来读取建立的Huffman.txt文本文档,再据程序中提示完成第二步操作,也即是讲压缩的文件以Huffman编码放入一个由用户自己建立的文本文档中,接着再根据提示完成第三步操作,即对要压缩的文件解压后放入由用户建立的任意名的文本文档中,由此完成操作。
六、测试结果
被编码〔局部字符〕:
被解码〔局部文件〕:
七、参考书目
[1]徐孝凯.数据结构实用教程(c/c++描述)[M].北京:
清华大学出版社,2006年6月
[2]郑莉等.c++语言程序设计(第三版)[M].北京:
清华大学出版社,2003年12月
八、附录
#include<
iostream>
fstream>
string>
iomanip>
usingnamespacestd;
stringremfile[600000];
//存放原文件字符的数组
intremcount=0;
//记录元素个数
floatbitecount=0;
//记录二进制码的个数
structhuffchar{//存放读入字符的类
intcount;
//字符出现的个数
chardata;
//字符};
intcount=1;
//记录huff数组中字符实际出现的个数
huffcharhuff[1000];
//类的对象
//文件读入局部和统计字符出现的频率
boolchar_judge(charc)//判断字符出现的函数
{
for(inti=1;
if(huff[i].data==c){huff[i].count++;
}//如果出现过,出现的频数加1
returnfalse;
voidchar_add(charc)//添加新出现的字符;
huff[count++].count++;
//个数增加
//文件的读取
ifstreaminfile;
{cout<
}
{remfile[++remcount]=c;
//recount记录元素个数
if(!
char_judge(c))
char_add(c);
}//文件读入和统计字符出现频率局部结束
//构造huffman树程序局部
structhuff_tree{//huffman树结点定义
intparent;
intlchild;
intrchild;
intweight;
//权值};
intsum;
//huffman树中结点的个数
huff_treehuffman[1000];
voidcreathuffman()//构造huffman树的函数
{intmin1,min2;
//指示权值最小
intloc1,loc2;
//指向权值最小的两个数的位置
=sum;
{//对huffman树的结点进行初始化
huffman[i].parent=0;
huffman[i].lchild=0;
huffman[i].rchild=0;
huffman[i].weight=0;
for(intm=1;
m<
count;
m++)//将权值赋给huffman[].weight
huffman[m].weight=huff[m].count;
sum=2*count-1;
for(intj=count;
j<
j++)
{loc1=loc2=0;
//权值最小的
min1=min2=20000;
for(intk=1;
k<
=j-1;
k++)//求权值最小的两个地址
if(huffman[k].parent==0)
if(huffman[k].weight<
=min1)
{min2=min1;
min1=huffman[k].weight;
loc2=loc1;
loc1=k;
else
=min2)
{min2=huffman[k].weight;
loc2=k;
//将求出的两个权值最小的结点合并为新的结点,并将新的结点存入数组中
huffman[loc1].parent=j;
huffman[loc2].parent=j;
huffman[j].lchild=loc1;
huffman[j].rchild=loc2;
huffman[j].weight=huffman[loc1].weight+huffman[loc2].weight;
//计算新结点的权值}}
//构造huffman树的程序局部结束
//huffman编码开始
structhuffcode{//编码结构体
stringbits[100];
//存放解码
stringc;
//存放字符};
huffcodehcode[100];
voidhuffmancode()//编码函数
{intrem,p;
intcount1=0;
for(inty=1;
y<
y++)
{//编码局部
rem=y;
hcode[y].c=huff[y].data;
p=huffman[y].parent;
while(p!
=0)
{if(huffman[p].lchild==rem)
hcode[y].bits[++count1]='
0'
elsehcode[y].bits[++count1]='
1'
rem=p;
p=huffman[p].parent;
hcode[y].count=count1;
count1=0;
for(intt=1;
t<
t++)//输出所编的码
字符"
hcode[t].c<
编码:
"
intr=hcode[t].count;
while(r)
hcode[t].bits[r--];
}}
stringstr;
voidcode_huffman_file()
{ofstreamfp;
请输入文件名"
endl<
例如:
huffman1.txt"
该文件用来存放编码后的文件即压缩文件"
cin>
>
str;
fp.open(str.c_str());
fp)//检查文件是否翻开
不能翻开"
str<
文件"
for(intj=1;
=remcount;
{for(inti=1;
if(remfile[j]==hcode[i].c)
{for(intk=hcode[i].count;
k>
0;
k--)
{fp<
hcode[i].bits[k];
bitecount++;
break;
}}
fp.close();
}//编码,并将编码存入文件局部结束
voidcode_file_out()//将编码过的文件恢复
{ifstreamfp1;
//编码文件
ofstreamfp2;
//解压缩文件
fp1.open(str.c_str());
fp1)//检查文件是否翻开
charinchar;
huffman2.txt"
该文件存放解压缩后的文件"
strings1;
s1;
fp2.open(s1.c_str());
fp2)//检查文件是否翻开
不能翻开"
s1<
for(intptr=sum;
!
fp1.eof();
)//将编码转为字符输入的到文件中
{fp1>
inchar;
if(inchar=='
)
ptr=huffman[ptr].rchild;
//查找相应编码对应huffman树中的位置
elseptr=huffman[ptr].lchild;
if(huffman[ptr].lchild==0&
&
huffman[ptr].rchild==0)
//判断是否为叶子结点
{fp2<
huff[ptr].data;
ptr=sum;
//是叶子结点,将该结点的对应字符输入到文件中
请检查原文件"
huffman.txt"
与解压缩文件"
*******************************请检查*************************************"
}//解压缩文件局部结束
//计算压缩比例
y1=bitecount/8/remcount*100;
voidmain()
数据结构课程设计"
Huffman树文件压缩与解压缩"
*******************************************************"
system("
pause"
);
read_file_count();
creathuffman();
huffmancode();
code_huffman_file();
code_file_out();
evaluating();
文件的压缩与解压缩完成"
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- huffman 编码 解码 实现 文件 压缩 解压缩