# Huffman树及编码的实现

## 定义

Huffman树又称最优树，是一类带权路径长度最短的树，而Huffman编码是基于Huffman树生成的一种前缀编码，保证了可变编码的平均编码最短。

## 生成方法

1. 首先，假设有n个权值，则整个Huffman树的结点有2n-1个，未填充的节点有n-1个
2. 从n个权值中挑选两个权值最小的结点构成一棵树的叶子节点，生成的树的根节点的权值为两个叶子节点的和，n++；
3. 重复上述步骤，直到所节点都有权重。（即循环n-1次）

## Huffman代码如下

#include <iostream>
#include <string>
using namespace std;
struct HuffmanNode{
int weight;
int parent,lchild,rchild;
};
void createHuffmanTree(HuffmanNode *& node, int *w, int n);
void selectNode(HuffmanNode *node, int & s1, int &s2, int n);
int main(){
HuffmanNode *node;
int w[] = { 5, 29, 7, 8, 14, 23, 3, 11 };
createHuffmanTree(node, w, 8);
system("pause");
return 0;
}

void createHuffmanTree(HuffmanNode *& node, int *w, int n){
int i;
int s1, s2;//两个权重最小的Node
int s = 2 * n - 1;//节点总数
node = new HuffmanNode[s + 1];//获取相应的空间大小
memset(node, 0, (s + 1)*sizeof(HuffmanNode));
for (i = 1; i <= n; i++){
node[i].weight = *w++;
}
for (i = n + 1; i <= s; i++){
selectNode(node, s1, s2, i-1);
node[i].weight = node[s1].weight + node[s2].weight;
node[i].lchild = s1;
node[i].rchild = s2;
node[s1].parent = i;
node[s2].parent = i;
}

//对huffmanTree 进行编码

int start, c, f;
char **res = (char**)malloc((n + 1)*sizeof(char*));
char *cd = (char*)malloc(n*sizeof(char));
cd[n - 1] = '\0';
for (int i = 1; i <= n; i++){
start = n - 1;//code最长有n-1位
for (c = i, f = node[i].parent; f != 0; c = f, f = node[f].parent){
if (node[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
}
res[i] = (char*)malloc((n - start)*sizeof(char));
strcpy_s(res[i],n-start, &cd[start]);
}

for (int i = 1; i <= n; i++){
cout << res[i] << endl;
}

}

void selectNode(HuffmanNode *node, int & s1, int &s2,int n){
s1 = 0;
s2 = 0;
int i;
int min = INT_MAX;

for (i = 1; i <= n; i++){
if (node[i].parent == 0){
min = node[i].weight;
break;
}
}

for (i = 1; i <= n; i++){
if (node[i].parent == 0 && node[i].weight <= min){
min = node[i].weight;
s1 = i;
}
}
min = INT_MAX;
for (i = 1; i <= n; i++){
if (node[i].parent == 0 && node[i].weight < min){
if (i == s1)
continue;
min = node[i].weight;
s2 = i;
}
}
}

## 以上的测试用例

w={5,29,7,8,14,23,3,11}

## 对应的结果表格如下

No weight parent lchild rchild
1 5 9 0 0
2 29 14 0 0
3 7 10 0 0
4 8 10 0 0
5 14 12 0 0
6 23 13 0 0
7 3 9 0 0
8 11 11 0 0
9 8 11 1 7
10 5 12 3 4
11 15 13 8 9
12 29 14 5 10
13 42 15 6 11
14 58 15 2 12
15 100 0 13 14