实验目的:
(1) 掌握二叉树的定义;
(2) 掌握哈夫曼树和哈夫曼编码算法的实现。
实验内容:
实现一个哈夫曼编码系统,系统包括以下功能:
(1) 字符信息统计:读取待编码的源文件SourceFile.txt,统计出现的字符及其频率。
附:SourceFile.txt文件内容为
U ARE THE BEST IN MY HEART
(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中,直到所有的字符处理完毕为止。
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<cstdio>
#include<fstream>
#include<string>
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] = ' ';
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:000
B:0110
E:111
H:001
I:0111
M:1000
N:1001
R:010
S:1010
T:110
U:1011
ResultFile.txt
101100001011111000111101101111010110011110011000001111000010110