1.路径长度:一串节点序列k1,k2......kn,从k1到kn经过的分支数即为这两点之间的路径长度,路径长度等于路径上节点个数减1。
2.带权路径长度:有时树的节点具有权值,这时节点的带权路径长度规定为从树根节点到该节点之间的路径长度与该点权的乘积。
3.树的带权路径长度(WPL):定义为树中所有叶子节点的带权路径长度之和。
哈夫曼树
又称为最优二叉树,它是n个带权叶子节点构成的所有二叉树中,WPL最小的二叉树。哈夫曼树中除了叶子节点外的其他所有节点都有两个孩子。
给我们n个节点,我们用其作为叶子节点构造一棵哈夫曼树,将这n个节点视为n棵树的森林,每次从中选取权值最小的两棵树合并为一棵树,新树的节点权值为两树之和,那么经过n-1次操作后,最后只剩余一棵树,即所求的哈夫曼树。
哈夫曼编码
在发送电报信息中,每个字母对应为一个二进制编码,为了尽可能缩短电报的总长度,应该使出现次数较多的字母二进制编码较短。故将每个字母的出现频率作为结点的权值赋予叶子结点,每个分支结点的左右分支分别用0和1编码,从树根结点到每个叶子结点的路径上所经分支的0、1编码序列即等于该叶子结点的二进制编码。
//C语言程序实例
#include<stdio.h>
#include<stdlib.h>
typedef struct Huffman{
int data;
struct Huffman *left,*right;
}*huffman;
int len; //输入节点的个数
//创建哈夫曼树
huffman createTree(int len){
huffman ptrarr[len]; //指针数组
huffman ptr,root;
for(int i=0;i<len;i++){ //开辟len个叶子节点
ptr=(huffman)malloc(sizeof(struct Huffman));
int tmp;scanf("%d",&tmp);
ptr->data=tmp;
ptr->left=ptr->right=NULL;
ptrarr[i]=ptr;
}
for(int i=1;i<len;i++){ //操作执行n-1次
int k1=-1,k2;
for(int j=0;j<len;j++){ //从指针数组中挑选出两个指针,它们的数组下标赋给k1,k2
if(ptrarr[j]!=NULL&&k1==-1)
{k1=j;continue;}
if(ptrarr[j]!=NULL)
{k2=j;break;}
}
for(int j=k2;j<len;j++){ //使k1为节点权最小的指针的数组下标,k2为次小的
if(ptrarr[j]!=NULL){
if(ptrarr[j]->data<ptrarr[k1]->data){
k2=k1;
k1=j;
}
else if(ptrarr[j]->data<ptrarr[k2]->data)
k2=j;
}
}
root=(huffman)malloc(sizeof(struct Huffman)); //合并为一棵新树
root->data=ptrarr[k1]->data+ptrarr[k2]->data;
root->left=ptrarr[k1];root->right=ptrarr[k2];
ptrarr[k1]=root;ptrarr[k2]=NULL;
}
return root;
}
//递归计算哈夫曼树的带权路径长度
int getweight(huffman root,int len){
if(root==NULL)
return 0;
else{
if(root->left==NULL&&root->right==NULL){
return root->data*len; //递归出口,到达叶子节点
}
else
return getweight(root->left,len+1)+getweight(root->right,len+1);
}
}
//中序遍历输出哈夫曼树
void inTraverse(huffman root){
if(root==NULL)
return;
inTraverse(root->left);
printf("%d ",root->data);
inTraverse(root->right);
}
//对输入的叶子节点进行哈夫曼编码
void huffcode(huffman root,int len){
static int arr[100];
if(root!=NULL){
if(root->left==NULL&&root->right==NULL){
printf("节点权值为%d的编码为:",root->data);
for(int i=0;i<len;i++)
printf("%d",arr[i]);
printf("\n");
}
else{
arr[len]=0;
huffcode(root->left,len+1);
arr[len]=1;
huffcode(root->right,len+1);
}
}
}
int main(){
printf("输入树的叶子节点数:");
scanf("%d",&len);
huffman root;
root=createTree(len);
printf("中序遍历为:\n");
inTraverse(root);
int weight=getweight(root,0);
printf("哈夫曼树的带权路径长度为:%d\n",weight);
printf("哈夫曼编码为:\n");
huffcode(root,0);
return 0;
}