树(四)<C语言>

哈夫曼树

基本概念

  1.路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径。

  2.结点的路径长度:两结点路径上的分支数

  3.树的路径长度:从树根到每个结点的路径长度之和。

     如图:从A到B,C,D,E,F,G,H,I的路径长度分别为1,1,2,2,2,2,3,3。树的路径长度为16。

  注意:结点数目相同的二叉树中,完全二叉树是路径最短的二叉树,但路径最短的二叉树不一定是完全二叉树,因为叶子结点可以移动到其他位置。(充分条件)

 4.权:将树中结点赋给一个有某种含义的数值,则这个数值称为该结点的权

 5.结点的带权路径长度:从根结点到该结点之间的路径长度与该结点权的乘积。

 6.树的带权路径长度:树中所有叶子结点的带权路径长度之和。 

哈夫曼树定义:最优(二叉)树,带权路径长度最短的(二叉)树。

哈夫曼树构造算法  

算法解释

  哈夫曼树中权越大的叶子离根越近\Rightarrow贪心算法:构造哈夫曼树时首先选择权值小的叶子结点

(1)根据n个给定的权值{W1,W2,...Wn,}构成n棵二叉树的森林F={T1,T2,...,Tn},其中Ti只有一个带权Wi的根结点。

(2)在F中选取两棵根结点的权值最小的树作为左右子树,构造一棵新的二叉树,且设置新的二叉树的根结点的权值为左右子树根结点的权值之和。

(3)在F中删除选取的两个树,并将新得到的二叉树加入森林。

  哈夫曼树的结点的度数都为0,2,没有度为1的结点。

  包含n个叶子结点的哈夫曼树共有2n-1个结点。

算法表示

  采用顺序存储结构——一维结构数组:

typedef struct {
	int wight;
	int parent, lch, rch;
}HTNode,*HTLink;

 构造哈夫曼树:

 创建一个大小为2n-1的一维数组,前n(1~n)个储存根结点,后面n-1个用来存储新的根结点。从所有根节点中,选两个最小的根节点,构成新的二叉树,以此递归。

#include<stdio.h>
#include<stdlib.h>
typedef struct {
	int wight;
	int parent, lch, rch;
}HTNode,*HTLink;
void SelectNode(HTLink HT, int n, int& s1,int &s2){
	int x1 = 0, x2 = 0;
	int w1 = 999, w2 = 999;
	for (int i = 1; i <= n; i++) {
		if (HT[i].parent == 0 && HT[i].wight < w1) {
			w2 = w1;
			x2 = x1;
			w1 = HT[i].wight;
			x1 = i;
		}
		else if (HT[i].parent == 0 && HT[i].wight < w2)
		{
			w2 = HT[i].wight;
			x2 = i;
		}
		s1 = x1;
		s2 = x2;
	}
}
void CreatHTLink(HTLink& HT, int n) {
	HT = (HTNode*)malloc((2 * n) * sizeof(HTNode));
	int s1, s2;
	for (int i = 1; i < 2 * n; i++) {
		HT[i].parent = 0;
		HT[i].lch = 0;
		HT[i].rch = 0;
	}
	for (int i = 1; i <= n; i++) {
		scanf_s("%d", &HT[i].wight);
	}
	for (int i = n+1; i <= 2 * n - 1; i++) {
		SelectNode(HT, i-1, s1, s2);
		HT[i].lch = s1;
		HT[i].rch = s2;
		HT[i].wight = HT[s1].wight + HT[s2].wight; 
		HT[s2].parent = i;
		HT[s1].parent = i;
	}
	return;
}

哈夫曼树应用

哈夫曼编码

(1)统计字符集中每个字符出现的平均概率(概率越大,要求编码越短);

(2)利用哈夫曼树的特点:权越大的叶子离根节点越近,将每个字符的概率值作为权值,构建哈夫曼树。概率越大,路径越短

(3)在哈夫曼树的每个分支上标上0或1,结点的左分支标0,右分支标1。把从根结点到每个叶子结点的路径的标号连起来,作为该叶子代表的字符编码。

为什么哈夫曼编码能够保证是前缀编码?

因为在哈夫曼树中,没有一片树叶是另一片树叶的祖先,所以每个叶结点的编码不可能是其它叶结点的编码前缀。

为什么哈夫曼编码能够保证字符编码总长最短?

因为哈夫曼树带权路径最短,故字符编码总长最短。

性质1:哈夫曼编码是前缀码。

性质2:哈夫曼编码是最优前缀码。

算法实现:从叶子递归到根结点编码,再翻过来就是哈夫曼编码,创建二维字符串数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值