lfbcsdn博客

专注互联网的菜鸟

哈夫曼树的基本操作,(树的建立,带权路径长度,哈夫曼编码)

哈夫曼树中的名词意思:(ps:本想画个图的不知这上面怎么弄,就没弄了)

树的权值:每个树节点所在的那个数字。

路径:两个节点之间所经过的分支。

路径长度: 某一路径上的分支条数。

节点带权路径长度: 节点的权值*该节点的路径长度。

树带权路径长度:所有叶子节点的带全路径长度之和。

树带权路径长度:所有叶子节点的带全路径长度之和。

建立哈夫曼树:单独将数组中的每个值作为一个节点,依次选出剩余节点的最小与次小,并将其合为树结构的一部分。代码为:

 
//建立哈夫曼树  
btreenode *CreateHuffman(int a[],int n)
{  
	int i;  
	btreenode *s[n+1], *ss;  
	for(int i = 0;i<n;i++){  
	    s[i] = new btreenode;  //初始化s指针数组,使每个指针元素指向a数组中对应的元素结点  
	    s[i]->data = a[i];   //将树拆成森林,每棵树都只有一个根节点  
	    s[i]->left = s[i]->right = NULL;  
	}  
	
	for(int i  = 1;i<n;i++){        //进行 n-1次循环建立哈夫曼树  
	       int k = -1,t;           //k表示森林中具有最小权值的树根结点的下标,t为次最小的下标  
	    for(int j = 0;j<n;j++){   //k初始指向森林中第一棵树,t指向第二棵  
	            if(s[j]&&k==-1){  
                   k = j;  
                   continue;  
	            }  
		        if(s[j]){  
		            t =  j;  
		            break;  
		        }  
	    }  
	        for(int i = t;i<n;i++){   //从当前森林中求出最小权值树和次最小 ;  
	        if (s[i]){  
	            if(s[i]->data<s[k]->data){        //比最小树小 
	                t = k;  
	                k = i;  
	            }  
	            else if(s[i]->data<s[t]->data){  //比次小树小 
	                t = i;  
	            }  
	            else{  
	                ;  
	            }  
	        }  
	    }  
	       //由最小权值树和次最小权值树建立一棵新树,ss指向树根结点(以后依次建立)  
	       ss  = new btreenode;     //ss = (btreenode *)malloc(sizeof(btreenode))		   
	       ss->data =   s[k]->data+s[t]->data;  
	       ss->left =   s[k];  
	       ss->right =  s[t];  
	       s[k] =  ss;  //关键点:将ss赋给s[k](k为上述找到的最小树下标,但这是s[k]代表的值已改变,同时把s[t]失效的置空,  
	                   //在这里起向下一个判断的作用if(s[j]){t = j;break;}  
	       s[t] = NULL;  
	}  
		return ss; 
		free(s);   //释放分配空间  
}  	

哈夫曼树的带权路径长度: 递归至树的叶子节点则此节点的路径长度为:(len值*所带的权值),否则每向下一层len+1(len为树层数):代码为:

//求哈夫曼树的带权路径长度  	
int WeightPathLength(btreenode* FBT, int len){          //参数len为树的层数 
	if(!FBT){  
	        return 0;  
	}  
	else{  
	    if(FBT->left ==NULL&&FBT->right ==NULL)//访问到叶子结点  
	        return FBT->data*len;  
	    else{               //访问到非叶子结点,进行递归调用,返回左右子树的带权路径长度之和,len递增  
	        return  WeightPathLength(FBT->left,len+1)+WeightPathLength(FBT->right,len+1);//一定要记得加1  
	    }  
	}     
}  

哈夫曼编码:将编码值存到数组中,递归到叶子节点则输出数组保存的编码值,代码为:

//哈夫曼编码  
void HuffManCoding(btreenode* FBT, int len){   //参数len为树的层数 
	static int a[20];   					 //定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减1 
	if(FBT){ 								//访问到叶子结点时输出其保存在数组a中的0和1序列编码  
	    if(FBT->left == NULL&&FBT->right == NULL){  
	        printf("结点权值为%d的编码:",FBT->data);  
	         for(int i = 0;i<len;i++){  
	             printf("%d",a[i]);  
	        }  
	            printf("\n") ;  
	    }  
	    else{    //访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组  
	            //a的对应元素中,向下深入一层时len值增1  
	           a[len] = 0;  
	           HuffManCoding(FBT->left,len+1);  
	           a[len] = 1;  
	           HuffManCoding(FBT->right,len+1);  
	        }  
	}  
}  
完整代码为:

#include <iostream>  
#include<cstdio>  
#include<cstdlib>  
using namespace std;  
typedef struct BTreeNode  
{  
    int  data;  
    struct BTreeNode* left;  
    struct BTreeNode* right;  
}btreenode;  
      
