哈夫曼树的定义:
哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数}。树的路径长度是从树根到每一结点的路径长度之和,记为WPL = (W1*L1+W2*L2+W3*L3+…+Wn*Ln),N个权值Wi(i=1,2,…n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,…n)。可以证明哈夫曼树的WPL是最小的。
构建哈夫曼树:
代码实现:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct hnode {
int weight; // 权重
int parent;
int lchild;
int rchild;
}HuffmanTree, *HuffmanTreePtr;
typedef char** HuffmanCode;
// 选择权值最小的两个下标
void Select(HuffmanTreePtr HT, int len, int &s1, int &s2) {
int min1 = 32367;
int min2 = 32367;
int i;
for(i = 1; i <= len; i ++) {
if(HT[i].weight < min1 && HT[i].parent == 0) {
s2 = s1;
min2 = min1;
min1 = HT[i].weight;
s1 = i;
}else if(HT[i].weight < min2 && HT[i].parent == 0) {
s2 = i;
min2 = HT[i].weight;
}
}
}
// 创建哈夫曼树
void CreatHuffman_Tree(HuffmanTreePtr &HT, int n) {
int m = 2 * n - 1; // 节点总数
int s1 = 0, s2 = 0; // 对应节点的下标
int i;
HT = (HuffmanTreePtr)malloc(sizeof(HuffmanTree) * (m + 1));
for(i = 1; i <= n; i ++) { // 0号设为哨兵
scanf("%d", &HT[i].weight);
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
} // 初始化
for(i = n + 1; i <= m; i ++) {
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
} // 初始化
for(i = n + 1; i <=m; i ++) {
Select(HT, i - 1, s1, s2);
HT[s1].parent = HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
// 跟踪代码
printf("%d 和 %d 的parent是%d\r\n", s1, s2, i);
printf("%d 的权值是%d\r\n", s1, HT[s1].weight);
printf("%d 的权值是%d\r\n", s2, HT[s2].weight);
printf("%d 的权值是%d\r\n", i, HT[i].weight);
}
}
// 进行哈夫曼编码
void Huffman_Code(HuffmanTreePtr HT, HuffmanCode &HC, int n) {
int i, k, m;
char* code; // 临时储存编码
HC = (HuffmanCode)malloc(sizeof(char*) * (n + 1));
code = (char*)malloc(sizeof(char) * n);
code[n - 1] = '\0';
for(i = 1; i <= n; i ++) {
k = n -1;
m = i;
while(HT[m].parent != 0) {
k --;
if(HT[HT[m].parent].lchild == m) {
code[k] = '0';
}else if(HT[HT[m].parent].rchild == m) {
code[k] = '1';
}
m = HT[m].parent;
}
HC[i] = (char*)malloc(sizeof(char) * (n - k));
strcpy(HC[i], &code[k]);
}
}
int main() {
int n; // 节点数
scanf("%d", &n);
HuffmanTreePtr HT;
HuffmanCode HC;
CreatHuffman_Tree(HT, n);
Huffman_Code(HT, HC, n);
for(int i = 1; i <= n; i ++) {
printf("%d 的编码是%s\r\n", i, HC[i]);
}
return 0;
}
运行结果: