哈夫曼树及其编码

首先是哈夫曼树的定义:在一棵二叉树中,带权路径长度达到最小,成这样的树是最优二叉树,也是哈弗曼树。大概意思就是把数值大的节点放在树上面,数值小的节点放在树下面。哈夫曼树的结构使用顺序结构,这里直接使用了数组。

建造哈弗曼树的思路:根据二叉树的性质,有n个叶子节点,二叉树就会有2n-1个节点。定义一个数组,前n个节点作为叶子节点,从前n个节点中选择两个最小的节点,作为一棵二叉树的左右节点,这棵二叉树的根节点值为左右孩子节点值之和。把这个根节点的值放入数组中,然后接着从数组中(新加入的节点也算)选取两个最小的节点,只不过把已经使用过的节点忽略掉,这样不断循环,每个节点和其他节点都有对应关系。

代码实现:

定义结构体,里面有四个成员,分别为权值,父节点,左孩子节点,右孩子节点,这里的节点指的是他在数组中对应的下标位置,如果是0则没有父节点或者孩子节点,权值不能为0.

 

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define n 7
 5 #define m 2*n-1
 6 #define maxval 100
 7 
 8 typedef struct{
 9     int weight;
10     int parent,lchild,rchild;
11 }HufmTree;
12 
13 HufmTree *init(){
14     
15     HufmTree *hf = (HufmTree *)malloc(sizeof(HufmTree));
16     if(hf==NULL)
17         return NULL;
18     
19     return hf;
20     
21 }
22 
23 void setHuffmanTree(HufmTree *tree[]){
24     
25     int i,j,p1,p2,s1,s2;
26     for(i=n;i<m;i++){                        //从n位置开始,都是两个节点新合成的节点,直到m位置结束 
27         p1 = p2 = 0;                         //每次循环开始,都要数组从头开始遍历 
28         s1 = s2 = maxval;                    
29         for(j=0;j<=i-1;j++)                    //在所有节点中寻找,i后面没有数值的空位置用不到 
30             if(tree[j]->parent==0)             //此处的代码的作用是检查该节点是否已经使用过,因为使用过的节点肯定有父节点    
31                 if(tree[j]->weight<s1){        //寻找最小权值的节点 
32                     s2 = s1;                    
33                     s1 = tree[j]->weight;
34                     p2 = p1;
35                     p1 = j;
36                 }
37                 else if(tree[j]->weight<s2){//寻找次小权值的节点 
38                     s2 = tree[j]->weight;
39                     p2 = j;
40                 }
41         tree[p1]->parent = tree[p2]->parent = i;    //把两个最小节点的父节点指向i 
42         tree[i]->weight = tree[p1]->weight + tree[p2]->weight;    //父节点权值等于左右孩子权值之和 
43         tree[i]->lchild = p1;                //指明父节点的左右孩子节点 
44         tree[i]->rchild = p2;
45     }
46     
47 }
48 
49 void display(HufmTree *tree[n]){
50     
51     int i;
52     for(i=0;i<m;i++){
53         printf("%d ",tree[i]->weight);
54     }
55     printf("\n");
56 }

 

哈弗曼编码:使出现频率高的编码放在上面,频率低的编码放在下面。

 

 

以上图为例,其中A的频率最高,离根节点最近,GFED频率最低,在最下面。

实现原理:从根节点到每个叶子节点间的路径值作为编码,图片里的规定是左子树的路径为1,右子树的路径为0,这样每个节点都有自己的编码且不会重复

 1 void createHuffmanCode(HufmTree *tree[n]){
 2      
 3      
 4      int i,j,p,start;
 5      char *temp;                                    //临时存放字母编码的数组 
 6      for(i=0;i<n;i++){                            //从0~n之间都是二叉树的叶子节点 
 7          start = n-1;                            //存放temp数组的下标,从后往前,指向最后面 
 8          temp = (char *)malloc(n*sizeof(char));    //为数组分配空间 
 9         temp[start] = '\0';                        //添加字符串结束标志 
10          j = i;                                    //j代表为哪个叶子节点编码 
11         p = tree[j]->parent;                    //p是j的父节点 
12          while(p!=0){
13              if(tree[p]->lchild==j)
14                  temp[--start] = '0';            //如果j是p的左孩子,则在数组中添加一个 '0'
15             else
16                 temp[--start] = '1';            //反之则添加一个 '1'
17             j = p;
18             p = tree[p]->parent;                //j和p不断往上循环 
19         }
20         printf("%d:%s \n",tree[i]->weight,&temp[start]);
21     }
22      
23  }
24  
25 void main(){
26     
27     HufmTree *tree[m];
28     int i,num[n] = {7,3,2,4,9,10,5};
29     
30     //分配空间 
31     for(i=0;i<m;i++)
32         tree[i] = init();
33         
34     //数组每个节点内的所有值初始化时都设为0 
35     for(i=0;i<m;i++){
36         tree[i]->weight = 0;
37         tree[i]->parent = 0;
38         tree[i]->rchild = 0;
39         tree[i]->lchild = 0;
40     }
41     
42     //为数组前n个数的权值赋值 
43     for(i=0;i<n;i++)
44         tree[i]->weight = num[i];
45     
46     setHuffmanTree(tree);
47     
48     display(tree);
49     
50     createHuffmanCode(tree);
51     
52 }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-11-23 15:07  捞的不谈  阅读(3258)  评论(0编辑  收藏  举报