//建立哈夫曼树  
btreenode *CreateHuffman(int a[],int n)
{  
	int i;  
	btreenode *s[n+1], *ss;  
	for(int i = 0;i<n;i++){  
	    s[i] = new btreenode;  //初始化s指针数组,使每个指针元素指向a数组中对应的元素结点  
	    s[i]->data = a[i];   //将树拆成森林,每棵树都只有一个根节点  
	    s[i]->left = s[i]->right = NULL;  
	}  
	
	for(int i  = 1;i<n;i++){        //进行 n-1次循环建立哈夫曼树  
	       int k = -1,t;           //k表示森林中具有最小权值的树根结点的下标,t为次最小的下标  
	    for(int j = 0;j<n;j++){   //k初始指向森林中第一棵树,t指向第二棵  
	            if(s[j]&&k==-1){  
                   k = j;  
                   continue;  
	            }  
		        if(s[j]){  
		            t =  j;  
		            break;  
		        }  
	    }  
	        for(int i = t;i<n;i++){   //从当前森林中求出最小权值树和次最小 ;  
	        if (s[i]){  
	            if(s[i]->data<s[k]->data){        //比最小树小 
	                t = k;  
	                k = i;  
	            }  
	            else if(s[i]->data<s[t]->data){  //比次小树小 
	                t = i;  
	            }  
	            else{  
	                ;  
	            }  
	        }  
	    }  
	       //由最小权值树和次最小权值树建立一棵新树,ss指向树根结点(以后依次建立)  
	       ss  = new btreenode;     //ss = (btreenode *)malloc(sizeof(btreenode))		   
	       ss->data =   s[k]->data+s[t]->data;  
	       ss->left =   s[k];  
	       ss->right =  s[t];  
	       s[k] =  ss;  //关键点:将ss赋给s[k](k为上述找到的最小树下标,但这是s[k]代表的值已改变,同时把s[t]失效的置空,  
	                   //在这里起向下一个判断的作用if(s[j]){t = j;break;}  
	       s[t] = NULL;  
	}  
		return ss; 
		free(s);   //释放分配空间  
}  	
//求哈夫曼树的带权路径长度  	
int WeightPathLength(btreenode* FBT, int len){          //参数len为树的层数 
	if(!FBT){  
	        return 0;  
	}  
	else{  
	    if(FBT->left ==NULL&&FBT->right ==NULL)//访问到叶子结点  
	        return FBT->data*len;  
	    else{               //访问到非叶子结点,进行递归调用,返回左右子树的带权路径长度之和,len递增  
	        return  WeightPathLength(FBT->left,len+1)+WeightPathLength(FBT->right,len+1);//一定要记得加1  
	    }  
	}     
}  
 
//哈夫曼编码  
void HuffManCoding(btreenode* FBT, int len){   //参数len为树的层数 
	static int a[20];   					 //定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减1 
	if(FBT){ 								//访问到叶子结点时输出其保存在数组a中的0和1序列编码  
	    if(FBT->left == NULL&&FBT->right == NULL){  
	        printf("结点权值为%d的编码:",FBT->data);  
	         for(int i = 0;i<len;i++){  
	             printf("%d",a[i]);  
	        }  
	            printf("\n") ;  
	    }  
	    else{    //访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组  
	            //a的对应元素中,向下深入一层时len值增1  
	           a[len] = 0;  
	           HuffManCoding(FBT->left,len+1);  
	           a[len] = 1;  
	           HuffManCoding(FBT->right,len+1);  
	        }  
	}  
}  
	
int main(){  
	btreenode *s;  
	int n;  
	printf("从键盘输入待构造的哈夫曼树中带权叶子结点数n:");  
	while(true){  
	    scanf("%d",&n);  
	    if(n>0){  
	        break;  
	    }  
	    else{  
	        printf("-------输入不合法,请重新输入!!\n");  
	    }  
	}  
	int *a = (int *)malloc(n *sizeof(int));  
	printf("从键盘输入%d个整数作为权值:",n);  
	for (int i = 0; i < n; i++)  
	    scanf("%d", &a[i]);  
	s = CreateHuffman(a,n);  
	
	printf("哈夫曼树的带权路径长度:");  
	printf("%d\n", WeightPathLength(s, 0));  
	
	printf("树中每个叶子结点的哈夫曼编码:\n");  
	HuffManCoding(s,0);  
	
	return 0;  
}



阅读更多
版权声明:本文为博主原创文章,如需转载,请注明出处。 https://blog.csdn.net/lfb637/article/details/78114061
个人分类: 数据结构与算法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