哈夫曼压缩Word文档下载推荐.docx
- 文档编号:19625941
- 上传时间:2023-01-08
- 格式:DOCX
- 页数:15
- 大小:68.28KB
哈夫曼压缩Word文档下载推荐.docx
《哈夫曼压缩Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《哈夫曼压缩Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
4.1.3还原为原文件9
4.1.4退出10
4.2分析10
5.参考文献.11
1设计内容及要求
1.1内容
设计目标是要实现哈夫曼压缩的编码器和译码器。
码器工作如下:
首先读入待压缩文件为了保证与原文件信息完全一致,对文件的读写都采用二进制的方式进行。
然后建立并分析字母表,最多只有256种可能的符,对每种字符出现的频度进行统计,以频度作为建立哈夫曼树的权值。
频度表建立好以后,可以建立哈夫曼树,对出现的每种字符进行哈夫曼编码。
此时再读入原文件,逐个字节进行编码,将得到的编码流逐个写入文件。
译码过程相对简单:
读入被压缩文件,将其解释为比特流,根据哈夫曼树对比特流逐个译码,将译码结果逐个写到磁盘文件。
1.2要求
准备一个文件,统计该文件中各种字符的频率,对各字符进行Huffman编码,将该文件翻译成Huffman编码文件,再将Huffman编码文件翻译成源文件。
2概要设计
2.1函数结构设计
在head.h文件中共有3个函数,分别为:
voidSelect(intk,int&
s1,int&
s2)
voidcompress()
voiduncompress()
其中voidSelect(intk,int&
s2)是在voidcompress()中调用的,他的功能是在K个元素中选择权值最小的两个结点S1,S2;
voidcompress()和voiduncompress()是在a.cpp的main函数中被调用的,他们的功能分别是压缩和解压缩。
函数结构图如下:
2.2数据结构设计
哈夫曼算法的实现可以采用链表结构生成哈夫曼树,但是效率比较低,也可以使用堆排序,这里采用的是线形表的顺序存储结构:
structhead
{
unsignedcharb;
//记录字符在数组中的位置
longcount;
//字符出现频率(权值)
longparent,lch,rch;
//定义哈夫曼树指针变量
charbits[256];
//定义存储哈夫曼编码的数组
}
该存储结构在二叉树中的结点结构如下:
b
count
parent
lch
rch
bits
3设计过程或程序代码
功能设计
3.1compress函数:
该函数将完成压缩目标文件的功能,首先输入文件名,读取目标文件ifp=fopen(filename,"
rb"
),这里”rb”是按二进制方式进行读操作,输入压缩后的文件名fopen(outputfile,"
wb"
),其中”wb”是打开或建立一个二进制文件,只允许写数据。
(filename为需要压缩的文件名,outputfile为完成压缩后的文件名)
while(!
feof(ifp))
{
fread(&
c,1,1,ifp);
fread(buffer,size,count,fp),
header[c].count++;
//字符重复出现频率加1
flength++;
//出现字符则原文长度加1
}
feof()为文件检测函数,若文件没有结束返回是0,当文件结束时返回1。
fread()是从一个流中读数据,fread(buffer,size,count,fp),其中buffer是一个指针,在fread函数中,它表示存放输入数据的首地址。
size表示数据块的字节数。
count表示要读写的数据块块数。
fp表示文件指针。
for(i=0;
i<
512;
i++)
if(header[i].count!
=0)header[i].b=(unsignedchar)i;
//如果该字符出现过,将他的哈夫曼码值及其对应的ASCII码存放在一维数组header[i]中,且编码表中的下标和ASCII码满足顺序存放关系。
elseheader[i].b=0;
header[i].parent=header[i].lch=header[i].rch=-1;
//是对结点进行初始化。
}
3.2建立哈夫曼树:
for(i=0;
256;
i++)//根据频率(权值)大小,对结点进行排序,选择较小的结点进树。
for(j=i+1;
j<
j++)
{
if(header[i].count<
header[j].count)
{
tmp=header[i];
header[i]=header[j];
header[j]=tmp;
}
}
}
根据哈夫曼树的性质,n个叶子结点(权)需要2n-1个结点来构建一棵哈夫曼树:
for(i=n;
m;
Select(i-1,s1,s2);
header[s1].parent=header[s2].parent=i;
header[i].lch=s1;
header[i].rch=s2;
header[i].count=header[s1].count+header[s2].count;
header[i].lch=s1;
//计算左分支权值大小;
header[i].rch=s2;
//计算右分支权值大小;
header[s1].parent=header[s2].parent=i;
//依据parent域值(结点层数)确定树中结点之间的关系;
header[i].count=header[s1].count+header[s2].count;
//父结点的权值为其左孩子和右孩子权值之和;
构建哈夫曼树时用到了一个Select()函数:
在K个元素中选择父结点不为-1的权值最小的两个结点S1,S2;
{
s1,s2=0;
longmin1=9999999;
for(intj=1;
k;
if(header[j].parent!
=-1)
if(header[j].count<
header[s1].count)
s2=s1;
s1=j;
}
elseif(header[j].count<
header[s2].count)
s2=j;
}
longmin1=9999999;
假设字符出现频率的最大值(最大权值),比较如下图:
j=1,s1=s2=0
0
1
2
3
4
5
……
j=1,s1=0,header[j].count<
header[s1].count
j=2,s1=1,header[j].count<
j=3,s1=2,header[j].count<
header[s2].count
哈夫曼无重复前缀编码:
n;
f=i;
header[i].bits[0]=0;
while(header[f].parent!
j=f;
f=header[f].parent;
if(header[f].lch==j)//置左分支编码0;
j=strlen(header[i].bits);
memmove(header[i].bits+1,header[i].bits,j+1);
//依次存储连接”0””1”编码;
header[i].bits[0]='
0'
;
else//置右分支编码1
1'
其中header[i].bits[0]=0;
根结点编码0。
将编码好的数据写入文件:
fseek(ifp,0,SEEK_SET);
从文件开始位置向前移动0字节,即定位到文件开始位置。
fwrite(&
flength,sizeof(int),1,ofp);
用来将数据写入文件流中,参数flength指向欲写入的数据地址,总共写入的字符数以参数size*int来决定,返回实际写入的int数目;
buf[0]=0;
定义缓冲区,它的二进制表示00000000。
while(!
feof(ifp))
c=fgetc(ifp);
f++;
if(c==header[i].b)break;
strcat(buf,header[i].bits);
j=strlen(buf);
c=0;
下面对哈夫曼编码位操作进行压缩存储:
while(j>
=8)
for(i=0;
8;
if(buf[i]=='
)c=(c<
<
1)|1;
elsec=c<
1;
fwrite(&
c,1,1,ofp);
pt1++;
strcpy(buf,buf+8);
if(f==flength)break;
其中strcpy(buf,buf+8);
是将一个字节一个字节地拼接起来,pt1是统计压缩以后文件长度的。
对哈夫曼编码位操作进行压缩存储:
if(j>
0)
strcat(buf,"
00000000"
);
if(buf[i]=='
fwrite(&
数据写入:
(header[i].b),1,1,ofp);
c=strlen(header[i].bits);
fwrite(&
j=strlen(header[i].bits);
if(j%8!
=0)若存储的位数不是8的倍数,则补0;
for(f=j%8;
f<
f++)
strcat(header[i].bits,"
0"
while(header[i].bits[0]!
=0)
c=0;
for(j=0;
j++)//字符的有效存储不超过8位,则对有效位数左移实现两字符编码的连接
if(header[i].bits[j]=='
//|1不改变原位置上的"
"
1"
值;
strcpy(header[i].bits,header[i].bits+8);
//把字符的编码按原先存储顺序连接。
3.3uncompress函数:
该函数完成的功能是将一个目标压缩文件解压还原,首先输入文件名,读取目标文件ifp=fopen(filename,"
fread(&
flength,sizeof(long),1,ifp);
读取原文件长度,对文件进行定位。
f,sizeof(long),1,ifp);
fseek(ifp,f,SEEK_SET);
n,sizeof(long),1,ifp);
header[i].b,1,1,ifp);
fread(&
p=(long)c;
读取原文件字符的权值;
header[i].count=p;
if(p%8>
0)m=p/8+1;
elsem=p/8;
j++)
fread(&
f=c;
itoa(f,buf,2);
//将f转换为二进制表示的字符串
f=strlen(buf);
for(l=8;
l>
f;
l--)
strcat(header[i].bits,buf);
header[i].bits[p]=0;
i++)//根据哈夫曼编码的长短,对结点进行排序:
for(j=i+1;
if(strlen(header[i].bits)>
strlen(header[j].bits))
tmp=header[i];
header[i]=header[j];
header[j]=tmp;
解码:
通过哈夫曼编码的长短,依次解码,从原来的位存储还原到字节存储
while
(1)
while(strlen(bx)<
(unsignedint)p)
l--)//在单字节内对相应位置补0
strcat(bx,"
strcat(bx,buf);
for(i=0;
if(memcmp(header[i].bits,bx,header[i].count)==0)break;
strcpy(bx,bx+header[i].count);
//从压缩文件中的按位存储还原到按字节存储字符,字符位置不改变;
c=header[i].b;
m++;
//m是用来统计解压后的文件长度
if(m==flength)break;
//flength是原文件长度;
fclose(ifp);
fclose(ofp);
关闭文件。
4设计结果与分析
4.1程序运行截图:
4.1.1原始菜单界面:
4.1.2压缩目标文件:
需要实现压缩功能时请按提示输入“1”,压缩的目标文件自备,需要手动输入,压缩后的文件名同理,见图:
4.1.3还原为原文件:
需要实现解压功能时请按提示输入选择“2”,解压的目标文件自备,需要手动输入,解压后的文件名同理,见图:
4.1.4退出:
需要推出操作时请按提示输入“0”,见图:
3
4
4.2分析
1.静态哈夫曼编码方法有一些缺点:
对于过短的文件进行编码的意义不大,因为光以4BYTES的长度存储哈夫曼树的信息就需1024Bytes的存储空间;
2.对较大的文件进行编码时,频繁的磁盘读写访问会降低数据编码的速度。
经过网上查询已经有了改进之法--动态的哈夫曼编码方法。
动态哈夫曼编码使用一棵动态变化的哈夫曼树,对第t+1个字符的编码是根据原始数据中前t个字符得到的哈夫曼树来进行的,编码和解码使用相同的初始哈夫曼树,每处理完一个字符,编码和解码使用相同的方法修改哈夫曼树,所以没有必要为解码而保存哈夫曼树的信息。
编码和解码一个字符所需的时间与该字符的编码长度成正比,所以动态哈夫曼编码可实时进行。
动态哈夫曼编码比静态哈夫曼编码复杂的多;
3.哈夫曼树是哈夫曼编码的应用,也是编码和译码的核心,是连接编码和译码的纽带。
该压缩软件采用的正是哈夫曼算法,建立哈夫曼树,对原文件中的字符进行哈夫曼编码,通过将哈夫曼算法应用与压缩软件,更进一步理解哈夫曼树的建立和对各个叶子结点的编码。
哈夫曼压缩技术对文本文件压缩效率很高,对于2进制文件这种方法也很成功,但压缩比没有那么显著;
4.编码不是唯一的,但用你的代码算出来的是唯一的,所以传输一定要用自己的代码解码,构造好哈夫曼树后,就可根据哈夫曼树进行编码。
例如:
字符根据其出现的概率作为权值构造一棵哈夫曼树后,经哈夫曼编码得到的对应的码值。
只要使用同一棵哈夫曼树,就可把编码还原成原来那组字符;
5.该程序中因为涉及文件操作,多次读写文件,为了保证操作后的文件与原文件的一致性,在打开或者建立新文件时都是以二进制进行操作,这不仅加深了我们对文件操作的理解,也在程序中体现了完整性,并且将解压后的文件和原文件相比较具有一致性,体现的程序的健壮性。
5参考文献
[1]谭浩强.C程序设计[M].3版.北京:
清华大学出版社,2005
[2]王晓东.数据结构(STL框架).北京:
清华大学出版社,2009.9
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 哈夫曼 压缩