【STL】priority_queue

一、priority_queue的使用

  优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。priority_queue实际上是,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)(默认情况下,priority_queue是大根堆)。

函数说明
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即堆顶元素
top()返回优先级队列中最大(最小元素),即堆顶元素
empty()检测优先级队列是否为空,是返回true,否则返回false

这里作者想强调的并不是这些函数,因为这些函数是适配器都有的函数(stack、queue),而是强调priority_queue的模板参数

  1. 默认情况下,priority_queue是大堆,默认使用vector作为其底层存储数据的容器。
       根节点为最大元素
vector<int> v{3,2,7,6,0,4,1,9,8,5};
priority_queue<int> q1;
for (auto& e : v)
	q1.push(e);
cout << q1.top() << endl;	//	9
  1. 如果要创建小堆,将第三个模板参数换成greater比较方式,第二个模板参数是底层容器,默认是vector,也可以是deque。

注:

  1. 这里底层容器不能是list,因为向上向下调整要支持随机访问,而list不支持随机访问,故不能使用list
  2. 如果是自定义类,需要重载“>”或者“<”
  3. 这里说明一下模板参数的第三个参数,这是STL的另一大组件——仿函数,仿函数实际是类,对这个类进行了“()”运算符重载。(文章后面模拟实现priority_queue中对继续说明仿函数)
#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
int main() {
	vector<int> v{3,2,7,6,0,4,1,9,8,5};
	priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
	cout << q2.top() << endl;
}

3.也可以自己提供比较器规则。(这里就不举例了,可以看后面模拟实现的比较定义)

二、priority_queue的模拟实现

  1. 仿函数类:重载"()" 运算符的一个类
      使用仿函数,自定义优先级,不需要修改代码,增加代码的灵活性。
template <class T>
struct Greater {
	bool operator()(const T& a, const T& b) {
		return a > b;
	}
};

template <class T>
struct Less {
	bool operator()(const T& a, const T& b) {
		return a < b;
	}
};

2.priority_queue的具体模拟实现
(这里的代码并没有全部模拟,这个代码也并不是注重堆的向上/向下调整算法(虽然代码已具体实现),这份代码注重的就是模板的第二个和第三个参数,主要是适配器是由底层容器作为模板参数实现,还有仿函数的思想)

template<class T, class Container, class Compare>
class Priority_Queue {
public:
	void push(const T& val) {
		_con.push_back(val);
		//向上调整
		shiftUp(_con.size() - 1);
	}

	void pop() {
		swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();
		//向下调整
		shiftDown(0);
	}

	T& top() {
		return _con.front();
	}

	size_t size() {
		return _con.size();
	}

	bool empty() {
		return _con.empty();
	}

private:
	Container _con;
	Compare _com;

	void shiftUp(size_t child) {
		size_t parent = (child - 1) >> 1;	//父亲结点为 (该结点-1)/2
		while (child > 0) {
			//if (_con[child] > _con[parent]) {
			if (_com(_con[child], _con[parent])) {
				swap(_con[child], _con[parent]);
				child = parent;
				parent = (child - 1) >> 1;
			} else {
				break;
			}
		}
	}

	void shiftDown(size_t parent) {
		size_t child = 2 * parent + 1;
		while (child < _con.size()) {
			//if (child + 1 < _con.size() && _con[child + 1] > _con[child]) {
			if (child + 1 < _con.size() && _com(_con[child + 1], _con[child])) {
				++child;
			}
			//if (_con[child] > _con[parent]) {
			if (_com(_con[child], _con[parent])) {
				swap(_con[child], _con[parent]);
				parent = child;
				child = 2 * parent + 1;
			}
			else {
				break;
			}
		}
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值