数据结构-树和二叉树-Huffman树

树和二叉树

Huffman 树

赫夫曼(Huffman)树,又称最优树,是一类带权路径长度最短的树,有着广泛的应用。

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

路径长度:路径上分支的数目构成路径长度。

树的路径长度:树根到每一个节点的路径长度之和。

树的带权路径长度:树中所有叶子节点的带权路径长度之和,记作 W P L = ∑ k = 1 n w k l k WPL = \sum_{k=1}^{n}w_kl_k WPL=k=1nwklk

最优二叉树或赫夫曼树:假设有n个权值 { w , w , . . . , w . } \left \{w,w,...,w.\right \} {w,w,...,w.},试构造一棵有n个叶子结点的二叉树,每个叶子结
点带权为 w i w_i wi,则其中带权路径长度WPL最小的二叉树称做最优二叉树或赫夫曼树。

在这里插入图片描述

构造霍夫曼树

霍夫曼最早给出了一个带有一般规律的算法,俗称霍夫曼算法。

现叙述如下:
(1)根据给定的n个权值 ( w 1 , w 2 , . . . , w n ) (w_1,w_2,...,w_n) (w1,w2,...,wn)构成n棵二叉树的集合 F = { T 1 , T 2 , … T n } F=\left \{T_1,T_2,…T_n\right \} F={T1,T2,Tn},其中每棵二叉树 T i T_i Ti中只有一个带权为 w i w_i wi的根结点,其左右子树均空。
(2)在F中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
(3)在F中删除这两棵树,同时将新得到的二叉树加入F中。
(4)重复(2)和(3),直到F只含一棵树为止。这棵树便是赫夫曼树。

Huffman编码

前缀编码:要设计长短不等的编码,则必须是任一个字符的编码都不是另一个字符的编码的前缀,这种编码称做前缀编码。

//-----赫夫曼树和赫夫曼编码的存储表示-----
typedef struct {
    unsigned int weight;
    unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree;    //动态分配数组存储霍夫曼树
typedef char * * HuffmanCode; // 动态分配数组存储霍夫曼编码表
//求huffman编码的算法如下所示
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC,int *w, int n){
    // w 存放 n个字符的权重(均>0),构造huffman树HT,并求出 n个字符的huffman编码HC
    if (n<=1) return ; // 节点小于等于 1的返回None
    m = 2 * n -1;// 树节点的个数
    HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));  //0号单元未用 ,申请(m+1)*htnode尺寸的内存
    for (p = HT, i = 1; i<=n; ++i,++p,++w) *p = {*w, 0, 0 , 0};// 构造n个二叉树,值为w;parent,lchild,rchild都为 0 
    for (;i<=m; ++i ,++p) *p = {0,0,0,0};// 从n到m之间的二叉树权重,parent,lchild,rchild 都置为0
    for (i = n+1; i<=m;++i){//建huffman树
        	//在HT[1..i-1]选择parent 为0 且weight 最小的两个节点,其序号分别为s1和s2.
        Select(HT,i-1, s1,s2); 
        HT[s1].parent=i;HT[s2].parent = i; // 最小的两个节点其父节点置为i,
        HT[i].lchild = s1; HT[i].rchild = s2; // 节点i的左节点置位s1,右节点置为s2
        HT[i].weight = HT[s1].weight+ HT[s2].weight; //节点i的权重为 左右子节点权值相加
    }
    //---从叶子到根逆向求每个字符的赫夫曼编码---
	HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符编码的头指针向量
	cd=(char*)malloc(n*sizeof(char));
	//分配求编码的工作空间
	cd[n-1]="\0";
	//编码结束符。
	for(i=1;i<=n;++i){
		//逐个字符求赫夫曼编码
		start=n-1;
		//编码结束符位置
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent)//从叶子到根逆向求编码
			if(HT[f].lchild==c) cd[--start]="0";
			else cd[--start]="1";
			HC[i]=(char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间
			strcpy(HC[i],&cd[start]);			//从cd复制编码(串)到HC
		}
		free(cd);//释放工作空间
		
}//HuffmanCoding
例题

已知某系统在通信联络中只可能出现8种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,0.11,试设计赫夫曼编码。

设权w=(5,29,7,8,14,23,3,11),n=8,则m=15,按上述算法可构造一棵赫夫曼树如图6.26所示。其存储结构HT的初始状态如图6.27(a)所示,其终结状态如图6.27(b)所示,所得赫夫曼编码如图6.27 (c)所示。

在这里插入图片描述

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4TlL64T-1632650370957)(image-20210926175446048.png)]

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值