Huffman树

Huffman树/最优二叉树:
(一)Huffman树的定义:

(1)节点的带权路径长度WPL(weighted path length):
根结点到该节点的路径长度与该节点的权值的乘积为节点的WPL:
(2)树的带权路径长度WPL:
树的WPL:树上所有叶子节点的带权路径长度之和。
(3)Huffman树/最优二叉树:
带权路径长度最小的二叉树为Huffman树/最优二叉树.

(二)Huffman树的特点:
(1)Huffman树上没有度数为1的节点。即n1=0
(2)n=2*n0-1;(n为节点数目,n0为叶子节点数目)
因为n=n0+n1+n2=n0+n2=n0+n0-1=2*n0-1

(三)Huffman树的构造:
构造一个有n0个叶子节点的Huffman树。

(1)思想:
1.根据给定的n个权值{w1,w2,...wn},对应节点构成n棵二叉树的森林F={T1,T2,...Tn},每棵二叉树只有一个权值为wi的根节点,左右孩子为空。
2.在F中选择两棵根节点的权值最小的二叉树,作为左右子树构造一棵新的二叉树,新的二叉树的根节点的权值为左右子树的根节点的权值之和。
3.在F中删除这两棵二叉树,将新的二叉树添加到F中。
4.重复2和3,直至F中只有一棵树,即为Huffman树。

(2)范例:
 如下图:

(3)代码实现:

/*
Huffman树中的每个节点的类型:
*/
typedef struct HTNode {
 DataType data;
 WeightType weight;
 int parent ;
 int lchild;
 int rchild;
};

/*
Huffman树的数据类型:
*/
typedef struct HFTree{
 HTNode elem[Maxsize];//
 int leafCount;//叶子节点的个数
 int root; //最终的huffman树的根节点的下标。root=2*n-2
};

/*
目的:根据给出的数据序列dataArray[n],以及权值序列weightArray[n],构造一棵huffman树。
n为叶子节点个数,即序列长度。
注 : ht为引用型参数;
注意:此中,huffman树是用数组来存储各个节点的,但是不是用数组的下标来标识各个节点之间的关系。
而是通过节点中的lchild,rchild,parent(int 类型)来标识各个节点之间的关系。
*/
void createHFTree(HFTree & ht , DataType [] dataArray , WeightType [] weightArray ,int n){
 WeightType minWeight1,minWeight2;//两个根节点权值最小的权值
 int index_minWeight1,index_minWeight2;//根节点权值最小的节点的下标
 int i ,j ,k;

 for(i=0;i<n;i++){//初始化将每个叶子节点的data,weight填写
 ht.elem[i].data=dataArray[i];
 ht.elem[i].weight=weightArray[i];
 }

 for(i=0;i<2*n-1;i++){//初始化所有节点的parent,lchild ,rchild;
 ht.elem[i].parent=ht.elem[i].lchild=ht.elem[i].rchild=-1;
 }

 /*elem[]数组的0~n-1填充的是叶子节点,n~2*n-2填充的双分支节点*/
 for(i=n;i<2*n-1;i++){
  minWeight1=minWeight2=MaxValue;
  index_minWeight1=index_minWeight2=0;//初始化最小的权值,及其下标。

  for(k=0;k<i;k++){//for循环找出根节点权值最小的两个权值,及其根节点下标
   if(ht.elem[k].parent==-1){//是否为根节点

    if(ht.elem[k].weight<minWeight1){//节点k的权值比最小都小
     minWeight2=minWeight1;//minWeight1为最小的权值,
     minWeight1=ht.elem[k].weight;//minWeight2为权值次小的权值
     index_minWeight2=index_minWeight1;
     index_minWeight1=k;
    }
    else if(ht.elem[k].weight<minWeight2){
    //节点k的权值比最小大,但是比次小小。
     minWeight2=ht.elem[k].weight;
     index_minWeight2=k;
    }

   }

  }

  ht.elem[index_minWeight1].parent=i;
  ht.elem[index_minWeight2].parent=i;//删除两个子树
  ht.elem[i].lchild=index_minWeight1;//加入新的节点
  ht.elem[i].rchild=index_minWeight2;
  ht.elem[i].weight=minWeight1+minWeight2;
 }

ht.leafCount=n;
ht.root=2*n-2;
}

(四)Huffman编码:
/*
编码类型;
注:code[start~N-1]存放一个叶子的huffman编码;

*/
#define N 10
typedef struct HFCode{
 char code[N];
 int start;
};

/*
目的:生成huffman编码;
思想:
1.对于当前的叶子节点ht.elem[i](0<=i<=leafCount),现将其对应的编码tempCode.start=N-1;
2.寻找当前节点的父节点,ht.elem[parent],如果当前节点为父节点的左孩子,则tempCode[start--]=0,为右孩子,则tempCode[start--]=1;
3.父节点成为新的当前节点,重复1,2,直至父节点为-1.

*/
//hfCode的每一个元素为一个叶子节点的编码
void createHFCode(HFTree & ht ,HFCode  hfCodeArray[]){
 int current,father;//current为当前节点的下标,father为其父节点的下标
 HFCode tempCode;
 int i;
 for(i=0;i<ht.leafCount;i++){//为每一个叶子节点建立编码
  current=i;//叶子节点存在ht的elem[0~leafCount-1]中。
  father=ht.elem[i].parent;
  tempCode.start=N-1;

  while(father!=-1){
   if(ht.elem[father].lchild==current)
   tempCode.code[start--]='0';
   else tempCode.code[start--]='1';

   current=father;//更新current,father,向上走一步。
   father=ht.elem[current].parent;
  }

  tempCode.start++;
  htCodeArray[i]=tempCode;
 }

}

------

注:也可以使用最小堆来构建Huffman树。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值