2023/5/14总结

哈夫曼树

哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(WPL)达到最小,则称该二叉树为哈夫曼树,也被称为最优二叉树。

怎样才能使带权路径长度最短:根据WPL(权值*边*边数)的计算规则,我们要尽可能地让权值大的叶子节点靠近根节点,让权值小的叶子节点远离根节点,这样就能使得这颗二叉树的带权路径长度达到最小。

哈夫曼树的构建 

1.将输入的n个数据,权值为输入的数,然后构建n棵只有根的树。

2.每次都选出两棵权值最小的数,生成这两棵树的父节点,权值为这两棵树的权值和,这样每次合并一次就会少一颗树。

3.不断地合并,直到只剩下一棵树,这就是我们构建的哈夫曼树。

构建哈夫曼树就是反复选择两个最小的元素进行合并,直到只剩下一个元素。

如下动图 :

 观察该图后我们还发现:

1.哈夫曼树不存在度为1的结点。这是因为我们每次都是选择两棵子树进行合并。

2.如果给定n个数要求构建哈夫曼树,则构建出来的哈夫曼树结点总数为2n-1。

注意:由于我们每两个结点都要构建一个父节点,所以在定义单个结点类型时,我们要定义一个变量存储该节点的双亲结点下标。

typedef double DataType; //结点权值的数据类型

typedef struct HTNode //单个结点的信息
{
	DataType weight; //权值
	int parent; //父节点
	int lc, rc; //左右孩子
}*HuffmanTree;

 构建代码如下:

void Select(HuffmanTree &HT,int n,int &s1,int &s2){
	int min;
	for(int i=1;i<=n;i++){
		if(HT[i].parent==0) {
			min=i;
		    break;
		}
	}
	for(int i=min+1;i<=n;i++){
		if(HT[i].parent==0&&HT[i].weight<HT[min].weight)
		min=i;
	}
	s1=min;
	for(int i=1;i<=n;i++){
		if(HT[i].parent==0&&i!=s1) {
			min=i;
		    break;
		} 
	}
	for(int i=min+1;i<=n;i++){
		if(HT[i].parent==0&&HT[i].weight<HT[min].weight&&i!=s1)
		min=i;
	}
	s2=min;
} 

void CreatHuff(HuffmanTree &HT,DataType *w,int n)
{
	int m=2*n-1;//总结点数
	HT=(HuffmanTree)calloc(m+1,sizeof(HTNode));
	for(int i=1;i<=n;i++){
		HT[i].weight=w[i];
	}
	for(int i=n+1;i<=m;i++){//构建 
		//选择权值最小的两个下标,s1最小放在左子树,
		//生成他们的父节点,父节点权值为他们的和 
		int s1,s2;
		Select(HT,i-1,s1,s2);
		HT[i].weight=HT[s1].weight+HT[s2].weight;
		HT[s1].parent=i;
		HT[s2].parent=i;
		HT[i].leftc=s1;
		HT[i].rightc=s2;
	}
}

在该代码中,主要分为两部分,Select函数用于找到目前最小的两个元素,CreatHuff函数用于创建哈夫曼树,也就是生成两个元素的父节点依次连接起来。

 哈夫曼编码:

对于哈夫曼树上的叶子结点,根据从根结点到该叶子结点的路径所确定的一个编号,就是该叶子结点的哈夫曼编码。

对于任意一棵二叉树,我们把二叉树上的所有分支都进行编号,所有的左分支都标记为0,所有的右分支都标记为1。

代码如下:

void HuffCoding(HuffmanTree &HT,HuffmanCode &HC,int n){
	 HC=(HuffmanCode)malloc(sizeof(char *)*(n+1));//下标为0的空间不用
	 char *code=(char *)malloc(sizeof(char)*n);//辅助空间,编码最长为n(前n-1为数据,n为'\0')
	 code[n-1]='\0';
	 for(int i=1;i<=n;i++){
	 	int start=n-1;
	 	int c=i;
	 	int p=HT[c].parent;
	 	while(p){
	 		if(HT[p].leftc==c) code[--start]='0';
	 		else code[--start]='1';
	 		c=p;
	 		p=HT[c].parent;
		 }
		 HC[i]=(char *)malloc(sizeof(char)*(n-start));
		 strcpy(HC[i],&code[start]);
	 } 
	 free(code);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值