哈夫曼树--数据结构

本文详细介绍了哈夫曼树的概念、特点、构造算法以及哈夫曼编码的原理。哈夫曼树是一种带权路径长度最短的二叉树,用于数据压缩和高效编码。通过构建哈夫曼树并进行编码,可以实现字符的前缀编码,从而减少通信中的数据传输量。文章还提供了示例展示如何为不同频率的字符设计哈夫曼编码,并与等长编码进行了比较,强调了哈夫曼编码在信息传输中的优势。
摘要由CSDN通过智能技术生成

 


 
 

  

哈夫曼树

  哈夫曼树,又称最优树,时一类带权路径长度最短的树。
  从树中一个结点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称做路径长度
  树的路径长度是从树根到每一结点的路径长度之和。
  树的带权路径长度为树中所有叶子结点的带权路径长度之和,通常记作 WPL = ω1l1 + …… + ωnln
  假设有 n 个权值{ ω1,ω2,……,ωn },试构造一棵有 n 个叶子结点的二叉树,每个叶子结点带权为 ωi,则其中带权路径长度 WPL 最小的二叉树称做最优二叉树哈夫曼树
哈夫曼树示例
(a)WPL = 7×2+5×2+2×2+4×2=36;
(b)WPL = 7×3+5×3+2×1+4×2=46;
(c)WPL = 7×1+5×2+2×3+4×3=35;
其中(c)树最小。可以验证它恰好为哈夫曼树,即其带权路径长度在所有带权为7、5、2、4的 4 个叶子结点的二叉树中居最小。
 
 

哈夫曼树的特点

  1. WPL最小
  2. 给定权值的哈夫曼树可能不只一棵
  3. 只有度为 2,度为 0 的结点—正则的(严格的)二叉树
  4. 一棵有 n 个叶子结点的哈夫曼树共有 2n-1 个结点
  5. 权值越大的叶结点越靠近根结点,而权值越小的叶结点越远离根结点
     
     

构造哈夫曼树算法

  1. 根据给定的 n 个权值 {ω1,ω2,……,ωn} 构成 n 棵二叉树的集合 F={T1,T2,……,Tn},其中每棵二叉树 Ti 中只有一个带权为 ωi 的根结点,其左右子树均空。
  2. 在 F 中选取两棵根结点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。
  3. 在 F 中删除这两棵树,同时将新得到的二叉树加入 F 中。
  4. 重复 1 和 2,直到 F 只含一棵树为止。这棵树便是哈夫曼树。
     
     

哈夫曼编码

  若采用相同长度的不同码字代表相应的符号,就称为等长编码
  若要设计长短不等的编码,则必须是任一个字符的编码都不是另一个字符的编码的前缀,这种编码称做前缀编码
  可以利用二叉树来设计二进制的前缀编码。约定左分支表示字符‘0’,右分支表示字符‘1’(左0右1),则可以从根结点到叶子结点的路径上分支字符组成的字符串作为该叶子结点字符的编码。如此得到必为二进制前缀编码,二进制前缀编码也被称为哈夫曼编码。
 

示例

假设用于通信的电文由字符集{a,b,c,d,e,f,g}中的字母构成。它们在电文中出现的频度分别为 {0.31,0.16,0.10,0.08,0.11,0.20,0.04}
为这7个字母设计哈夫曼编码
为这7个字母设计等长编码,至少需要几位二进制数?
哈夫曼编码比等长编码使电文总长压缩多少?

先对权值进行排序。
1
每次从序列中取出两个结点。然后构成一个结点,重新放回序列。
2

然后再次重复操作,直至,队列剩余一个结点为止。
3
4
5
6
7
结果
等长编码位数相同表示 7 种符号至少需要 3 位二进制位。
23 =8,所以需要三位二进制数
等长二进制三位共100个字符,占用100 * 3 = 300
哈夫曼编码:2 * 20+ 3 * 10+11* 3+4 * 4+8 * 4+16 * 3+ 31 * 2 = 261
压缩:(300 - 261)/ 300 = 0.13

 
 

