实验目的:
(1) 掌握二叉树的定义;
(2) 掌握哈夫曼树和哈夫曼编码算法的实现。
实验内容:
实现一个哈夫曼编码系统,系统包括以下功能:
(1) 字符信息统计:读取待编码的源文件SourceFile.txt,统计出现的字符及其频率。
附:SourceFile.txt文件内容为
AAAAABBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCDDDDDDDDEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFGGGHHHHHHHHHHH
(2) 建立哈夫曼树:根据统计结果建立哈夫曼树。
(3) 建立哈夫曼码表:利用得到的哈夫曼树,将各字符对应的编码表保存在文件Code.txt中。
(4) 对源文件进行编码:根据哈夫曼码表,将SourceFile.txt中的字符转换成相应的编码文件ResultFile.txt。
实现提示:
(1) 字符信息统计:假设源文件SourceFile.txt中的字符只有大小写英文字母(同一个字母的大小写看作一个字符),则字符统计算法的实现过程可以归纳为:先定义一个含有26个元素的整形数组,用来存储各个字母出现的次数,最后还要排除其中出现次数为0的数组元素。
(2) 建立哈夫曼树:参考教材算法5.10,补充函数Select的实现。
(3) 建立哈夫曼码表:参考教材算法5.11,将编译表HC中的内容写到文件Code.txt中。
(4) 对源文件进行编码:依次读入文件SourceFile.txt中的字符 c,在编码表 HC 中找到此字符,将字符c转换为编码表中存放的编码串,写入编码文件ResultFile.txt中,直到所有的字符处理完毕为止。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<fstream>
#include<iostream>
using namespace std;
typedef struct{
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
int a[24+1],b[24+1];
char c[24+1];
void Select(HuffmanTree &HT,int n,int &s1,int &s2){
for(int i=1;i<=n;i++)
if(HT[i].parent==0&&s1==0) {s1=i;break;}
for(int i=1;i<=n;i++)
if(HT[i].parent==0&&HT[i].weight<HT[s1].weight) s1=i;
for(int i=1;i<=n;i++)
if(HT[i].parent==0&&s2==0&&i!=s1) {s2=i;break;}
for(int i=1;i<=n;i++)
if(HT[i].parent==0&&HT[i].weight<HT[s2].weight&&i!=s1) s2=i;
}
void CreateHuffmanTree(HuffmanTree &HT,int n){
if(n<=1) return;
int m=2*n-1;//构造一棵哈夫曼树所需要的所有节点数
HT=new HTNode[m+1];//m+1指从第一个结点开始,第0个结点不用
for(int i=1;i<=m;i++){
HT[i].parent=0;
HT[i].lchild=0;
HT[i].rchild=0;
}
for(int i=1;i<=n;i++) HT[i].weight=b[i];//把字母出现的次数赋值给哈夫曼树的weight
for(int i=n+1;i<=m;i++){
int s1=0,s2=0;
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;
}
}
void CreateHuffmanCode(HuffmanTree &HT,HuffmanCode &HC,int n){
HC=new char*[n+1];
char *cd=new char[n];
cd[n-1]='\0';
for(int i=1;i<=n;i++){
int start=n-1,c=i,f=HT[i].parent;
while(f){
--start;
if(HT[f].lchild==c) cd[start]='0';
else cd[start]='1';
c=f;
f=HT[f].parent;
}
HC[i]=new char[n-start];
strcpy(HC[i],&cd[start]);
}
delete cd;
}
int main(){
freopen("SourceFile.txt","r",stdin);//打开输入文件
memset(a,0,sizeof(a));
string str;
getline(cin,str);//接收文件的字符串并保存到str中
for(int i=0;i<str.length();i++)//统计每个字母出现的频率即次数
a[str[i]-64]++;
int n=0;
for(int i=1,j=1;i<=24;i++)//统计有多少个不同的字母以及把没出现的字母去除掉
if(a[i]!=0){
n++;
b[j]=a[i];
c[j++]=i+64;
}
HuffmanTree HT;
HuffmanCode HC;
CreateHuffmanTree(HT,n);
CreateHuffmanCode(HT,HC,n);
freopen("Code.txt","w",stdout);
for(int i=1;i<=n;i++)
cout<<c[i]<<':'<<HC[i]<<endl;
freopen("ResultFile.txt","w",stdout);
for(int i=0;i<str.length();i++){
for(int j=1;j<=n;j++){
if(str[i]==c[j]) cout<<HC[j];
}
}
return 0;
}
输出结果:
字符对应的编码表保存在文件Code.txt,结果为:
A:0001
B:10
C:1110
D:1111
E:110
F:01
G:0000
H:001
根据哈夫曼码表,将SourceFile.txt中的字符转换成相应的编码文件ResultFile.txt,结果为:
0001000100010001000110101010101010101010101010101010101010101010101010111011101110111011101110111011111111111111111111111111111111110110110110110110110110110110110110110110010101010101010101010101010101010101010101000000000000001001001001001001001001001001001