哈夫曼树的基本概念与运用

//主要给自己看的,不会写的那么详细。

在洛谷-深入浅出这本书中的贪心这一节,有提到所谓的哈夫曼编码,后续了解到其与一种特殊的数据结构“哈夫曼树”,又被称为最优二叉树紧密相连。深入浅出这本书并未对其进行详细解释,所以自学了。


一些基本概念

路径:一个结点到另一个结点所经过的结点,比如A到D的路径就是ABD

路径长度: 一个结点到另一个结点所经过的边的数量被称为路径长度,比如A到D了的路径长度为2

结点带权路径长度:指一个结点的权数 乘以 该节点到根节点的路径长度。

WPL(树的带权路径长度):指树的所有叶子结点的带权路径长度之和,叶子结点是指没有孩子结点的结点。也可以通过将所有的非根节点的权值累加起来计算出WPL。


拥有以上的基本知识后,我们可以简单介绍一下哈夫曼树了,哈夫曼树指的就是,WPL最小的二叉树,最优二叉树。

原则上,我们需要将叶子结点权重较小的远离树根,权重较大的靠近树根,这样便可以构建出一个哈夫曼树。

如何将一串数据,构建成哈夫曼树呢,对于C++,我们可以采用优先队列(priority_queue)的方式,将权重最小的两个元素先排好,较小的那个元素是左节点,较大的那个元素是右节点,然后这两个节点的父节点的权重就是这两个元素之和,再以此类推,直到构建完毕。

通过构建哈夫曼树,我们可以很容易的求出最小WPL。

例题

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

例如有 33 种果子,数目依次为 1, 2 , 9 。可以先将 1 、 2 堆合并,新堆数目为 3 ,耗费体力为 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 ,耗费体力为 12 。所以多多总共耗费体力 =3+12=15 。可以证明 15 为最小的体力耗费值。

此题标记为贪心题,但是我们需要知道该如何贪,如果我们对哈夫曼树有一些基本的了解,我们便可以知道,将果子的数目进行排序,构建出哈夫曼树,便可以求出最小WPL,也就是该题所说的最小的体力耗费值。这里我们采用了将所有的非根节点累加起来的策略计算出最终值。

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
	priority_queue<int,vector<int>,greater<int>> h;
	int n,res=0; cin >> n;
	for (int i = 0; i < n; i++)
	{
		int num;
		cin >> num;
		h.push(num);
	}
	while (h.size()>1)
	{
		int sum = 0;
		sum += h.top(); h.pop();
		sum += h.top(); h.pop();
		h.push(sum);
		res += sum;
	}
	cout << res;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值