priority_queue优先级队列

目录

1.priority_queue介绍

2.priority_queue使用

3.仿函数比较

4.heap

5.priority_queue模拟实现


1.priority_queue介绍

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

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

优先队列被实现为容器适配器

容器适配器即将特定容器类封装作为其底层容器类

底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问

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


2.priority_queue使用

优先级队列默认使用vector作为其底层存储数据的容器,默认情况下priority_queue是大堆。

priority_queue()构造一个空的优先级队列
priority_queue(first,last)根据迭代器区间构造优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中最大(最小元素),即堆顶元素
size()返回优先级队列里的元素个数
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即堆顶元素

3.仿函数比较

priority_queue的模板参数有三个:

T队列元素的类型
Container 容器类型(默认vector)
Compare比较元素类型的仿函数类(默认less)(大堆)

对于内置类型或者已经支持< > 比较的类型,使用库里支持的less和greater就可以在头文件functional里。

less 是一个类operator重载了() 用来比较返回 true 或者 false

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

在需要比较的类里传类模板参数

template<class T , class Compare = less<T>>

在类的任何位置都可以使用,一般有两种方式:

1. 先 Compare 定义一个对象 com 然后 com(a,b) 来进行比较

2. Compare()(a,b) 匿名对象调用

这里com() 就像函数调用一样,实际上是类对()的重载,因为作用像函数,所以叫仿函数


4.heap

优先级队列底层就是一个堆(heap)

建一个堆的时间复杂度分两种情况

1.向下建堆

一句话,少的点挪动的次数多 时间复杂度约等于 T(N)

2.向上建堆

多的点挪动次数多  时间复杂度 T(N*LogN)

若是pop n次用来排序,时间复杂度 T(N*LogN) 

优先级队列,使用迭代器建堆,比遍历push,要好


5.priority_queue模拟实现

#pragma once

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


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

	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		Compare com;

		priority_queue() {};

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
			:_con(first, last)
		{
			//Container tmp(first, last);
			//swap(tmp, _con);
			for (int i = ((int)_con.size() - 1 - 1) >> 1; i >= 0; --i)
			{
				adjust_down(i);
			}
		}

		void adjust_up(size_t son)//T(log size())
		{
			size_t parent = (son - 1) / 2;
			while (son != 0)
			{
				if (com(_con[parent], _con[son]))
				{
					swap(_con[son], _con[parent]);
					son = parent;
					parent = (son - 1) / 2;
				}
				else
					break;
			}
		}

		void adjust_down(size_t parent)//T(log size())
		{
			size_t son = parent * 2 + 1;
			while (son < size())
			{
				if (son + 1 < size() && com(_con[son], _con[son + 1]))
				{
					++son;
				}
				if (com(_con[parent], _con[son]))
				{
					swap(_con[son], _con[parent]);
					parent = son;
					son = parent * 2 + 1;
				}
				else
					break;
			}
		}

		void push(T val)
		{
			_con.push_back(val);
			adjust_up(size()-1);
		}

		void pop()
		{
			swap(_con[0], _con[size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

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

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

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值