Huffman树,又称最优二叉树,是一类带权路径最短的树,有着广泛的应用。
Huffman树中没有度为1的节点,所以一棵有 n 个叶子节点的 Huffman 树中,总共有 2n-1 个结点。
构建赫夫曼树的步骤:
1)根据给定的 n 个权值 {w1,w2,w3,...,wn} 构成 n 棵二叉树的集合 F={T1,T2,T3,...,Tn},其中每棵二叉树 Ti 中只有一个带权为 wi 的根节点,其左右子树均为空。
2)在 F 中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根节点的权值为其左右子树上根节点的权值之和。
3)在 F 中删除这两棵树,同时将新得到的二叉树加入 F 中。
4)重复 2)和 3),直到 F 只含一棵树为止。这棵树便是 Huffman 树。
在《数据结构》书中已经给出了部分源码,但是代码中使用的Select函数在书中没有提供,所以我在代码中重写了Select函数以及该函数的调用。
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
typedef struct
{
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree;
void Select(HuffmanTree &P, int m, int &s1, int &s2)
//该函数的功能是选出结构数组中权重最小的两个节点
//其中已经选择过一次的结点剔除在外
{
int wmin, j;
wmin = P[s1].weight>=P[s2].weight? P[s1].weight: P[s2].weight; //wmin=结点s1,s2中的最小值
for(int i=0; i<m; i++)
{
if((P[i].weight<wmin)||P[i].parent!=0) continue; //选择s1比较的参考点
s1 = i;
break;
}
j = i; //j为s2比较的参考点
for(; i<m; i++)
{
//除去已经选择过的点,以及添加的结点中权重为0的点
if(P[i].weight<wmin||P[i].parent!=0||(P[i].weight==0&&i>=(m+1)/2)) continue;
if(P[i].weight<=P[s1].weight) s1=i;
}
for(j=0; j<m; j++)
{
if(P[j].weight<wmin||P[j].parent!=0||j==s1) continue;
s2 = j;
break;
}
for(; j<m; j++)
{
if(P[j].weight<wmin||P[j].parent!=0||j==s1||(P[j].weight==0&&j>=(m+1)/2)
) continue;
if(P[j].weight<=P[s2].weight) s2 = j;
}
}
void HuffmanCreate(HuffmanTree &HT, int *w, int n)
//HT is a struct array
//w is the weight array of every nodes
//n is the number of nodes
{
if(n<=1) exit(0);
int i;
int w_tmp;
int s1 = n, s2 = n+1;
HuffmanTree P;
int m = 2*n-1; //一棵含有n个叶子节点的赫夫曼树,总共含有2*n-1个结点
HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode)); //动态分配一块内存空间,用来存储完整的赫夫曼树
for(i=0,P=HT;i<n;i++,P++,w++) //设置前n个叶子结点的初值,HT保存数组首地址,P在数组上滑动
{
P->weight = *w;
P->parent = 0;
P->rchild = 0;
P->lchild = 0;
}
for(;i<m;i++,P++) //设置后n-1个叶子结点的初值
{
P->weight = 0;
P->parent = 0;
P->lchild = 0;
P->rchild = 0;
}
printf("the initial array of node:\n");
for(i=0;i<m;i++)
{
printf("weight:%d\tparent:%d\tlchild:%d\trchild:%d\n",HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
for(i=n;i<m;i++) //构建赫夫曼树
{
Select(HT, m, s1, s2); //调用Select函数,找到s1,s2
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].lchild = s1;
HT[i].rchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
}
printf("the Huffman tree:\n");
for(i=0;i<m;i++)
{
printf("num:%d\tweight:%d\tparent:%d\tlchild:%d\trchild:%d\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);
}
}
void main()
{
HuffmanTree tree;
int w[SIZE] = {7,4,8,5,3,9,2,1,6,0};
HuffmanCreate(tree, w, SIZE);
system("pause");
}
运行结果如下:
