Huffman编码树

先简单回顾一下哈夫曼二叉树的概念:哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+ Wn*Ln),N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的。 
        构造哈夫曼树的算法如下: 
        1)对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,..., Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。 
        2)在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。 
        3)从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。 
        4)重复2)和3),直到集合F中只有一棵二叉树为止。
        下面举一个很普通的例子:
         对于权2,3,5,7,11,13,17,19,23,29,31,37,41,求具有最小带权外部路径长度的二叉树.
        1>找到最小权值和次小权值2和3,然后2+3=5构成两个节点的父母,并将5作为下次合并的新权值;
                                    5
                                  /    \
                               2        3
       2>此时权值更新为5,5,7,11,13,17,19,23,29,31,37,41;然后按照1>的模式找到5和5 并产生其父母10,并作为下次合并的新权值;
                                 10
                               /     \
                             5        5
                                     /   \
                                    2     3
        3>同理 10,7,11,13,17,19,23,29,31,37,41;
                                                  17
                                                /    \
                                              7       10
                                                        /  \
                                                      5     5
                                                             / \
                                                            2    3
           4>  17,11,13,17,19,23,29,31,37,41;
                   此时注意最小数和次小树不再是前两位,所以要另起一棵树,由11 和13构成;
                                                                                        17
                                                                                         /\
                                                                                      7    10
                                            24                                              /\
                                             /\                                              5  5
                                           11 13                                             /\
                                                                                               2  3
           5>好了依次比到最后:
                 17,17,24,19,23,29,31,37,41;
                 19,24,23,29,31,34,37,41;
                 24,29,31,34,37,41,42;
                 31,34,37,41,42,53;
                 37,41,42,53,65;
                 42,53,65,78;
                 65,78,95;
                 95,143;
                 238;
            完整的树图:
                                                                                          238
                                                                                    /              \
                                                                                95                  143
                                                                              / \                     /     \ 
                                                                           42     53              65       78
                                                                        /\          /   \            /   \         / \
                                                                     19  23   24  29           31  34     37  41
                                                                                  / \                      /  \
                                                                                 11  13               17     17
                                                                                                                   / \ 
                                                                                                                 7     10 
                                                                                                                       /   \
                                                                                                                      5     5
                                                                                                                            /\
                                                                                                                          2     3
 

对于哈夫曼树,有一个很重要的定理:对于具有n个叶子节点的哈夫曼树,共有2*n-1个节点。

构造哈夫曼树的算法的实现原理如下:对于n个叶子节点,我们根据上面的定理构造出大小为2*n-1的数组来存放整个哈夫曼树。这个数组的前n个位置存放的为已知的叶子节点,后(n-1)个位置存放的为动态生成的树内节点。在算法的大循环过程中,要做的事情就是根据位置i前面的已知节点(或者是叶节点或者是生成的树内节点),找出 parent为-1(即节点尚且是一个子树的根结点)的节点中权值最小的两个节点,然后根据这两个节点构造出位置为i的新的父节点(也就是一棵新树的根结点)。
而哈弗曼编码也类似于哈弗曼树的构建,只是要构建一串010101010111…….其核心就是使频率越高的码元采用越短的编码。编码过程就根据不同码元的频率(相当于权值)构造出哈夫曼树,然后求叶子节点到根节点的路径,其中节点的左孩子路径标识为0,右孩子路径标识为1。
下面给出Huffman算法的完整代码:
#include  < stdio.h >
#define  n 4
typedef 
struct   
{
    
int  parent;
    
int  lchild,rchild;
    
int  weight;
    
int  flag;
}Node;

typedef 
struct  
{
    
char  bit[n];
    
int  start;
    
char  ch;
}CodeNode;

Node haffman[
7 ];
CodeNode code[n];

int  select( int  j)
{
    
int  i,position;
    
int  Min = 100 ;
    
for  (i = 0 ;i <= j;i ++ )
        
if  (haffman[i].weight < Min  &&  haffman[i].flag ==- 1 )
        {
            Min
= haffman[i].weight;
            position
= i;
        }
    haffman[position].flag
= 1 ;
    
return  position;
}

void  haffmanCode()
{
    
int  i,j,p,k;
    
    
for  (i = 0 ;i < n;i ++ )
    {
        printf(
" %d  " ,haffman[i].weight);
        code[i].start
= n - 1 ;
        j
= i;
        p
= haffman[i].parent;
        
while  (p !=- 1 )
        {
            
if  (haffman[p].lchild == j)
                code[i].bit[code[i].start]
= ' 0 ' ;    // 左0右1;
             else
                code[i].bit[code[i].start]
= ' 1 ' ;
            code[i].start
-- ;
            j
= p;
            p
= haffman[p].parent;
        }
        
for (k = code[i].start + 1  ;k < n ;k ++ )
          printf(
" %c " ,code[i].bit[k]);
        printf(
" \n " );
    }

}

int  main()
{
    
    
int  max = 100  , i ;
    
int  m1,m2;

    
// 初始化节点数据;
     for  (i = 0 ;i < 2 * n - 1 ;i ++ )
    {
        haffman[i].weight
= 0 ;
        haffman[i].parent
=- 1 ;
        haffman[i].lchild
=- 1 ;
        haffman[i].rchild
=- 1 ;
        haffman[i].flag
=- 1 ;
    }
    printf(
" 请输入叶子节点的权值: " );
    
for  (i = 0 ;i < n;i ++ )
    {
        scanf(
" %d " , & haffman[i].weight);   
    }
    
// 构造哈弗曼二叉树(n-1次合并);
     for  (i = n ; i < 2 * n - 1  ;i ++ )
    {
        m1
= select(i - 1 );         // 最小权值位;
        m2 = select(i - 1 );      // 次最小权值;
        haffman[m1].parent = i;
        haffman[m2].parent
= i;   // 父节点在数组中的位置;
        haffman[i].weight = haffman[m1].weight + haffman[m2].weight;
        haffman[i].lchild
= m1;
        haffman[i].rchild
= m2;     // 儿子节点在数组中的位置;
        
    }
    
for  (i = 0  ;i < 2 * n - 1  ;i ++ )
        printf(
" %d " ,haffman[i].weight);
    printf(
" \n " );
    haffmanCode();
}

转载于:https://www.cnblogs.com/gavindlutsw/archive/2011/08/07/Huffman.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值