基于Huffman赫夫曼编码的文本压缩程序Word下载.docx
- 文档编号:20571013
- 上传时间:2023-01-24
- 格式:DOCX
- 页数:24
- 大小:233.57KB
基于Huffman赫夫曼编码的文本压缩程序Word下载.docx
《基于Huffman赫夫曼编码的文本压缩程序Word下载.docx》由会员分享,可在线阅读,更多相关《基于Huffman赫夫曼编码的文本压缩程序Word下载.docx(24页珍藏版)》请在冰豆网上搜索。
打开要压缩的文本文件,读取文件中的字符,统计文件中不同字符出现的频率,建立赫夫曼树,通过赫夫曼树对出现的互不相同的字符进行编码,建立编码表,接着将将赫夫曼树(即解码表)写入压缩文件中。
再次重新读取文件中的字符,对每个字符通过查阅编码表确定对应的编码,将该字符的赫夫曼编码写入压缩文件。
对压缩文件的解压过程为:
打开压缩文件,读取压缩文件解码表部分,读取压缩文件的编码数据,将压缩数据通过解码表进行解码,将解码出的字符写入解码文件中。
程序执行后,用户按照程序的提示选择相应的功能选项。
当用户选择压缩功能,此时程序要求用户输入要压缩的文本文件的路径,用户输入完成后。
程序检查文件是否能够建立。
检查完成后,程序将文件从硬盘读入内存。
接着程序将统计不同字符出现的频率以及建立编码表的初步结构。
例如当文件中存有如下表所示字符。
表1文件字符属性表
字符
第一字节机内码/ASCII
第二字节机内码
权重
的
181
196
20
a
97
9
把
176
209
14
表
177
237
5
班
224
1
补
178
185
2
百
214
17
防
183
192
12
飞
201
博
169
13
包
252
才
197
6
方
189
8
拜
221
3
A
65
份
必
216
英文字符在计算机中是以标准ASCII码进行表示,一个英文字符占一个字节空间,编码范围为0~127;
汉字在计算机中是以GB2312编码进行表示。
每个汉字占两个字节存储空间,汉字的存储使用机内码,各字节的机内码编码范围为160~254。
现在需要考虑使用怎样的数据结构来存放这些字符,如果采用如下简单的数据结构存放:
typedefstruct
{
chardata[3];
//存放字符
intinternal_code1;
//存放第一字节的机内码/ASCII码
intinternal_code2;
//存放第二字节的机内码,英文默认为0
intweight;
//存放字符的权重
char*code;
//字符的赫夫曼编码
}CodeList,*CodePList;
分析所要处理的字符数据会发现:
许多的字符的第一字节的机内码相同,如“防”、“飞”、“方”、“份”,第一字节机内码都是183。
这是因为汉字是通过划分区号和位号来表示的,所有汉字被划分成了94个区,94个位,所以当汉字属于同一个区,那么它的第一字节机内码就会相同。
如果采用如上的数据结构建立的线性表来存放处理字符,就会存在大量数据冗余。
在这种情况下,就有必要为特定的数据设计合适的数据结构。
通过分析,采用如下数据结构:
charinternal_code;
//存放第二字节机内码
char*code;
//存放字符的赫夫曼编码
}InternalCode;
intcount;
//已编码字符数
//存放第一字节机内码
InternalCode*internal_code_address;
//第二字节机内码及字符的
}HuffmanCode,*HuffmanPCode;
//赫夫曼编码的地址
该结构的优点:
当汉字的第一字节机内码相同,则该第一字节机内码只会被存储一次,从而消除汉字第一字节机内码存储的冗余,而且可以方便的使用折半查找快速检索编码表来确定字符的赫夫曼编码。
采用该数据结构对表1数据进行表示如图1。
图1编码表HC的存储结构
这种数据结构形式上类似于图的邻接表结构,功能上类似于哈希表的链地址法。
但邻接表的表结点采用链式存储,而图1的表结点和头结点都采用线性表储存。
图1中编码表HC的内码1是纵向非递减排列,内码2是横向非递减排列。
HC[i].count–HC[i–1].count等于HC[i]实际存储的字符数量。
例如,HC[3]中字符数为7,HC[2]中字符数为2,则HC[3]存放了5个字符,这5个字符拥有相同的第一字节机内码176。
程序执行压缩操作详细过程:
当程序从文件中读取一个字符后,通过字符的编码范围分析该字符是属于ASCII还是GB2312,若是ASCII编码,增加编码表HC纵向表长,将该字符的ASCII码按非递减次序插入到内码1处,并将当前位置的字符数加1,并置内码2默认为0;
如果是汉字,首先通过折半查找算法纵向查找编码表HC的内码1成员,若当前汉字第一字节机内码已经出现过,则折半查找返回该机内码1在HC表中的位置,增加当前位置的横向表长,将汉字的第二字节机内码按非递减次序插入当前位置的内码2处。
否则将汉字的第一字节机内码按非递减次序插入HC表的内码1区域,第二字节机内码直接插入内码2处。
在读取文件的同时记录文件中各字符出现的频率,当编码表HC表构建完成,此时w={3,9,14,3,1,2,17,5,5,13,2,6,20,9,8,5,12}。
依次从w中选择权重最小并且双亲为0的两个结点,根据这两个结点生成新的结点,新结点的权重为这两个最小结点的和,新结点的左右子树为这两个结点在w中的位置。
根据表1数据构建赫夫曼树如图2所示。
赫夫曼树存储结构的初始状态如图3(a),终结状态如图3(b)。
图2根据表1构造的赫夫曼树
图3(a)HT初始状态图3(b)HT终止状态
根据生成的赫夫曼树对HC表中的字符进行编码,编码的方法:
从该叶子到根逆向求该字符的编码。
例如图2中“把”的权值为14,对应的编码为:
“000”。
将得到的赫夫曼编码写入HC[i].internal_code_address[j].code指向的区域。
当字符编码完成之后,打开压缩文件,将赫夫曼树HT中除权重以外的数据(解码无需权重信息)写入压缩文件中,作为下一次解压缩的解码表。
再次打开要压缩的文本文件,读取文件中的字符,根据编码的范围确定该字符是ASCII还是GB2312,如果ASCII则调用折半查找函数,在编码表HC中进行纵向查找,查找此ASCII出现的位置p1,该字符的编码为HC[p1].internal_code_address[1].code;
如果字符是汉字,则调用折半查找先纵向查找该汉字的第一字节机内码在HC中的位置p1,然后从HC[p1].internal_code_address开始横向查找该汉字的第二字节机内码的位置p2,这样就得到了该汉字的赫夫曼编码为HC[p1].internal_code_address[p2].code因为赫夫曼编码在HC表中是以字符串形式存放(因为计算机的基本储单位是字节,如果以位存放,需要另设一个空间来表示未编码的位空间大小)。
所以需要将字符串“0101“转换为二进制0101写入文件。
因为每个赫夫曼编码的长度是不一样的,假设某字符的赫夫曼长度为4,则将该编码写入一个字节后,还剩余4个位,则下一次可以继续从第5个位开始写入,当所有字符的编码都写入完毕后,最后一个字节并不一定会用完,所以需要附设一个字节来记录最后一个字符编码实际写入的编码位数。
编码文件的结构如下图所示:
图4压缩文件存储结构
程序解压文件:
打开压缩文件,取出压缩文件的解码表长度N,根据N读取N条解码表记录,重建解码表HT,然后读取压缩数据DATA,解码的过程是从根出发,按DATA数据的0或1确定找左子树还是右子树,直至叶子结点,便求得了DATA相应的字符。
将字符写入文件,直至所有DATA数据处理完毕,整个解压过程结束。
三、程序源代码
1.头文件CourseDesign.h
#ifndef_COURSEDESIGN_H_
#define_COURSEDESIGN_H_
//-----Huffman树存储结构
charch[3];
unsignedintweight;
unsignedintparent,lchild,rchild;
}HTNode,*HuffmanTree;
//----Huffman编码表存储结构
charinternal_code;
//-------解码表存储结构
unsignedintlchild,rchild;
}DecodeList,*DecodePList;
//------辅助数组,置/取一个字节的指定位
conststaticunsignedcharmask[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
template<
classT>
staticintSearch_Bin(intkey,TL,intlow,inthigh);
staticvoidInsertSort(TL,intstart,intend);
voidSelect(constHuffmanTreeHT,intn,int&
s1,int&
s2);
voidStatistics(HuffmanPCode&
HC,intinternal_code1,intinternal_code2,int(*FrequencyMeter)[255],int&
n);
boolInit(char*filename,HuffmanPCode&
HC,int*&
w,int&
voidCreateHuffmanTree(HuffmanTree&
HT,constHuffmanPCodeHC,constint*w,intn);
voidHuffmanCoding(constHuffmanTreeHT,HuffmanPCodeHC,intn);
boolCompress(char*ifilename,char*ofilename,constHuffmanPCodeHC,constHuffmanTreeHT,intn);
boolDeCompress(char*ifilename,char*ofilename);
voidInterface();
#endif
2.函数实现文件CourseDesign.cpp
#include"
CourseDesign.h"
#include<
iostream>
fstream>
iomanip>
malloc.h>
string.h>
usingnamespacestd;
//-----------折半查找----------------
intSearch_Bin(intkey,TL,intlow,inthigh)
intmid=0;
intinternal_code;
while(low<
=high)
{
mid=(low+high)/2;
internal_code=int(L[mid].internal_code&
0xFF);
if(key==internal_code)
{
returnmid;
}
elseif(internal_code>
key)
high=mid-1;
else
low=mid+1;
}
return0;
}
//--------对HC表的字符域做插入非递减排序-----
voidInsertSort(TL,intstart,intend)
inti;
L[0]=L[end];
i=end-1;
while(i>
=start&
&
int(L[i].internal_code&
0xFF)>
int(L[0].internal_code&
0xFF))
L[i+1]=L[i];
i--;
L[i+1]=L[0];
//-------寻找权重最小的两个结点----------------------
s2)
inti=0;
s1=s2=0;
for(i=1;
i<
=n;
++i)
if(HT[i].parent==0)
if(s1==0)
{
s1=i;
}
elseif(s2==0)
s2=i;
elseif(HT[i].weight<
HT[s1].weight||HT[i].weight<
HT[s2].weight)
s1=HT[s1].weight<
HT[s2].weight?
s1:
s2;
//----构建HC.internal_code以及HC.internal_code_address结构-------------
n)
intposition;
if(internal_code1<
128)
if(FrequencyMeter[internal_code1][0]==0)
++n;
HC=(HuffmanPCode)realloc(HC,(n+1)*sizeof(HuffmanCode));
HC[n].internal_code=internal_code1;
HC[n].count=1;
HC[n].internal_code_address=(InternalCode*)malloc(2*sizeof(InternalCode));
HC[n].internal_code_address[1].internal_code=0;
//0号单元未用
InsertSort(HC,1,n);
++FrequencyMeter[internal_code1][0];
else
if(FrequencyMeter[internal_code1][internal_code2]==0)
position=Search_Bin(internal_code1,HC,1,n);
if(position!
=0)
++HC[position].count;
HC[position].internal_code_address=(InternalCode*)realloc(HC[position].internal_code_address,(HC[position].count+1)*sizeof(InternalCode));
HC[position].internal_code_address[HC[position].count].internal_code=internal_code2;
InsertSort(HC[position].internal_code_address,1,HC[position].count);
else
++n;
HC=(HuffmanPCode)realloc(HC,(n+1)*sizeof(HuffmanCode));
HC[n].internal_code=internal_code1;
HC[n].count=1;
HC[n].internal_code_address=(InternalCode*)malloc(2*sizeof(InternalCode));
HC[n].internal_code_address[1].internal_code=internal_code2;
InsertSort(HC,1,n);
++FrequencyMeter[internal_code1][internal_code2];
//--------统计不同字符出现的频率以及构建HC的机内码成员结构-------
ifstreamifs(filename);
inti=0,j=0;
intFrequencyMeter[255][255]={0};
charch1,ch2;
n=0;
HC=NULL;
w=NULL;
if(ifs.fail())
cout<
<
"
can'
topenfile!
endl;
returnfalse;
while((ch1=ifs.get())!
=EOF)
if(int(ch1&
ch2=ifs.get();
ch2=0;
Statistics(HC,int(ch1&
0xFF),int(ch2&
0xFF),FrequencyMeter,n);
HC[0].count=0;
for(i=2;
++i)HC[i].count+=HC[i-1].count;
w=(int*)malloc(HC[n].count*sizeof(int));
for(j=HC[i-1].count;
j<
HC[i].count;
++j)
w[j]=FrequencyMeter[int(HC[i].internal_code&
0xFF)][int(HC[i].internal_code_address[j-HC[i-1].count+1].internal_code&
0xFF)];
ifs.close();
returntrue;
//--------构造赫夫曼树HT---------------------
HT,constHuffmanPCodeHC,constint*w,intn)
intm=0,s1=0,s2=0;
if(HC[n].count<
=1)return;
m=2*HC[n].count-1;
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
for(j=HC[i-1].count+1;
=HC[i].count;
++j,++w)
HT[j].ch[0]=HC[i].internal_code;
HT[j].ch[1]=HC[i].internal_code_address[j-HC[i-1].count].internal_code;
HT[j].ch[2]='
\0'
;
HT[j].weight=*w;
HT[j].lchild=HT[j].rchild=HT[j].parent=0;
for(i=HC[n].count+1;
=m;
*HT[i].ch=0;
HT[i].weight=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基于 Huffman 赫夫曼 编码 文本 压缩 程序