从树中一个结点到另外一个结点路径上的分支数目,称作路径长度。
结点的带权路径长度为从该结点到根结点之间的路径长度与结点上权的乘积。
Huffman树,又称最优树,是带权路径长度最短的树。树的带权路径长度是树中所有叶子结点的带权路径长度之和。
Huffman树的构造方法是不断地选取权值最小的两棵树作为左右子树构造一棵新的二叉树,其权值为两棵子树的权值之和,直到只有一棵树为止。
Huffman编码是Huffman树的主要应用,Huffman编码是根据字符使用频率确定字符编码。
一棵含有n个叶子结点的Huffman树共有2n-1个结点,存储在一维数组中。 求编码时,需要从叶子结点向上走到根结点,并且该叶子结点若为双亲的左子树,则编码为0,右子树编码为1。
/*在前n个结点中选择两个权值最小的并且parent为0(树根)的结点*/
void select(HTNode huftree[],int n,int &s1,int &s2)
{
int i,min1,min2;
int temp;
min1 = INT_MAX;
min2 = INT_MAX;
for(i=1; i<=n; i++)
if(huftree[i].parent == 0 && huftree[i].weight<min1)
min1 = huftree[i].weight,s1 = i;
for(i=1; i<=n; i++)
if(huftree[i].parent == 0 && huftree[i].weight<min2 && i!=s1)
min2 = huftree[i].weight,s2 = i;
//必须比较:保证s1<s2,因为若weight的值相同的话,s1取后者,s2取前者,使s1>s2
if(s1>s2)
{
temp = s1;
s1 = s2;
s2 = temp;
}
}
void HuffmanCoding(HTNode HT[],HuffmanCode &HC,int w[],int n)
{
char cd[n];
int start;
int i;
int c,f;
int s1,s2;
if(n <= 1) return ;
int m = 2 * n - 1;
for(i=1; i<=n; i++)
{
HT[i].weight = w[i-1];
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
for(i=n+1; i<=m; i++)
{
HT[i].weight = 0;
HT[i].parent = 0;
HT[i].lchild = 0;
HT[i].rchild = 0;
}
/*构造Huffman树*/
for(i=n+1; i<=m; i++)
{
select(HT,i-1,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;
}
/*求解Huffman编码*/
HC = (HuffmanCode)malloc((n+1)*sizeof(char *));
cd[n-1] = '\0';
for(i=1; i<=n; i++)
{
start = n-1;
for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent)
if(HT[f].lchild == c) cd[--start] = '0';
else cd[--start] = '1';
HC[i] = (char *)malloc((n-start)*sizeof(char));
strcpy(HC[i],&cd[start]);
}
}