C++ priority_queue优先级队列
C++ priority_queue优先级队列(堆)
1. priority_queue的介绍和使用
1.1 queue的介绍
priority_queue的文档
priority_queue就是堆(优先级队列),分大根堆和小根堆
1.2 queue的使用
下面就介绍priority_queue的常用接口
1.2.1 成员函数
Member functions | 接口说明 |
---|---|
empty | 判断priority_queue是否为空,是空返回true,非空返回false |
size | 返回priority_queue中元素的个数 |
top | 返回priority_queue堆顶元素 |
push | 压堆,并且自动维护堆的性质(大根堆/小根堆) |
pop | 删除priority_queue堆顶元素 |
swap | 交换两个priority_queue的内容 |
#include <iostream>
#include <queue>
using namespace std;
int main()
{priority_queue<int> heap1; // 默认为大根堆priority_queue<int, vector<int>, less<int>> heap2 = heap1; // 大根堆priority_queue<int, vector<int>, greater<int>> heap3; // 小根堆heap1.push(1);heap1.push(4);heap1.push(3);heap1.push(2);heap1.push(6);heap1.push(5);while (!heap1.empty()){cout << heap1.top() << endl;heap1.pop();}heap1.swap(heap2);return 0;
}
2. priority_queue底层实现
2.1 容器适配器(配接器)
根据文档说明 priority_queue 是一种 container adaptor 即适配器
2.1.1 什么是适配器(配接器)
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另一个接口
C++STL中有三种适配器:
- container adapter 两个容器 stack 、queue其实是适配器
- iterator adapter
- function adapter 改变仿函数的接口者
2.2 仿函数
2.2.1 仿函数的定义
仿函数(Functor)是一种行为类似函数的对象,它可以被用作函数并接受参数。在C++中,仿函数通常是重载了函数调用运算符即
()
operator()()
,仿函数可以像函数一样被调用,并且可以保存状态信息。
按照操作数划分:一元仿函数、二元仿函数…
按照功能划分:算数运算、关系运算、逻辑运算
2.2.2 仿函数的结构
下面就是一个典型的一个Less的仿函数(即前面比后面Less更小)
template<class T>
strcut Less
{bool operator()(const T& x, const T& y) // ()运算符重载{return x < y;}
}
C++的 <functional>
文件中也有内置的仿函数 less
与 greater
2.2.3 仿函数的使用
仿函数的功能类似函数指针,将仿函数作为参数传递给算法,并且满足STL对抽象性的要求(运用模板技术)。
方法一:
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
int main()
{vector<int> v;srand(unsigned(time(0)));for (int i = 0; i < 10; ++i){v.push_back(rand() % 100);}sort(v.begin(), v.end(), less<int>()); // 传送less<int>()的匿名对象(升序)// sort(v.begin(), v.end(), greater<int>()) (降序)for (auto& e : v){cout << e << " ";}cout << endl; return 0;
}
方法二:
int main()
{priority_queue<int, vector<int>, less<int>> heap; // less<int>作为一种类型传给模板,大根堆//priority_queue<int, vector<int>, greater<int> heap; // 小根堆heap.push(1);heap.push(4);heap.push(3);heap.push(2);heap.push(6);heap.push(5);while (!heap.empty()){cout << heap.top() << endl;heap.pop();}cout << endl;return 0;
}
2.3 模拟实现priority_queue
priority_queue.h
#pragma once#include <vector>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;}
};namespace Alen
{template<class T, class Container = vector<T>, class Compare = Less<T>>class priority_queue{public:void AdjustUp(int child){Compare com; // 实例化仿函数的对象 int parent = (child - 1) / 2;while (child > 0){//if (_con[parent] < _con[child]) // 建大堆if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void AdjustDown(int parent){Compare com;size_t child = parent * 2 + 1;size_t size = _con.size();while (child < size){// 找出比较大的孩子if (child + 1 < size && _con[child] < _con[child + 1]){++child;}//if (_con[parent] < _con[child])if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);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(){return _con[0];}size_t size() const{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;};
}
这就是利用适配器的思想,调用已有的容器接口来完成客户期望的接口,并且采用引入了仿函数的用法,将大小根堆变化更加自由灵活,不需要更改原代码或者拷贝另一份。