哈夫曼树构造代码

typedef struct{
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode, *HuffmanTree;	//动态分配数组存储哈夫曼树 
typedef char **HuffmanCode;	//动态分配数组存储哈夫曼编码表 

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){
	//w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC 
	if(n <= 1)//字符小于一个 
		return;
	m = 2 * n - 1;//m为生成的中间节点个数 
	HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));	//0号单元未用 
	for(p = HT, i = 1; i <= n; i++, p++, w++)//字符初始化 
		*p = {*w, 0, 0, 0};
	for(; i <= m; i++, p++)//中间节点初始化 
		*p = {0, 0, 0, 0};
	for(i = n+1; i<= m; i++){	//建哈夫曼树 
		//在HT[1..i-1]选择parent为0且weight最小的两个结点,其序号分别为s1和s2 
		Select(HT, i-1, s1, s2);
		HT[s1].parent = i;
		HT[s2].parent = i;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
	}
	//从叶子到根逆向求每个字符的哈夫曼编码 
	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);//释放工作空间 
}

示例

  已知某系统在通信联络中只可能出现 8 种字符,其概率分别为0.05,0.29,0.07,0.08,0.14,0.23,0.03,3.11,试设计哈夫曼编码。
在这里插入图片描述
在这里插入图片描述

 
 

哈夫曼编码和二进制编码的比较

  1. 码字不同。 哈夫曼所构造的码字不是唯一的,对于同一信息源,无论上述的顺序如何排序,它的平均码长是不会改变,所以他的优点是编码效率唯一性。而二进制编码所构成的码字是唯一。
  2. 长度不同。 哈夫曼树是依据字符出现概率来构造异字头的平均长度最短的码字,比较精准,二进制编码用预计规定的方法将文字、数字或其他对象编成二进制的数码,或将信息、数据转换成二进制电脉冲信号。二进制是最基础的编码。
  3. 稳定性不同。 哈夫曼编码的稳定性。如果改变其中一位数据就会产生改变。二进制编码具有抗干扰能力强,可靠性高等优点。
哈夫曼树是一种特殊的二叉树结构,用于编码和解码数据。在哈夫曼树中,每个叶子节点都代表一个字符或符号,并且具有一个与之关联的权值,代表该字符或符号出现的频率或概率。根据哈夫曼树的概念,我们可以通过给定的叶子节点的权值来构建哈夫曼树。 对于给定的叶子节点的权值,构建哈夫曼树的步骤如下: 1. 首先,根据叶子节点的权值从小到大进行排序。 2. 选取权值最小的两个叶子节点,并将它们作为两个子节点创建一个新的父节点。新父节点的权值等于这两个子节点的权值之和。 3. 将这个新的父节点插入到叶子节点中,同时删除原来的两个子节点。 4. 重复步骤2和步骤3,直到只剩下一个节点,即根节点,这个节点就是哈夫曼树的根节点。 根据题目提供的例子,我们可以看到一种不是建树的方法,只使用数组来模拟哈夫曼树的构造过程。这种方法是通过数组来存储节点的信息,并通过一些特定的计算方式来模拟构建哈夫曼树的过程。 根据题目的描述,我们需要根据叶子节点的个数和权值来生成哈夫曼树,并计算所有节点的值与权值的乘积之和。这个问题可以通过构建哈夫曼树的步骤来解决。首先,我们需要将叶子节点根据权值进行排序。然后,按照步骤2和步骤3构建哈夫曼树,直到只剩下一个节点。最后,计算所有节点的值与权值的乘积之和。 综上所述,数据结构哈夫曼树的例题是通过给定叶子节点的权值来构建哈夫曼树,并计算所有节点的值与权值的乘积之和。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [超好理解的哈夫曼树(最优二叉树)与例题](https://blog.csdn.net/weixin_45720782/article/details/109316157)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值