目录
①. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
②. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
③. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
④. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
⑤. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
⑥. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
调整的基本思想如下:
- 将目标结点与其父结点进行比较。
- 若目标结点的值比父结点的值大,则交换目标结点与其父结点的位置,并将原目标结点的父结点当作新的目标结点继续进行向上调整;若目标结点的值比其父结点的值小,则停止向上调整,此时该树已经是大堆了。
代码实现:
- //堆的向上调整(大堆)
- void AdjustUp(vector<int>& v, int child)
- {
- size_t parent = (child - 1) / 2; //通过child计算parent的下标
-
- while (child > 0)//调整到根结点的位置截止
- {
- if (v[parent] < v[child])//孩子结点的值大于父结点的值
- {
- //将父结点与孩子结点交换
- swap(v[child], v[parent]);
-
- //继续向上进行调整
- child = parent;
- parent = (child - 1) / 2;
- }
- else//已成堆
- {
- break;
- }
- }
- }
调整的基本思想如下:
- 将目标结点与其较大的子结点进行比较。
- 若目标结点的值比其较大的子结点的值小,则交换目标结点与其较大的子结点的位置,并将原目标结点的较大子结点当作新的目标结点继续进行向下调整;若目标结点的值比其较大子结点的值大,则停止向下调整,此时该树已经是大堆了。
代码实现:
- //堆的向下调整(大堆)
- void AdjustDown(vector<int>& v, int n, int parent)
- {
- //child记录左右孩子中值较大的孩子的下标
- int child = 2 * parent + 1;//先默认其左孩子的值较大
-
- while (child < n) //child不能越界
- {
- if (child + 1 < n && v[child] < v[child + 1])//右孩子存在并且右孩子比左孩子还大
- {
- child++;//较大的孩子改为右孩子
- }
-
- if (v[parent] < v[child])//左右孩子中较大孩子的值比父结点还大
- {
- //将父结点与较小的子结点交换
- swap(v[child], v[parent]);
-
- //继续向下进行调整
- parent = child;
- child = 2 * parent + 1;
- }
- else//已成堆
- {
- break;
- }
- }
- }
- namespace XM //防止命名冲突
- {
- //比较方式(使内部结构为大堆)
- template<class T>
- struct less
- {
- bool operator()(const T& x, const T& y)
- {
- return x < y;
- }
- };
-
- //比较方式(使内部结构为小堆)
- template<class T>
- struct greater
- {
- bool operator()(const T& x, const T& y)
- {
- return x > y;
- }
- };
-
-
- //优先级队列的模拟实现
- template<class T, class Container = vector
, class Compare = less> - class priority_queue
- {
- public:
- //堆的向上调整
- void AdjustUp(int child)
- {
- int parent = (child - 1) / 2; //通过child计算parent的下标
- while (child > 0)//调整到根结点的位置截止
- {
- if (_comp(_con[parent], _con[child]))//通过所给比较方式确定是否需要交换结点位置
- {
- //将父结点与孩子结点交换
- swap(_con[child], _con[parent]);
-
- //继续向上进行调整
- child = parent;
- parent = (child - 1) / 2;
- }
- else//已成堆
- {
- break;
- }
- }
- }
-
- //插入元素到队尾(并排序)
- void push(const T& x)
- {
- _con.push_back(x);
- AdjustUp(_con.size() - 1); //将最后一个元素进行一次向上调整
- }
-
- //堆的向下调整
- void AdjustDown(int n, int parent)
- {
- int child = 2 * parent + 1;
- while (child < n)
- {
- if (child + 1 < n&&_comp(_con[child], _con[child + 1]))
- {
- child++;
- }
-
- if (_comp(_con[parent], _con[child]))//通过所给比较方式确定是否需要交换结点位置
- {
- //将父结点与孩子结点交换
- swap(_con[child], _con[parent]);
-
- //继续向下进行调整
- parent = child;
- child = 2 * parent + 1;
- }
- else//已成堆
- {
- break;
- }
- }
- }
-
- //弹出队头元素(堆顶元素)
- void pop()
- {
- swap(_con[0], _con[_con.size() - 1]);
- _con.pop_back();
- AdjustDown(_con.size(), 0); //将下标为0个元素进行一次向下调整
- }
-
- //访问队头元素(堆顶元素)
- T& top()
- {
- return _con[0];
- }
- const T& top() const
- {
- return _con[0];
- }
-
- //获取队列中有效元素个数
- size_t size() const
- {
- return _con.size();
- }
-
- //判断队列是否为空
- bool empty() const
- {
- return _con.empty();
- }
- private:
- Container _con; //底层容器
- Compare _comp; //比较方式
- };
- }
(1)关于priority_queue底层堆的调整
(2)仿函数实现比较方式