目录
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;
};
}
完