【C++ STL】-- priority_queue底层原理、使用、模拟实现

目录

priority_queue的使用:

priority_queue的默认定义的模板:

priority_queue的定义并初始化:

priority_queue的模拟实现:

堆的排序算法:

堆的向上调整算法核心:

堆的向下调整算法核心:

priortiy_queue接口的模拟实现


priority_queue的使用:

priority_queue文档介绍

        priority_queue是一个拥有权值观念的queue,它允许加入新元素、移除旧元素、审视旧元素等功能,由于其是一个queue,所以只允许在底端插入元素,并从顶端取出元素,除此之外别无其它存取元素的途径。
        优先级队列默认使用vector 作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。

priority_queue的默认定义的模板:

注意:

  • 默认情况下priority_queue是大堆。
  • 默认情况下priority_queue是以vector作为底层容器

(大多数情况下都是使用vector作为底层容器即可,我们需要变动的只是存储类型、构造堆结构的形式)

方式一:规定的存储类型,默认内部构造大堆结构

//int类型:
priority_queue<int> q1;
//double类型
priority_queue<double> q2;

方式二:默认内部构造小堆结构

priority_queue<int, vector<int>, greater<int>> q;

priority_queue的定义并初始化:

template <class InputIterator>
         priority_queue (InputIterator first, InputIterator last,
                         const Compare& comp = Compare(),
                         const Container& ctnr = Container());
vector<int> v{ 1,2,3,4,5,6,7,8,9,10 };
//使用大堆结构
priority_queue<int> q1(v.begin(), v.end());
//使用小堆结构
priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());
empty测试容器是否为空(公共成员函数)
size返回大小(公共成员函数)
top访问顶部元素(公共成员功能)
push插入元素(公共成员函数)
emplace(C++11)构造并插入元素(公共成员函数)
pop删除顶部元素(公共成员函数)
swap(C++11)交换内容(公共成员函数)
#include<iostream>
#include<queue>
#include<list>
using namespace std;
int main() {
	priority_queue<int> q1;
	for (int i = 0; i < 10; i++)
	{
		q1.push(i);
	}
	//q1:9 8 5 6 7 1 4 0 3 2

	vector<int> v{ 10,20,30 };
	priority_queue<int> q2(v.begin(), v.end());
	//q2:30 20 10

	q2.swap(q1);
	cout << q1.size() << endl;//输出:3
	cout << q2.size() << endl;//输出:10
	//q1:30 20 10
	//q2:9 8 5 6 7 1 4 0 3 2

	while (!q1.empty()) {
		cout << q1.top() << " "; 
		q1.pop();
	}
	cout << endl;
	//输出:30 20 10

    return 0;
}

priority_queue的模拟实现:

注意,下标计算父子间的关系:

  • leftchild = parent * 2 + 1
  • rightchild = parent * 2 + 2
  • parent = (child - 1) / 2 (因为只会保留整数部分)

堆的排序算法:

       此处以小根堆为例;(向上调整算法用于存入数据)。

堆的向上调整算法核心:

(父节点与子节点大小的比较,子对父)

  • 如果比父亲小,则交换,然后继续向上比较并调整(最多调整到跟节点就结束了)。
  • 如果比父亲大,则调整结束。

堆的向下调整算法核心:

(父节点与子节点大小的比较,父对子)

  • 如果比父亲小,则交换,然后继续向下比较并调整。(最多调整到叶子节点就结束了)
  • 如果比父亲大,则调整结束。

本人的堆的算法博客:

priortiy_queue接口的模拟实现

        只要知道了堆的向上排序调整算法和向下排序调整算法后,其实prirotiy_queue的模拟实现几乎已经可以说是完成了。

成员函数实现方法
push利用容量适配器本身的push_back(),并结合堆的向上调整算法。
pop根据堆的排序思维,利用swap(),将第一个元素与最后一个元素交换位子(确保中间元素的堆序不被打乱),然后容量适配器本身的pop_back(),再使用堆的向下调整算法。
top利用容量适配器本身的front()
size利用容量适配器本身的size()
empty利用容量适配器本身的empty()

