priority_queue
- priority_queue 简单介绍
- priority_queue 使用
- 内置类型测试
- 自定义类型测试
- priority_queue 模拟实现
- 仿函数(less、greater)
priority_queue 简单介绍
优先级队列是一种容器适配器。类似于堆,可以随时插入元素,只能检索优先级队列中位于顶部的元素。
priority_queue是作为容器适配器实现的,容器适配器是对特定容器类封装,作为其底层的容器。vector、deque符合priority_queue需求,如果没有指定特定的底层容器,默认使用vector。需要支持随机访问迭代器,以便内部保持堆结构。
priority_queue 使用
在默认底层容器vector中使用堆算法,将vector中的元素构成堆的结构,所以priority_queue就是堆。
使用场景:在需要用到堆的位置。priority_queue默认是大堆。
函数 | 接口说明 |
---|---|
priority_queue() | 构造空的优先级队列 |
priority_queue(first, last) | 迭代器范围构造优先级队列 |
empty() | 判断优先级队列是否为空 |
top() | 返回堆顶元素的const引用 |
push(val) | 将val插入优先级队列中 |
pop() | 删除堆顶元素 |
内置类型测试
void test_priority_queue()
{//默认是大堆 -- less less在sort中对应的是升序,但是在priority_queue中建的大堆//priority_queue<int> pq;//仿函数greater控制建小堆priority_queue<int, vector<int>, greater<int>> pq;pq.push(5);pq.push(10);pq.push(3);pq.push(1);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;
}
test2:
void test_priority_queue()
{vector<int> v{ 3,2,7,6,0,4,1,9,8,5 };//默认大堆priority_queue<int> pq;for (auto& e : v){pq.push(e);}cout << pq.top() << endl;//创建小堆priority_queue<int, vector<int>, greater<int>> pq1(v.begin(), v.end());cout << pq1.top() << endl;
}
自定义类型测试
如果是自定义类型的数据,用户需要提供大于(>)或者小于(<)的重载
class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);public:Date(int year = 1900, 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);}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}void test_priority_queue()
{// 大堆,需要用户在自定义类型中提供<的重载priority_queue<Date> pq1;pq1.push(Date(2023, 8, 6));pq1.push(Date(2023, 7, 6));pq1.push(Date(2023, 6, 6));cout << pq1.top() << endl;// 如果要创建小堆,需要用户提供>的重载priority_queue<Date, vector<Date>, greater<Date>> pq2;pq2.push(Date(2023, 8, 6));pq2.push(Date(2023, 7, 6));pq2.push(Date(2023, 6, 6));cout << pq2.top() << endl;
}
注意: 如果自定义类型没有重载用于比较的符号, 则程序运行错误。
priority_queue 模拟实现
priority_queue类模板实现,借用了一个容器vector和两个仿函数less、greater。如果想进一步观察priority_queue的逻辑结构,请点击该链接:堆的实现
#include <vector>
#include <assert.h>// priority_queue--->堆
namespace kpl
{template<class T>struct less{bool operator()(const T& left, const T& right){return left < right;}};template<class T>struct greater{bool operator()(const T& left, const T& right){return left > right;}};template<class T, class Container = std::vector<T>, class Compare = less<T>>class priority_queue{public:// 创造空的优先级队列priority_queue(){}/*template<class InputIterator>priority_queue(InputIterator first, InputIterator last){ //这里可以不使用初始化列表//数据存入while (first != last){_con.push_back(*first);++first;}//向下调整建堆for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; --i){AdjustDown(i);}}*/template<class InputIterator>priority_queue(InputIterator first, InputIterator last): _con(first, last){// 将_con中的元素调整成堆的结构//向下调整建堆for (size_t i = (_con.size() - 1 - 1) / 2; i >= 0; --i){AdjustDown(i);}}void push(const T& data){_con.push_back(data);AdjustUP(_con.size() - 1);}void pop(){assert(!_con.empty());swap(_con.front(), _con.back());_con.pop_back();AdjustDown(0);}size_t size()const{return _con.size();}bool empty()const{return _con.empty();}// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性const T& top()const{return _con.front();}private:// 向上调整void AdjustUP(int child){int parent = (child - 1) / 2;while (child){if (_com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}// 向下调整void AdjustDown(int parent){size_t child = parent * 2 + 1;while (child < _con.size()){// 找以parent为根的较大的孩子if (child + 1 < _con.size() && _com(_con[child], _con[child + 1]))child += 1;// 检测双亲是否满足情况if (_com(_con[parent], _con[child])){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}private:Container _con;Compare _com;};
}
仿函数(less、greater)
仿函数(functor)是一个能行使函数功能的类或结构体。它实际上是一个可调用的对象,可以像调用函数一样来使用它,传入参数并获得返回值。与普通函数不同的是,仿函数可以保存状态信息,并且可以被其他函数调用。为了成为一个仿函数,类或结构体必须重载 operator() 运算符。在C++中,仿函数通常用于STL算法中的自定义排序、查找、过滤等操作。
test1:
//仿函数/函数对象
template<class T>
struct less
{bool operator()(const T& left, const T& right){return left < right;}
};template<class T>
struct greater
{bool operator()(const T& left, const T& right){return left > right;}
};int main()
{less<int> lessFunc;cout << lessFunc(1, 2) << endl;cout << lessFunc.operator()(1, 2) << endl;cout << less<int>()(1, 2) << endl;
}
test2: 仿函数的匿名对象使用
int main()
{greater<int> g;vector<int> v{ 1,3,4,1,0 };sort(v.begin(), v.end(), g);//sort(v.begin(), v.end(), greater<int>());//greater<int>() --> 匿名对象for (auto e : v){cout << e << " ";}cout << endl;cout << greater<int>()(1, 2) << endl;cout << g(1, 2) << endl;
}