赞
踩
目录
1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元 素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭 代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素
5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指 定容器类,则使用vector。
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap和pop_heap来自动完成此操作。
综上所述:
优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成 堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。
成员函数 | 功能 |
---|---|
push | 插入元素到队尾(并排序) |
pop | 弹出队头元素(堆顶元素) |
top | 访问队头元素(堆顶元素) |
size | 获取队列中有效元素个数 |
empty | 判断队列是否为空 |
swap | 交换两个队列的内容 |
举例:
- #include<iostream>
- #include<queue>
- #include<functional>
- #include<vector>
- #include<assert.h>
- using namespace std;
- #include"priority_Queue.h"
-
- //优先级队列
- void test_priority_queue1()
- {
- //默认是大的优先级高 -- 默认给的仿函数是less
- priority_queue<int> pq;
- //
- //控制小的优先级高 -- 给一个greater的仿函数
- //priority_queue<int, deque<int >, greater<int>> pq;
- pq.push(3);
- pq.push(3);
- pq.push(7);
- pq.push(1);
- pq.push(9);
- while (!pq.empty())
- {
- cout << pq.top() << " ";
- pq.pop();
- }
- cout << endl;
- }
优先级队列的底层就是堆,所以大多知识我们在堆那一节课已经学过!
我们去看文档的时候会发现优先级队列priority_queue有三个参数:第一个是我们所要存放数据的类型,第二个使我们所要使用的容器,那么第三个是什么呢?
我们在前面就学过,优先级默认情况下是大堆,也就是数据以降序的方式存放,第三个参数的意义就是我们可以也可以让它以升序的方式存放,我们先举例说明:
- void test_priority_queue1()
- {
- //默认是大的优先级高并且如果我们不给容器的话会默认给vector的容器
- priority_queue<int> pq;
- pq.push(8);
- pq.push(2);
- pq.push(3);
- pq.push(7);
- pq.push(6);
- pq.push(5);
- pq.push(4);
- while (!pq.empty())
- {
- cout << pq.top() << " ";
- pq.pop();
- }
- cout << endl;
- }
运行结果:
如果我们想实现升序,可以传入第三个参数greater<T>
通过查看文档我们能发现它需要头文件<functional>
- void test_priority_queue1()
- {
- //传入greater后为升序
- priority_queue<int,vector<int>,greater<int>> pq;
- pq.push(8);
- pq.push(2);
- pq.push(3);
- pq.push(7);
- pq.push(6);
- pq.push(5);
- pq.push(4);
- while (!pq.empty())
- {
- cout << pq.top() << " ";
- pq.pop();
- }
- cout << endl;
- }
那么为什么会这样呢?
其实我们所见的greater是一个仿函数。
他们的底层如下所示:
- template<class T>
- struct Less
- {
- bool operator()(const T& x, const T& y) const
- {
- return x < y;
- }
- };
-
- template<class T>
- struct Greater
- {
- bool operator()(const T& x, const T& y) const
- {
- return x > y;
- }
- };
这里的Less类其实就是我们在优先级队列给它第三个参数的缺省参数,这也是为什么默认是大堆的原因。
这里除了可以对普通的数据进行排序,其实对日期数据也可以排序!
首先我们给定一个日期类,并且重载了日期的输出的运算符和比较运算符。
-
- class Date
- {
- friend struct LessPDate;
- 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);
- private:
- int _year;
- int _month;
- int _day;
- };
-
- ostream& operator<<(ostream& _cout, const Date& d)
- {
- _cout << d._year << "-" << d._month << "-" << d._day << endl;
- return _cout;
- }
- void test_priority_queue2()
- {
- priority_queue<Date, vector<Date>> pq;
- //priority_queue<Date, vector<Date>,greater<Date>> pq;
- pq.push(Date(2022, 3, 26));
- pq.push(Date(2021, 10, 26));
- pq.push(Date(2023, 3, 26));
-
- while (!pq.empty())
- {
- cout << pq.top();
- pq.pop();
- }
- cout << endl;
- }
当然我们也可以使用库中的greater或者我们实现的仿函数来使其实现降序。
- #pragma once
-
- namespace mwb
- {
-
- template<class T>
- struct Less
- {
- bool operator()(const T& x, const T& y) const
- {
- return x < y;
- }
- };
-
- template<class T>
- struct Greater
- {
- bool operator()(const T& x, const T& y) const
- {
- return x > y;
- }
- };
-
- //大的优先级高 大堆
- template< class T, class Container = vector<T>,class Compare=Less<T> >
- class priority_queue
- {
- private:
- void adjust_up(size_t child)//向上调整算法
- {
- Compare com;
- size_t parent = (child - 1) / 2;
- while (child > 0)
- {
- //if (_con[child] > _con[parent])
- if(com(_con[parent],_con[child]))
- {
- swap(_con[child], _con[parent]);
- child = parent;
- parent = (child - 1) / 2;
- }
- else
- {
- break;
- }
- }
- }
-
- void adjust_down(size_t parent)
- {
- Compare com;
- size_t child = (parent * 2) + 1;
- //默认给左孩子
- while (child<_con.size())
- {
- //if (child + 1 < _con.size() && _con[child + 1] > _con[child])
- if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
- {
- child++;//如果右孩子大于左孩子那么取右孩子
- }
- //if (_con[child] > _con[parent])
- if(com(_con[parent],_con[child]))
- {
- swap(_con[child], _con[parent]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
- public:
- priority_queue()
- {}
-
- template <class InputIterator>
- priority_queue(InputIterator first, InputIterator last)
- :_con(first,last)
- {
- // 建堆
- for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
- {
- adjust_down(i);
- }
- }
-
- void push(const T& x)
- {
- _con.push_back(x);
- adjust_up(_con.size() - 1);
- }
- void pop()
- {
- assert(!_con.empty());//检测是否为空
-
- swap(_con[0], _con[_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;
-
- };
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。