哈夫曼树及其编码
Posted lsy-lsy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈夫曼树及其编码相关的知识,希望对你有一定的参考价值。
首先是哈夫曼树的定义:在一棵二叉树中,带权路径长度达到最小,成这样的树是最优二叉树,也是哈弗曼树。大概意思就是把数值大的节点放在树上面,数值小的节点放在树下面。哈夫曼树的结构使用顺序结构,这里直接使用了数组。
建造哈弗曼树的思路:根据二叉树的性质,有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(" "); 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] = ‘