难度提升:

        priortiy_queue是可以通过容量适配器实现less与gtreater实现,内部堆排序的结构不同。既然需要less与greater,我们也模拟实现一下。

template<class T, class Container = std::vector<T>, class Compare = less<T>>

template<class T>
class less { bool operator()(T& e1, T& e2) { return e1 < e2; } };
template<class T>
class greater { bool operator()(T& e1, T& e2) { return e1 > e2; } };
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
namespace qcr{

	template<class T>
	class less { bool operator()(T& e1, T& e2) { return e1 < e2; } };
	template<class T>
	class greater { bool operator()(T& e1, T& e2) { return e1 > e2; } };

	template<class T, class Container = std::vector<T>, class Compare = less<T>>
	class priority_queue {
	public:
		priority_queue():_con() {}
		template<class InputIterator>
		priority_queue(InputIterator begin, InputIterator end) : _con(begin, end) {
			//数据的输入
			//while (begin != end) {
			//	_con.push_back(*begin);
			//	++begin;
			//}

			//数据的大小堆建立
			for (int i = (_con.size() - 1 - 1) >> 1; i >= 0; --i)
				Adjust_down(i);
		}

		void Pop() {
			assert(!empty());

			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			Adjust_down(0);
		}

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

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

		void push(T x) {
			_con.push_back(x);
			Adjust_up(_con.size() - 1);
		}

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

		//向下排序
		void Adjust_down(size_t parent) {
			size_t child = parent * 2 + 1;
			while (child < _con.size()) {
				if (child + 1 < _con.size() && Compare()(_con[child], _con[child + 1]))
					++child;
				if (Compare()(_con[parent], _con[child])) {
					//将父节点子节点进行调换
					std::swap(_con[parent], _con[child]);
					//更新父、子节点的位置
					parent = child;
					child = parent * 2 + 1;
				}
				else{
					//堆已经建立成功
					break;
				}
					
			}
		}

		//向上排序
		void Adjust_up(size_t child) {
			size_t parent = (child - 1) >> 1;
			while (child) {
				if (Compare()(_con[parent], _con[child])) {
					//将父节点子节点进行调换
					std::swap(_con[parent], _con[child]);
					//更新父、子节点的位置
					child = parent;
					parent = (child - 1) >> 1;
				}
				else {
					//堆已经建立成功
					break;
				}
			}
		}
		Container _con;
	};
}
  • 13
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
C++ STL中的priority_queue是一个优先队列,它是一个使用堆来实现的容器。它可以按照一定的优先级顺序存储元素,并且每次访问队首元素都是访问优先级最高的元素。 在使用priority_queue时,可以通过定义不同的比较函数来指定元素的优先级顺序。默认情况下,对于基本类型,默认是大顶堆,降序队列。也可以通过指定参数来实现小顶堆,升序队列。例如: priority_queue<int, vector<int>, greater<int>> q; //小顶堆,升序队列 priority_queue<int, vector<int>, less<int>> q; //大顶堆,降序队列 在对priority_queue进行操作时,可以使用push()函数向队列中插入元素,使用top()函数获取队首元素,使用pop()函数删除队首元素。 在自定义类型的优先队列中,可以重载运算符>或<来定义优先级。例如,可以重载operator>来定义小顶堆,即优先级较小的元素排在前面。示例代码如下: struct Node{ int x, y; Node(int a=0, int b=0): x(a), y(b) {} }; bool operator> (Node a, Node b){ if(a.x == b.x) return a.y > b.y; return a.x > b.x; } priority_queue<Node, vector<Node>, greater<Node>> q; q.push(Node(rand(), rand())); while(!q.empty()){ cout<<q.top().x<<' '<<q.top().y<<endl; q.pop(); } 总结来说,C++ STL中的priority_queue是一个使用实现优先队列,可以按照指定的优先级顺序存储元素。可以通过定义不同的比较函数或重载运算符来指定优先级规则。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【总结】C++ 基础数据结构 —— STL优先队列priority_queue) 用法详解](https://blog.csdn.net/weixin_44668898/article/details/102132580)[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 ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

川入

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值