C++STL----priority_queue的使用与模拟实现

priority_queue简介

  1. priority_queue(优先队列)是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的

  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。

  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

  4. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector

  5. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

注意: 默认情况下priority_queue是大堆。

priority_queue的使用

使用vector作为底层容器,内部构造大堆结构。

priority_queue<int, vector<int>, less<int>> q1;

使用vector作为底层容器,内部构造小堆结构。

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

不指定底层容器和内部需要构造的堆结构。

priority_queue<int> q;

注意: 此时默认使用vector作为底层容器,内部默认构造大堆结构。

priority_queue各个接口的使用

成员函数功能
push插入元素到队尾(并排序)
pop弹出队头元素(堆顶元素)
top访问队头元素(堆顶元素)
size获取队列中有效元素个数
empty判断队列是否为空
swap交换两个队列的内容

实列:

#include <iostream>
#include <functional>
#include <queue>
using namespace std;
int main()
{
	priority_queue<int> q;
	q.push(3);
	q.push(6);
	q.push(0);
	q.push(2);
	q.push(9);
	q.push(8);
	q.push(1);
	while (!q.empty())
	{
		cout << q.top() << " ";
		q.pop();
	}
	cout << endl; //9 8 6 3 2 1 0
	return 0;
}

仿函数

仿函数也叫函数对象,是定义了一个含有operator()成员函数的对象,可以视为一个一般的函数,只不过这个函数功能是在一个类中的运算符operator()中实现,它将函数作为参数传递的方式来使用。也就是将类按照函数的使用方式使用。

仿函数在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值

class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
		return v1 + v2;
	}
};
//1.函数对象在使用时,可以像普通函数那样调用,可以有参数和返回值
void test01()
{
	MyAdd myAdd;
	cout << myAdd(1, 2) << endl;//3
}

仿函数的优点:
1.仿函数可有拥有自己的数据成员和成员变量,比一般函数灵活。
2.仿函数比函数指针的执行速度快。
3.仿函数可以作为模板参数使用,因为每个仿函数都拥有自己的类型。

缺点:
1.需要单独实现一个类。
2.定义形式比较复杂。

priority_queue的模拟实现

priority_queue的底层实际上就是堆结构,故其核心就是实现向上调整向下调整算法。两种算法的具体细节参考堆的详解

#pragma once
#include<iostream>
#include<assert.h>
#include<vector>

using namespace std;
namespace lhj_3
{
    //仿函数/函数对象  ---类重载operator()
    //也就是类对象可以像函数一样去使用
    //比较方式(使内部结构为大堆)
    template<class T>
	class less
	{
	public:
		bool operator()(const T& l,const T& r) const
		{
			return l < r;
		}
	};
    //比较方式(使内部结构为小堆)
    //仿函数
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& l, const T& r) const
		{
			return l > r;
		}
	};
    //优先级队列的模拟实现
	template<class T ,class Container=vector<T>, class compare=less<T>>
	//compare是进行比较的仿函数  ---less 为大堆  greater为小堆
	class priority_queue
	{
	public:
        //构造函数
		priority_queue()
		{}
		//迭代器区间构造
		template <class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first!=last)
			{
				_con.push_back(*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 (chile>0)
			{
				//下面两个等价,compare为仿函数
				//if (_con[parent]<_con[child] )
				if (com(_con[parent] , _con[child]))
				{
					std::swap(_con[child], _con[parent]);
					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 = parent * 2 + 1;
			while (child<_con.size())
			{
				//选出左右孩子中大的那一个
				//if (child+1<_con.size()&&_con[child+1]>_con[child])
				//if (child + 1 < _con.size() &&  _con[child]<_con[child + 1])
				if (child + 1 < _con.size() && com(_con[child] , _con[child + 1]))
				{
					++child;
				}
				//if (_con[child]>_con[parent])
				//if (_con[parent]<_con[child])
				if (com(_con[parent] , _con[child]))
				{
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		//弹出队头元素(堆顶元素)
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();

			adjust_down(0);
		}

	private:
		Container _con;//底层容器
        Compare com; //比较方式
	};
}

迭代器适配器

反向迭代器

在这里插入图片描述

反向迭代器也就是迭代器适配器,可以适配生成任何支持++,–的容器的反向迭代器
在这里插入图片描述

反向迭代器大致框架

#pragma once
namespace it
{
	//复用,迭代器适配器
	template<class Iterator,class Ref,class Ptr>
	struct __reverse_iterator
	{
		Iterator _cur;
		typedef __reverse_iterator<Iterator, Ref> RIterator;
		//用正向迭代器构造出一个反向迭代器
		__reverse_iterator(Iterator it)
			:_cur(it)
		{}
		RIterator operator++()
		{
			--_cur;
			return *this;
		}
		RIterator operator--()
		{
			++_cur;
			return *this;
		}
		Ref operator*()
		{
			auto tmp = _cur;
			//rbegin指向正向迭代器中end的位置
        	//而end为尾结点的下一个节点的位置,即头结点
            //故需要将tmp--后再解引用
			--tmp;
			return *tmp;
		}
		Ptr operator->()
		{
			return &(operator*());
		}
		bool operator!=(const RIterator& it)
		{
			return _cur != it._cur;
		}
	};
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值