哈夫曼编码能够保证是前缀码和最优前缀码。
#include <iostream>
#include <string.h>
#include <stdio.h>
/*
问题:
n = 8;
w = {5, 29, 7, 14, 23, 3, 11, 8};
m = 2n - 1 = 15;
求HuffmanCode?
答题思路:
顺序存储 -- 一维结构数组
初始化结果:
下标 weights parent lch rch
1 5 0 0 0
2 29 0 0 0
3 7 0 0 0
4 14 0 0 0
5 23 0 0 0
6 3 0 0 0
7 11 0 0 0
8 0 0 0 0
9 0 0 0 0
10 0 0 0 0
11 0 0 0 0
12 0 0 0 0
13 0 0 0 0
14 0 0 0 0
15 0 0 0 0
16 0 0 0 0
经过n-1次合并,产生n-1个结点:
1 找到i-1前面的节点中parent = 0,的两个最小值s1、s2;
2 HT[s1] = i; HT[s2] = i;
3 HT[i].weight = HT[s1].weight + Ht[s2].weight; HT[i].lch = s1; HT[i].rch = s2;
*/
// Huffman数的结点结构
struct HuffmanNode{
double weight;
int parent; // parent的下标
int lch; // 左孩子的下标
int rch; // 右孩子的下标
};
typedef HuffmanNode *HuffmanTree;// Huffman树
typedef char** HuffmanCode;
// 初始化Huffman树
void InitHuffman(HuffmanTree &, int);
// 产生n-1个节点
void CreatNewNode(HuffmanTree &, int);
// Huffman编码
void CreatHuffmanCode(HuffmanTree &, HuffmanCode &, int);
// 从森林中取2个权最小的树
void select(HuffmanTree &, int, int &, int &);
int main()
{
// 初始化
HuffmanTree HT;
int n;
std::cout << "Huffman 叶子节点数:" << std::endl;
std::cin >> n ;
InitHuffman(HT, n);
CreatNewNode(HT, n);
std::cout << HT[n+1].weight << std::endl;
HuffmanCode HC;
CreatHuffmanCode(HT, HC, n);
std::cout << HC[1] << std::endl;
std::cout << HC[2] << std::endl;
std::cout << HC[3] << std::endl;
std::cout << HC[4] << std::endl;
std::cout << HC[5] << std::endl;
std::cout << HC[6] << std::endl;
return 0;
}
// 初始化Huffman树
void InitHuffman(HuffmanTree &HT, int n)
{
int m = 2*n - 1;
HT = new HuffmanNode[m+1];
for(int i = 1; i <= m; ++i)
{
HT[i].parent = 0;
HT[i].lch = 0;
HT[i].rch = 0;
}
std::cout << "Huffman 叶子结点权重" << std::endl;
for(int i = 1; i <= n; i++)
std::cin >> HT[i].weight;
}
// 产生n-1个节点
void CreatNewNode(HuffmanTree &HT, int n)
{
int m = 2*n - 1;
for (int i = n + 1; i <= m; ++i)
{
// 寻找两个最小值s1, s2, parent = 0;
int s1, s2;
select(HT, n+i-1, s1, s2);
HT[s1].parent = i; HT[s2].parent = i;
HT[i].weight = HT[s1].weight + HT[s2].weight;
HT[i].lch = s1; HT[i].rch = s2;
// std::cout << HT[s1].weight << " " << HT[s2].weight << std::endl;
}
}
// Huffman编码
void CreatHuffmanCode(HuffmanTree &HT, HuffmanCode &HC, int n)
{
HC = new char*[n + 1]; // 分配n个字符编码的头指针矢量
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 != 0) // 从叶子结点向上回溯,至到根节点
{
--start;
if (HT[f].lch == c)
cd[start] = '0'; // 如果是左孩子,生成编码0
else
cd[start] = '1'; // 如果是右孩子,生成编码1
c = f; f = HT[f].parent; // 继续向上回溯
// std::cout << n << " " << f << " " << c << std::endl;
// std::cout << start << " " << cd[start] << std::endl;
}
HC[i] = new char[n-start]; // 为第i个字符串编码分配空间
strcpy(HC[i], &cd[start]); // 将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; // 释放临时空间
}
void select(HuffmanTree &HT, int len, int &s1, int &s2)
{
s1 = HT[1].weight;
for (int i = 1; i <= len; i++)
{
if (HT[i].parent != 0 || HT[i].weight <= 0)
continue;
if (HT[i].weight <= s1);
s1 = i;
}
for (int j = 1; j <= len; j++)
{
if (HT[j].parent != 0 || HT[j].weight <= 0 || j == s1)
continue;
if (HT[j].weight <= s1);
s2 = j;
}
}