赫夫曼树

赫夫曼树,又称最优二叉树,是带权路径最短的树。

基本概念:
路径:一个结点到另一个结点之间的分支构成两点间的路径
路径长度:分支的数目
树的路径长度:根结点到树上每一个结点的长度之和  =》完全二叉树是路径最短的树
结点的带权路径长度:结点到根节点的路径长度与结点上权的乘积。
树的带权路径长度:树中所有叶子结点的带权路径长度之和。

构造赫夫曼树的赫夫曼算法:
    1.根据给点的所有权值构成n棵二叉树的集合,每棵二叉树只有带权根节点,没有左右子树
2.每次从集合中选取权值最小的两棵树组成新的二叉树,此树根结点的权值为两颗子树权值之和
3.从集合中删除这两棵子树,添加新组成的树
4.重复2,3,直到集合中只剩下一棵树

赫夫曼树的使用:
前缀编码:若要设计产度不等的编码,则任意字符编码不能是另一字符编码的前缀。
赫夫曼编码:以字符出现的频率为权值,生成的前缀编码

赫夫曼树没有度为1的结点,n个叶子结点的赫夫曼树共有2n-1个结点。
赫夫曼树的数据结构:
typedef struct{
   unsigned int weight;
   unsigned int parent, lchild ,rchild ;
}HTNode,*HuffmanTree;
typedef char **HuffCode;

void HuffmanCoding(HuffmanTree &HF,HuffCode &HC,int* w,int n){
     //建立huffman树并编码
     m = 2n -1;
     HF = (HuffmanTree) malloc ( (m + 1) * sizeof(HTNode));
     for(p = HF,i =1;i <= n;++p,++i,++w) *p = {*w,0,0,0};
     for(;i <= m; ++p,++i,++w)  *p = {0,0,0,0};
   }
     for(i = n+1; i <+m,++i){
         Select(HT,i-1,s1,s2);  //永远从前面选择权值最小且parent = 0的两棵树
         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;
     }
     //求每一个字符的编码
     HC = (HuffCode) malloc ((n+1)* sizeof(char*));
     cd = (char*) malloc (m * sizeof(char));
     cd[n-1] = '/0';
    
     for(i = 1; i<= n; ++i){
          start = n-1; //start 用来指示编码字符的起始位置
                      
          //c: current    f :father  parent
          for(c =i,f = HF[i].parent;f != 0; c = f, f = HF[f].parent){
   if(HF[f].lchild = c)  cd[--start] = '0';
                 else cd[--start] = '1';
  }
      //n-start 指示编码的长度,即向左移了多少个字符
      HC[i] = (char*) malloc ((n-start)*sizeof(char) );
      strcpy(HC[i],&cd[start]);   //cd[start]编码字符起始位置
     }
     free(cd);
}

遍历赫夫曼树求编码方法:
1.自底向上
  如上,从自己出发,一层一层向上,如果它是父节点的左子树,那么编码字符为0,为右即为1,直到找到根节点,用start记录编码字符串的起始位置,n-start为其编码字符串长度
2.自顶向下


如下
//m指示根节点
p=m,cdlen =0;
for(i=1;i<=m;++i)  HT[i].weight =0;//全部权值归零
while(p){
 if(HT[p].weight == 0){//表示此结点还没有遍历过
    HT[p].weight == 1;
  
    if(HT[p].lchild != 0) cd[cdlen++] ='0';
    else(HT[p].rchilde == 0){//左右子树都为空,登记叶子结点的编码字符串
     HC[p] = (char*) malloc ((cdlen+1)*sizeof(char));
     cd[cdlen] = '\0';
     strcpy(HC[p],cd);
   }
   }
   else if(HT[p].weight == 1){//遍历过一次,即左子树已经遍历完了
  HT[p].weight == 2;
          if(HT[p].rchild != 0){
   p = HT[p].rchild; cd[cdlen++] = '1';
  }
   }
   else{ //左右子树已经遍历完,退回
  HT[p].weight == 0;
         p = HT[p].parent;   --cdlen;
 }
    }
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值