哈夫曼树
哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(WPL)达到最小,则称该二叉树为哈夫曼树,也被称为最优二叉树。
怎样才能使带权路径长度最短:根据WPL(权值*边*边数)的计算规则,我们要尽可能地让权值大的叶子节点靠近根节点,让权值小的叶子节点远离根节点,这样就能使得这颗二叉树的带权路径长度达到最小。
哈夫曼树的构建
1.将输入的n个数据,权值为输入的数,然后构建n棵只有根的树。
2.每次都选出两棵权值最小的数,生成这两棵树的父节点,权值为这两棵树的权值和,这样每次合并一次就会少一颗树。
3.不断地合并,直到只剩下一棵树,这就是我们构建的哈夫曼树。
构建哈夫曼树就是反复选择两个最小的元素进行合并,直到只剩下一个元素。
如下动图 :
观察该图后我们还发现:
1.哈夫曼树不存在度为1的结点。这是因为我们每次都是选择两棵子树进行合并。
2.如果给定n个数要求构建哈夫曼树,则构建出来的哈夫曼树结点总数为2n-1。
注意:由于我们每两个结点都要构建一个父节点,所以在定义单个结点类型时,我们要定义一个变量存储该节点的双亲结点下标。
typedef double DataType; //结点权值的数据类型
typedef struct HTNode //单个结点的信息
{
DataType weight; //权值
int parent; //父节点
int lc, rc; //左右孩子
}*HuffmanTree;
构建代码如下:
void Select(HuffmanTree &HT,int n,int &s1,int &s2){
int min;
for(int i=1;i<=n;i++){
if(HT[i].parent==0) {
min=i;
break;
}
}
for(int i=min+1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<HT[min].weight)
min=i;
}
s1=min;
for(int i=1;i<=n;i++){
if(HT[i].parent==0&&i!=s1) {
min=i;
break;
}
}
for(int i=min+1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<HT[min].weight&&i!=s1)
min=i;
}
s2=min;
}
void CreatHuff(HuffmanTree &HT,DataType *w,int n)
{
int m=2*n-1;//总结点数
HT=(HuffmanTree)calloc(m+1,sizeof(HTNode));
for(int i=1;i<=n;i++){
HT[i].weight=w[i];
}
for(int i=n+1;i<=m;i++){//构建
//选择权值最小的两个下标,s1最小放在左子树,
//生成他们的父节点,父节点权值为他们的和
int s1,s2;
Select(HT,i-1,s1,s2);
HT[i].weight=HT[s1].weight+HT[s2].weight;
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].leftc=s1;
HT[i].rightc=s2;
}
}
在该代码中,主要分为两部分,Select函数用于找到目前最小的两个元素,CreatHuff函数用于创建哈夫曼树,也就是生成两个元素的父节点依次连接起来。
哈夫曼编码:
对于哈夫曼树上的叶子结点,根据从根结点到该叶子结点的路径所确定的一个编号,就是该叶子结点的哈夫曼编码。
对于任意一棵二叉树,我们把二叉树上的所有分支都进行编号,所有的左分支都标记为0,所有的右分支都标记为1。
代码如下:
void HuffCoding(HuffmanTree &HT,HuffmanCode &HC,int n){
HC=(HuffmanCode)malloc(sizeof(char *)*(n+1));//下标为0的空间不用
char *code=(char *)malloc(sizeof(char)*n);//辅助空间,编码最长为n(前n-1为数据,n为'\0')
code[n-1]='\0';
for(int i=1;i<=n;i++){
int start=n-1;
int c=i;
int p=HT[c].parent;
while(p){
if(HT[p].leftc==c) code[--start]='0';
else code[--start]='1';
c=p;
p=HT[c].parent;
}
HC[i]=(char *)malloc(sizeof(char)*(n-start));
strcpy(HC[i],&code[start]);
}
free(code);
}