王道计算机机试练习——哈夫曼树

筅森魡賤 提交于 2020-03-09 15:06:41

王道计算机机试——哈夫曼树

题目描述
哈夫曼树,第一行输入一个数 n,表示叶结点的个数。需要用这些叶结点生 成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即 weight,题目需要输出 所有结点的值与权值的乘积之和。

1. 哈夫曼树求法

1)将所有结点放入集合 K。
2)若集合 K 中剩余结点大于 2 个,则取出其中权值最小的两个结点, 构造他 们同时为某个新节点的左右儿子,该新节点是他们共同的双亲结点,设定它的权 值为其两个儿子结点的权值和。并将该父亲结点放入集合 K。重复步骤 2 或 3。
3)若集合 K 中仅剩余一个结点, 该结点即为构造出的哈夫曼树数的根结点, 所有构造得到的中间结点 (即哈夫曼树上非叶子结点 )的权值和即为该哈夫曼树 的带权路径和。 为了方便快捷高效率的求得集合 K 中权值最小的两个元素,我们需要使用堆数 据结构。它可以以 O(logn)的复杂度取得 n 个元素中的最小元素。为了绕过对 堆的实现,我们使用标准模板库中的相应的标准模板 ——优先队列。

2.大顶堆与小顶堆

priority_queue<int> Q;

建立一个保存元素为 int 的堆 Q,但是请特别注意这样建立的堆其默认为大 顶堆,即我们从堆顶取得的元素为整个堆中最大的元素。而在求哈夫曼树中,我 们恰恰需要取得堆中最小的元素,于是我们使用如下语句定义一个小顶堆:

priority_queue<int, vector<int>, greater<int>> Q;//建立一个小顶堆

关于堆的有关操作如下:

Q.push(x); //将元素 x 放入堆 Q 中。
int a = Q.top();// 取出堆顶元素,即最小的元素保存在 a 中。
Q.pop();//弹出堆顶元素,取出后堆会自动调整为一个新的小顶堆。 

3.代码

#include<queue>
#include<iostream>
using namespace std;
priority_queue<int, vector<int>, greater<int>> Q;//建立一个小顶堆
int main() {
	int n;
	while (cin >> n) {
		while (Q.empty() == false) Q.pop();//清空堆中元素
		for (int i = 1; i <= n; i++) {//输入n个叶子节点权值
			int x;
			cin >> x;
			Q.push(x);
		}
		int ans = 0;//保存答案
		while (Q.size() > 1) {//当堆中元素大于1个,最后剩余一个
			int a = Q.top();
			Q.pop();
			int b = Q.top();
			Q.pop();//取出堆中两个最小元素,它们同为一个节点的左右儿子,且该双亲结点的权值为它们的和
			ans += a + b;//该父亲节点必为非叶子节点,所以累加其权值
			Q.push(a + b);//将该双亲节点的权值放回堆中
		}
		cout << ans;
	}
	return 0;
}

4.时间复杂度

在使用了优先队列以后,求哈夫曼树的过程不仅时间复杂度降低许多( O (nlogn)),同时代码也轻便不少,所以使用数据结构堆来辅助求解哈夫曼树, 是求哈夫曼树的最佳选择。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!