priority_queue 的介绍
1.优先队列的底层是用堆实现的,而且默认大堆。
2.优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的一个。
3.优先队列可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
4.优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为底层容器类,queue 提供一组特定的成员函数来访问其元素,元素从特定元素的尾部弹出,其成为优先队列的顶部。
5.底层容器可以是任意标准类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问,迭代器访问,并支持以下操作:
*empty():检验容器是否为空
*size():返回容器中有效元素个数
*front():返回容器中第一个元素的引用
*push_back():在容器尾部插入元素
*pop_back():删除容器尾部的元素
6.标准容器类vector和deque都满足这些条件,但默认会使用vector容器。
7.需要支持随机访问迭代器,以便在内部始终保持堆结构。容器适配器通过在需要时自动调用算法函数来完成所需操作。
priority_queue 的使用
1.默认情况下,创建大堆,底层按小于号比较
此时第三个模板参数默认less
#include <queue>
#include <vector>
#include <functional> //greater算法的头文件
#include<iostream>
using namespace std;
int main()
{
priority_queue<int> q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
q1.push(5);
while (!q1.empty())
{
cout << q1.top() << " ";
q1.pop();
}
cout << endl;
system("pause");
return 0;
}
结果如下:
2.如果要创建小堆,需要用到仿函数修饰优先级
此时要加头文件< functional> 并按下面的模板
template <class T, class Container = vector,class Compare = less >
将第三个模板参数换成gerater 比较方式:此时代码实现及结果
int main()
{
priority_queue<int,vector<int>,greater<int>> q1;
q1.push(1);
q1.push(2);
q1.push(3);
q1.push(4);
q1.push(5);
while (!q1.empty())
{
cout << q1.top() << " ";
q1.pop();
}
cout << endl;
system("pause");
return 0;
}
3.如果在priority_queue 中放自定义类型的数据,用户需要在自定义类型中提供> 或< 的重载。(只要有> <的重载即可)
这里,我以日期类为例,供大家参考。
class Date
{
public:
Date(int year = 1999, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{}
bool operator < (const Date& d)const //重载小于号
{
return (_year < d._year) ||
(_year == d._year && _month < d._month)||
(_year == d._year && _month == d._month && _day < d._day);
}
bool operator >(const Date& d)const //重载大于号
{
return (_year > d._year) ||
(_year == d._year && _month > d._month)||
(_year == d._year && _month == d._month && _day > d._day);
}
//重载输出符号
friend ostream &operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << "-" << d._month << "-" << d._day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
void TestPQ()
{
priority_queue<Date> q2; //此时默认大堆,只要在自定义类型中提供< 的重载
q2.push(Date(2018, 12, 11));
q2.push(Date(2014, 11, 01));
q2.push(Date(2014, 12, 14));
q2.push(Date(2015, 03, 21));
while (!q2.empty())
{
cout << q2.top() << " ";
q2.pop();
}
}
如果要建小堆,只要在自定义类型中提供> 的重载
priority_queue<Date, vector<Date>, greater<Date>> q2;
4.有些情况下,用户可能要自己提供比较规则
下面我写了一个商品按价格排序的实例,供大家理解。
class Goods
{
public:
bool operator<(const Goods r) const //重载小于号
{
return _price < r._price;
}
public:
int _price;
int _sales_volume;
int _evaluation;
int _comprehensive;
};
struct GoodsPriceLess //大堆的比较规则
{
bool operator()(const Goods& l, const Goods& r)
{
return l._price < r._price;
}
};
struct GoodsPriceGreater //小堆的比较规则
{
bool operator()(const Goods& l, const Goods& r)
{
return l._price > r._price;
}
};
void TestPQ3()
{
priority_queue<Goods, vector<Goods>, GoodsPriceLess> goodspq;
goodspq.push(Goods{ 1, 8, 8, 4 });
goodspq.push(Goods{ 9, 8, 7, 6 });
// 只按价格比
Goods top = goodspq.top();
cout << top._price << " ";
cout << top._sales_volume << " ";
cout << top._evaluation << " ";
cout << top._comprehensive << endl;
}
模拟实现 priority_queue 的功能
因为优先队列的底层是堆,所以在进行push和pop时,需要进行调堆。
附以下代码供大家参考。
template<class T, class Container = vector<T>, class Compare = less<T>>
class PriorityQueue
{
public:
void Adjustup(int child) //向上调堆
{
int parent = (child - 1) >> 1;
while (child > 0)
{
Compare com;
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
child = parent;
parent = (child - 1) >> 1;
}
else
{
break;
}
}
}
void Push(const T& x)
{
_con.push_back(x);
Adjustup(_con.size() - 1);
}
void AdjustDown(int parent) //向下调堆
{
int child = parent * 2 + 1;
while (child < _con.size())
{
Compare com;
if (child + 1 < _con.size()
&& com(_con[child], _con[child + 1]))
{
++child;
}
if (com(_con[parent], _con[child]))
{
swap(_con[parent], _con[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void Pop()
{
swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
AdjustDown(0);
}
const T& Top()
{
return _con[0];
}
size_t Size()
{
return _con.size();
}
bool Empty()
{
return _con.empty();
}
private:
Container _con;
};
void TestPQ4()
{
PriorityQueue<int> q4;
q4.Push(4);
q4.Push(3);
q4.Push(8);
q4.Push(1);
cout << q4.Top() << endl;
}
我暂时就写到这里啦,大家有其他想法和建议欢迎留言讨论哟~