哈夫曼编码就是根据不同字符出现的概率构建最优二叉树,生成最优前缀码,也就是每个字符的哈夫曼编码(二进制数)。
哈夫曼编码生成的过程是利用哈夫曼算法创建最优二叉树,在最优二叉树的左子树标0,右子树标为1,从树根遍历到树叶得到的二进制数就是该字符的哈弗曼编码。并且哈夫曼编码不是唯一的,因为当有两个字符概率相等时,树叶所代表的的字符并不是固定的,所以从树根到树叶的路径也不是唯一的,所以哈夫曼编码不是唯一的。
#include "pch.h"
#include <iostream>
#include<string>
using namespace std;
struct HuffmanTree
{
double weight; //权值
string ch; //存放字符
string code; //存放编码
int parent, lchild, rchild;
};
void Select(HuffmanTree *HT, int *s_1, int *s_2, int end) //选择出最小的两个权
{
double min_1, min_2, min;
int i = 0;
while (i < end && (HT + i)->parent != -1)
{
i++;
}
min_1 = (HT + i)->weight;
*s_1 = i;
i++;
while (i < end && (HT + i)->parent != -1)
{
i++;
}
min_2 = (HT + i)->weight;
*s_2 = i;
i++;
int *s;
if (min_1 >= min_2) //min_1是最小的
{
min = min_1;
min_1 = min_2;
min_2 = min;
s = s_1;
s_1 = s_2;
s_2 = s;
}
while (i < end )
{
if ((HT + i)->weight < min_1 && (HT + i)->parent == -1)
{
min_2 = min_1;
*s_2 = *s_1;
min_1 = (HT + i)->weight;
*s_1 = i;
}
else if ((HT + i)->weight < min_2 && (HT + i)->weight >= min_1 && (HT + i)->parent == -1)
{
min_2 = (HT + i)->weight;
*s_2 = i;
}
i++;
}
}
void SetHuffmanTree(HuffmanTree *HT, int n,char c[])
{
int weight;
string c1;
int i_1, i_2;
for (int i = 0; i < n; i++)
{
cin >> weight;
// cin >> c1;
(HT + i)->weight = weight;
(HT + i)->parent = -1;
(HT + i)->lchild = -1;
(HT + i)->rchild = -1;
(HT + i)->code = "";
(HT + i)->ch = c[i];
}
for (int i = n; i < 2 * n - 1; i++)
{
(HT + i)->parent = -1;
Select(HT, &i_1, &i_2, i);
(HT + i)->weight = (HT + i_1)->weight + (HT + i_2)->weight;
(HT + i_1)->parent = i;
(HT + i_2)->parent = i;
(HT + i)->lchild = i_1;
(HT + i)->rchild = i_2;
}
(HT + 2 * n - 2)->parent = -1;
}
void Huffman_Code(HuffmanTree *HT, int n) //编码
{
int i, j, k;
string str = "";
for (i = 0; i < n; i++)
{
str = "";
j = i;
while (HT[j].parent != -1)
{
k = HT[j].parent;
if (HT[k].lchild == j)
str += "0";
else
str += "1";
j = k;
}
for (int l = str.size()-1; l >= 0; l--)
{
HT[i].code += str[l]; //保存编码
}
cout << HT[i].ch << ":" << HT[i].code << endl;
}
}
void Huffman_Decode(HuffmanTree *HT, int n,string s) //解码
{
string temp = "", str = "";
for (int i = 0; i < s.size(); i++)
{
temp += s[i];
for (int j = 0; j < n; j++)
{
if (temp == HT[j].code)
{
str += HT[j].ch;
temp = "";
break;
}
else if (i == s.size() - 1 && j == n - 1 && temp != "")
{
cout << endl;
cout << "解码错误" << endl;
exit(0);
}
}
}
cout << "解码为:" << str << endl;
}
void ShowHuffmanTree(HuffmanTree *HT, int n) //输出哈夫曼树
{
cout << (HT + n)->weight << " ";
if ((HT + n)->lchild != -1 && (HT + n)->rchild != -1)
{
ShowHuffmanTree(HT, (HT + n)->lchild);
ShowHuffmanTree(HT, (HT + n)->rchild);
}
}
int main()
{
cout << "请输入要创建哈夫曼树的权值个数:" << endl;
int n=5;
//cin >> n;
cout << "请输入权值:" << endl;
char c[5] = { 'A','B','C','D','E' };
HuffmanTree *HT = new HuffmanTree[2 * n - 1];
SetHuffmanTree(HT, n,c);
Huffman_Code(HT, n);
string str;
cout << "请输入编码:" << endl;
cin >> str;
//for (int i = 0; i < n; i++)
// cout << HT[i].ch << ":" << HT[i].code << endl;
Huffman_Decode(HT, n, str);
delete []HT;
}
运行环境VS2017
运行结果