哈夫曼树及编码

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

哈夫曼树:哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为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连接起来,就是叶子节点中字符的哈夫曼编码。

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

 

 

 

很晚了==拜拜。

原文地址:https://www.cnblogs.com/PJQOOO/p/4088611.html