C++ priority_queue
小倪同学 -_- 人气:0priority_queue的使用
priority_queue简介
- 优先队列是一种容器适配器,有严格的排序标准,它的第一个元素总是它所包含的元素中最大的(或最小的)。
- 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆(或 最小堆)元素(优先队列中位于顶部的元素)。
- 默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
priority_queue的使用
成员函数 | 功能 |
---|---|
push | 插入数据 |
pop | 删除优先级队列中最大(最小)元素,即堆顶元素 |
top | 返回优先级队列中最大(最小)元素,即堆顶元素 |
empty | 检测优先级队列是否为空 |
size | 获取队列中有效元素个数 |
void TestPriorityQueue() { // 默认情况下,创建的是大堆,其底层按照小于号比较 vector<int> v{ 3, 2, 7, 6, 0, 4, 1, 9, 8, 5 }; priority_queue<int> q1;// 构建优先级队列 for (auto e : v) q1.push(e);//尾插 cout << "q1中元素个数:" << q1.size() << endl; for (size_t i = 0;i<v.size();++i) { cout << q1.top() << " ";//输出栈顶的数据 q1.pop();//尾删 } cout << endl; cout << "q1中元素个数:" << q1.size() << endl; cout << endl; // 如果要创建小堆,将第三个模板参数换成greater比较方式 priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end()); for (size_t i = 0; i<v.size(); ++i) { cout << q2.top() << " ";//输出栈顶的数据 q2.pop();//尾删 } cout << endl; }
如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。
class Date { 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); } 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 TestPriorityQueue() { // 大堆,需要用户在自定义类型中提供<的重载 priority_queue<Date> q1; q1.push(Date(2022, 1, 7)); q1.push(Date(2022, 1, 1)); q1.push(Date(2022, 1, 31)); cout << q1.top() << endl; cout << endl; // 如果要创建小堆,需要用户提供>的重载 priority_queue<Date, vector<Date>, greater<Date>> q2; q2.push(Date(2022, 1, 7)); q2.push(Date(2022, 1, 1)); q2.push(Date(2022, 1, 31)); cout << q2.top() << endl; }
priority_queue的模拟实现
priority_queue的底层实际上就是堆结构,可以参考博主之前写的有关堆的文章数据结构之堆
namespace nzb { //比较方式(使内部结构为大堆) template<class T> class Less { public: bool operator()(const T& x, const T& y) { return x < y; } }; //比较方式(使内部结构为小堆) template<class T> class Greater { public: bool operator()(const T& x, const T& y) { return x > y; } }; template<class T, class Container = 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 (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) { AdjustDown(i); } } //堆的向上调整 void AdjustUp(size_t child) { size_t parent = (child - 1) / 2;//找到父节点 while (child > 0) { if (_com(_con[parent], _con[child]))//判断是否需要交换 { //交换父子结点 swap(_con[parent], _con[child]); //继续向上调整 child = parent; parent = (child - 1) / 2; } else { break; } } } //向下调整 void AdjustDown(size_t parent) { size_t child = parent * 2 + 1;//算出左子节点的下标 while (child < _con.size()) { //找出子结点中符合比较方式的值 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 push(const T& x) { _con.push_back(x); AdjustUp(_con.size() - 1);//将最后一个元素向上调整 } //删除数据 void pop() { swap(_con[0], _con[_con.size() - 1]);//交换首尾数据 _con.pop_back();//尾删 AdjustDown(0);//首元素向下调整 } //访问头元素 const T& top() const { return _con[0]; } //获取队列中有效元素个数 size_t size() { return _con.size(); } //判空 bool empty() { return _con.empty(); } private: Container _con;//底层容器 Compare _com;//比较方式 }; }
加载全部内容