zoukankan      html  css  js  c++  java
  • 哈夫曼树及编码

    介绍哈夫曼编码之前先介绍一下哈弗曼树:

    哈夫曼树:哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度 为叶结点的层数)。树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+...+Wn*Ln) N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。可以证明哈夫曼树的WPL是最小的

    哈夫曼树的构造:

    一、构成初始集合

      对给定的n个权值{W1,W2,W3,...,Wi,...,Wn}构成n棵二叉树的初始集合F={T1,T2,T3,...,Ti,...,Tn},其中每棵二叉树Ti中只有一个权值为Wi的根结点,它的左右子树均为空。(为方便在计算机上实现算法,一般还要求以Ti的权值Wi的升序排列。) 

    二、选取左右子树

      在F中选取两棵根结点权值最小的树作为新构造的二叉树的左右子树,新二叉树的根结点的权值为其左右子树的根结点的权值之和。 

    三、删除左右子树

      从F中删除这两棵树,并把这棵新的二叉树同样以升序排列加入到集合F中。 

    四、重复二和三两步,

    重复二和三两步,直到集合F中只有一棵二叉树为止。

    构造过程如下:

    a 有权值为1,2,3,4四棵树;

    b 由于树1,2的权值处于最小和次最小,所以选中,并合成为一棵树,小的权值位于左边;

    c 从3,4,(1,2 = 3)三棵树里面选择权值最小的和次小的,我们选中3和(1,2)

    合成新树(3,(1,2)= 6);

    d 最后选出新树(4,(3,(1, 2)))

     

    哈夫曼树具体实现

     

    需要考虑的问题:

     

    1 用什么样的存储结构;

     

    2 怎么选择选择最小和次小权值的树;

     

    3 怎么存放合成的新树

     

    如果我们采用

     

    Struct node

     

    {

     

    Int key;

     

    Struct node *l;

     

    Struct node *r;

     

    }

     

    的存储结构的话,可以采用数组的链式结构,并设计标记数组如下:

     

    (我们以4个初始树为例子)

     

    标记数组:(有则标记为1,否则为0)

     

    Struct node n1

    Struct node n1

    Struct node n1

    Struct node n1

     

    存储数组

     

    Struct node n1

    Struct node n1

    Struct node n1

    Struct node n1

     

    第一次选择为1,2树,合成新树,我们可以统一放在最小树的位置上(也可以放在大树位置上),所以新树放于树1 的位置并更新其权值为两者之和,其状态为:

     

    标记数组:(有则标记为1,否则为0)

     

    1

    0

    1

    1

     

    存储数组

     

    Struct node n1

    Free()

    Struct node n1

    Struct node n1

     

    这样存储结构的问题解决了,其实做到这里我们应该比较清楚后面怎么做了,当然选择出最小值和次小值为比较简单的算法了。

     

    例:设有8个字符{A,B,C,D,E,F,G,H},其概率为{0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11},设其权值用整数表示为 {5,29,7,8,14,23,3,11},其哈夫曼树如图1所示。

     

     

    实现代码如下:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 struct node 
      5 {
      6     int key;
      7     struct node *l;
      8     struct node *r;
      9 };
     10 typedef struct node *pnode;
     11 int mark[100];
     12 struct node  huffman[100];
     13 void PrintNode(const pnode node)
     14 {
     15     printf("key = %d 
    ", node->key);
     16 }
     17 void PreOrder(pnode T)
     18 {
     19     if(T)
     20            
     21     {
     22            PrintNode(T);
     23            PreOrder(T->l);
     24                 
     25            PreOrder(T->r);
     26             
     27     }
     28       
     29 }
     30 void Select(int *mark, struct node *huffman, int size, int *choose)  
     31 {
     32      
     33         int i;
     34      
     35         for(i = 0;  i< size;  i++)
     36     {
     37         if(mark[i])
     38         {
     39             choose[0] = i;
     40             i++;
     41             break;
     42         }
     43     }
     44     choose[1] = choose[0];
     45         for(; i < size; i++ 46             { 
     47                          if(mark[i]) 
     48                          { 
     49                                               if(huffman[choose[0]].key >= huffman[i].key) 
     50                                                   { 
     51                                                           choose[1] = choose[0];
     52                                                               choose[0] = i;
     53                                                
     54                                                           
     55  56                                                   else if(huffman[choose[1]].key > huffman[i].key)    choose[1] = i;
     57                                            
     58                                                   
     59  60                              
     61  62  63 void Choose(int *mark, struct node *huffman, int size, int *choose)
     64 {
     65     int i;
     66     int minkey = 0;
     67     int tkey = 0;
     68     int temp = 0;
     69     for(i = 0;  i< size;  i++)
     70     {
     71         if(mark[i])
     72         {
     73             minkey = i;
     74             i++;
     75             break;
     76         }
     77     }
     78     tkey = minkey;
     79     for(;  i< size;  i++)
     80     {
     81         if(mark[i])
     82         {
     83             if(huffman[i].key < huffman[minkey].key)
     84             {
     85                 tkey = minkey;
     86                 minkey = i;
     87             }
     88             if(tkey == minkey)
     89                 tkey = i;
     90             if(huffman[tkey].key > huffman[i].key && i != minkey)
     91             {
     92                 tkey = i;
     93             }
     94         }
     95     }
     96     choose[0] = minkey;
     97     choose[1] = tkey;
     98 }
     99 pnode HuffmanTree(int *mark, struct node *huffman, int size)
    100 {
    101     int choose[2];
    102     int i;
    103     pnode mynode;
    104      
    105     for(i = 0;  i < size-1;  i++)
    106     {
    107         Select(mark, huffman, size, choose);
    108         mynode = (pnode)malloc(sizeof(struct node));
    109         mynode->key = huffman[choose[0]].key+huffman[choose[1]].key;//更新key值
    110         mynode->l = (pnode)malloc(sizeof(struct node));
    111         mynode->l->key = huffman[choose[0]].key;
    112         mynode->l->l = huffman[choose[0]].l;
    113         mynode->l->r = huffman[choose[0]].r;
    114         mynode->r = &huffman[choose[1]];
    115         huffman[choose[0]] = *mynode;
    116         mark[choose[1]] = 0;
    117         free(mynode);
    118 119     return &huffman[choose[0]];
    120 }
    121 int main(void)
    122 {
    123     int key[8] =  {5,29,7,8,14,23,3,11};
    124     int i;
    125     pnode huffmantree;
    126     memset(mark, -1sizeof(mark));
    127     memset(huffman, 0sizeof(huffman));
    128     for(i = 0;  i < 8;  i++)
    129     {
    130         huffman[i].key = key[i];
    131     }
    132     huffmantree = HuffmanTree(mark, huffman, 8);
    133     PreOrder(huffmantree);
    134     return 0;
    135 }

    哈夫曼编码:

    思想:得到哈夫曼树后,自顶向下按路径编号,指向左节点的边编号0,指向右节点的边编号1,从根到叶节点的所有边上的0和1连接起来,就是叶子节点中字符的哈夫曼编码。

    下图体现了哈夫曼编码的过程:

     

     

     

    很晚了==拜拜。

  • 相关阅读:
    [LeetCode] 1072. Flip Columns For Maximum Number of Equal Rows
    [LeetCode] 1730. Shortest Path to Get Food
    [LeetCode] 1005. Maximize Sum Of Array After K Negations
    [LeetCode] 1286. Iterator for Combination
    [LeetCode] 390. Elimination Game
    [LeetCode] 1940. Longest Common Subsequence Between Sorted Arrays
    [LeetCode] 794. Valid TicTacToe State
    [LeetCode] 1162. As Far from Land as Possible
    [LeetCode] 2022. Convert 1D Array Into 2D Array
    [LeetCode] LeetCode 2021勋章
  • 原文地址:https://www.cnblogs.com/PJQOOO/p/4088611.html
Copyright © 2011-2022 走看看