queue——priority_queue

priority_queue概述

在这里插入图片描述
优先级队列也是一个容器适配器,它的底层数据结构是用堆来实现的,用数组来模拟堆,所以它的底层容器也就是vector,后面是一个仿函数,大概就像sort函数一样,你可以提供自己的比较函数。
priority_queue默认数值更大的优先级更高。
当然我们也可以指定小的优先级更高,第三个参数指定为greater就行

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

这个greater在头文件functional中

priority_queue模拟实现

#pragma once

#include <vector>
using namespace std;

namespace csy {
	template <class T,class Container=vector<T>>
	class priority_queue {
	public:
		//如果自己写了构造函数,编译器将不会调用默认构造函数
		//所以还要自己定义一个无参的默认构造函数
		priority_queue()
		{

		}
		//迭代器区间构造函数
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push(*first);
				first++;
			}
			for (int i = (_con.size() - 1 - 1) / 2; i > 0; --i)
			{
				adjust_down(i);
			}
		}

		void adjust_up(size_t child)
		{
			size_t parent = (child-1)/2;
			while (child > 0)
			{
				if (_con[parent] < _con[child])
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1)/2;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void adjust_down(size_t parent)
		{
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				{
					child++;
				}

				if (_con[parent] < _con[child])
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

		const T& top() const
		{
			return _con[0];
		}

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

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
	};
}

这里还不够,我们这个模拟实现只能建大堆,库里面为了能随意转换大小堆,模板里面还有一个参数——仿函数

仿函数

仿函数/函数对象 – 类,重载operator()
类对象可以像函数一样去使用

template<class T>
class less
	{
	public:
		bool operator()(const T& l, const T& r) const
		{
			return l < r;
		}
	};
	less(1,2);
template <class T,class Container=vector<T>,class Compare=less<T>>

less虽然是一个对象,但是却可以像函数一样被调用,这种类就叫仿函数。
于是我们可以在优先队列的模板中添加参数,注意这里的参数是一个类型,所以我们添加的是一个仿函数类型而不是一个具体的对象
在private中添加一个仿函数对象就行,然后把函数中比较的地方换成仿函数调用。
新代码:

#pragma once

#include <vector>
using namespace std;

namespace csy {
	template <class T,class Container=vector<T>,class Compare=less<T>>
	class priority_queue {
	public:
		//如果自己写了构造函数,编译器将不会调用默认构造函数
		//所以还要自己定义一个无参的默认构造函数
		priority_queue()
		{

		}
		//迭代器区间构造函数
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push(*first);
				first++;
			}
			for (int i = (_con.size() - 1 - 1) / 2; i > 0; --i)
			{
				adjust_down(i);
			}
		}

		void adjust_up(size_t child)
		{
			size_t parent = (child-1)/2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				if(_cmp(_con[parent] , _con[child]))
				{
					swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1)/2;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void adjust_down(size_t parent)
		{
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _cmp(_con[child] , _con[child+1]))
				{
					child++;
				}

				//if (_con[parent] < _con[child])
				if(_cmp(_con[parent] , _con[child]))
				{
					swap(_con[parent], _con[child]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

		const T& top() const
		{
			return _con[0];
		}

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

		size_t size()
		{
			return _con.size();
		}
	private:
		Container _con;
		Compare _cmp;
	};
}

还有一个小问题,我们查看priority文档,会发现它有这样一个构造函数

explicit priority_queue (const Compare& comp = Compare(),
                         const Container& ctnr = Container());

这个构造函数首先需要明确的是传进去的是一个具体的Compare对象,跟algorithm中的sort函数类似
但是非常非常重要一点的是,我们需要知道,前者是在构造函数传的引用,用来构造这个优先队列对象的,你传进去的这个参数可能会在其他成员函数中被继续使用,比如push或者pop函数,而sort只是一个函数,传进去的对象也只有自己使用,出了函数被销毁了也无所谓,所以我们经常传进去一个匿名对象,但需要注意的是,构造priority_queue对象时,千万不能传匿名的Compare对象,这个匿名对象在构造函数结束后就失效了,那么在push或者pop的时候可能就会出现野指针,程序就崩溃了。
同时还要注意的是,我们是这样使用这个函数的:

std::priority_queue<int> pq(ls);

模板参数因为你只传了int,所以其他两个默认就是vector和less,所以构造函数参数也必须是less,否则就冲突了。
至于为什么是const对象,自然是怕你修改,如果在函数内Compare对象被修改了,也可能会出现未知的问题。

priority_queue类模板中仿函数与大小堆的关系

其实就是你如果想要大堆的话,那么拍出来的序列就是升序,那么对于这个序列中的两个值来说,这个仿函数应该满足,对于给定的要比较的两个值,如果a在这个序列中在b的前面,那么就返回true,否则返回false
所以为什么我们的优先级队列默认是大堆,并且传Less呢,因为大堆就是升序,所以对于给定的两个数,如果a在b的前面,就是a<b,就要返回true,所以需要用less

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值