Huffman编码及译码
1.掌握二叉树的二叉链表存贮结构。
2.掌握Huffman算法。
要求:
使用文件保存初始的文本数据及最终的结果。
- 文件名为inputfile1.txt的文件保存的是一段英文短文;
- 文件名为inputfile2.txt的文件保存01形式的编码段;
- 文件名为outputfile1.txt的文件保存各字符的出现次数和对应的编码;
- 文件名为outputfile2.txt的文件保存对应于inputfile2.txt的译码结果。
统计inputfile1.txt中各字符的出现频率,并据此构造Huffman树,编制Huffman 码;根据已经得到的编码,对01形式的编码段进行译码。
具体的要求:
1.将给定字符文件编码,生成编码,输出每个字符出现的次数和编码;
2.将给定编码文件译码,生成字符,输出编码及其对应字符。
输入数据格式:
详见要求部分。
输出数据格式:
outputfile1.txt文件中:
字符 出现次数 对应的编码
a 37 010
b 130 00
outputfile2.txt文件中:
This is a example.
分析(如何构造哈夫曼树):
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;
(3)从森林中删除选取的两棵树,并将新树加入森林;
(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
如:对 下图中的六个带权叶子结点来构造一棵哈夫曼树,步骤如下(借用一下他人好看的图):
代码如下(vs2012):
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
struct Huffmannode {
int parent;
int lc;
int rc;
int weight;
};
class Huffmantree {
private:
Huffmannode*node;
char* letter;
int leafnum;
public:
Huffmantree();
~Huffmantree();
Huffmannode*Initialization(int sum, char z[], int w[]);
void Encord(Huffmannode*node, char tree[], int sum, char z[], int w[]);
void Decord(Huffmannode*node, int sum, char z[]);
};
Huffmantree::Huffmantree() {
node = NULL;
letter = NULL;
leafnum = 0;
}
Huffmantree::~Huffmantree() {
delete[]node;
delete[]letter;
}
Huffmannode*Huffmantree::Initialization(int sum, char z[], int w[]) {
int min1, min2;
int loc1, loc2;
node = new Huffmannode[2 * sum - 1];
letter = new char[2 * sum - 1];
for (int i = 0; i<sum; i++) {
letter[i] = z[i];
node[i].weight = w[i];
node[i].parent = -1;
node[i].lc = -1;
node[i].rc = -1;
}
for (int i = sum; i<2 * sum - 1; i++) {
loc1 = -1;
loc2 = -1;
min1 = 32767;
min2 = 32767;
for (int j = 0; j<i; j++) {
if (node[j].parent == -1) {
if (node[j].weight<min1) {
min2 = min1;
min1 = node[j].weight;
loc2 = loc1;
loc1 = j;
}
else {
if (node[j].weight<min2) {
min2 = node[j].weight;
loc2 = j;
}
}
}
}
node[loc1].parent = i;
node[loc2].parent = i;
node[i].lc = loc1;
node[i].rc = loc2;
node[i].parent = -1;
node[i].weight = node[loc1].weight + node[loc2].weight;
}
return node;
}
void Huffmantree::Encord(Huffmannode*node, char t[], int sum, char z[], int w[]) {
char* code;
code = new char[sum];
int m = 0;
int i, n = 0;
ofstream shuchu;
shuchu.open("outputfile1.txt", ios::app);
while (z[n] != '\0') {
int r, k = 0, q;
r = n;
q = n;
shuchu << z[n] << " " << w[n] << " ";
while (node[r].parent != -1) {
r = node[r].parent;
if (node[r].lc == q) {
code[k] = '0';
k++;
}
else {
code[k] = '1';
k++;
}
q = r;
}
code[k] = '\0';
k -= 1;
while (k >= 0) {
shuchu << code[k];
k--;
}
shuchu << '\n';
n++;
}
shuchu.close();
ofstream out;
out.open("inputfile2.txt", ios::app);
while (t[m] != '\0') {
int j, s = 0;
for (i = 0; i<sum; i++) {
if (t[m] == z[i])break;
}
j = i;
while (node[j].parent != -1) {
j = node[j].parent;
if (node[j].lc == i) {
code[s] = '0';
s++;
}
else {
code[s] = '1';
s++;
}
i = j;
}
code[s] = '\0';
s -= 1;
while (s >= 0) {
out << code[s];
s--;
}
m++;
}
out.close();
}
void Huffmantree::Decord(Huffmannode *node, int sum, char z[]) {
ifstream tree("inputfile2.txt");
int k = 0;
char *code = new char[1000];
while (!tree.eof()) {
tree >> code[k];
k++;
}
code[k] = '\0';
tree.close();
ofstream yima("outputfile2.txt", ios::app);
k = 0;
int j = 2 * sum - 1 - 1;
while (code[k + 1] != '\0') {
if (code[k] == '0') {
j = node[j].lc;
}
if (code[k] == '1') {
j = node[j].rc;
}
if (node[j].lc == -1) {
yima << z[j];
j = 2 * sum - 1 - 1;
}
k++;
}
yima.close();
}
int main() {
ifstream in("inputfile1.txt", ios::app);
char tree[1000] = { 0 };
char letter[100];
int count[100] = { 0 };
int i = 0, t = 0;
while (!in.eof()) {
tree[t] = in.get();
t++;
}
tree[t] = '\0';
int k = 0;
in.close();
while (tree[i] != '\0') {
int m = 0;
for (int j = 0; j<k; j++) {
if (tree[i] == letter[j]) {
count[j]++;
m = 1;
}
}
if (m == 0) {
letter[k] = tree[i];
count[k]++;
k++;
}
i++;
}
count[k] = '\0';
letter[k] = '\0';
Huffmantree tree1;
Huffmannode*node = tree1.Initialization(k, letter, count);
tree1.Encord(node, tree, k, letter, count);
tree1.Decord(node, k, letter);
}