【C++】priority_queue的使用及模拟实现(含仿函数介绍)
文章目录
- 前言
- 一、 priority_queue的介绍
- 二、priority_queue的使用
- 三、仿函数
- 四、priority_queue的模拟实现
前言
一、 priority_queue的介绍(优先级队列是默认使用vector作为其底层存储数据的容器适配器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆)
二、priority_queue的使用 及 模拟实现
三、仿函数的介绍(通过重载函数调用运算符 operator() 使对象能够像函数一样被调用的编程方式)
一、 priority_queue的介绍
优先级队列是默认使用vector作为其底层存储数据的容器适配器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的地方,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。
priority_queue是堆结构,需要具备push_back()、pop_back()操作 并且 支持随机访问迭代器(堆排序需要支持随机访问)的线性结构,才可以作为priority_queue的底层容器,比如vector和deque都可以。默认情况下,如果没有为priority_queue实例化指定容器类,则使用标准容器vector(vector和deque的尾插尾删性能接近,但vector的随机访问效率优于deque)。
二、priority_queue的使用
函数声明 | 接口说明 |
---|---|
priority_queue( ) | 构造一个空的优先级队列 |
template < class InputIterator > priority_queue (InputIterator first, InputIterator last) | 用迭代器区间构造优先级队列 |
empty( ) | 检测优先级队列是否为空 |
size( ) | 返回优先级队列中元素的个数 |
top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop( ) | 删除优先级队列中最大(最小元素),即堆顶元素 |
示例一(两种构造优先级队列的方式):
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
priority_queue<int> pri1; // 构造一个空的优先级队列
pri1.push(5);
pri1.push(6);
pri1.push(9);
pri1.push(4);
pri1.push(2);
while (!pri1.empty())
{
cout << pri1.top() << ' ';
pri1.pop();
}
cout << endl;
vector<int> vec{ 5,6,9,4,2 };
priority_queue<int> pri2(vec.begin(),vec.end()); // 用迭代器区间构造优先级队列
while (!pri2.empty())
{
cout << pri2.top() << ' ';
pri2.pop();
}
cout << endl;
return 0;
}
示例二(优先级队列默认是大堆,通过修改比较规则(显示传greater仿函数),可将优先队列变为小堆):
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
priority_queue<int, vector<int>, greater<int>> pri1;
pri1.push(5);
pri1.push(6);
pri1.push(9);
pri1.push(4);
pri1.push(2);
while (!pri1.empty())
{
cout << pri1.top() << ' ';
pri1.pop();
}
cout << endl;
return 0;
}
三、仿函数
在C++中,仿函数是一种通过重载函数调用运算符 operator() 使对象能够像函数一样被调用的编程方式。
#include <iostream>
using namespace std;
namespace zh
{
class Add
{
public:
int operator()(int a, int b) {
return a + b;
}
};
class less
{
public:
int operator()(int a, int b) {
return a < b;
}
};
class greater
{
public:
int operator()(int a, int b) {
return a > b;
}
};
}
int main()
{
zh::Add add;
zh::greater grt;
zh::less ls;
int a = 8;
int b = 6;
cout << add(8, 6) << endl; // add(8, 6) 等于 add.operator()(8,6)
cout << grt(8, 6) << endl; // grt(8, 6) 等于 grt.operator()(8,6)
cout << ls(8, 6) << endl; // ls(8, 6) 等于 ls.operator()(8,6)
return 0;
}
四、priority_queue的模拟实现
#include <vector>
#include <assert.h>
using namespace std;
namespace zh
{
template<class T>
struct less // 模拟实现less类
{
bool operator()(const T& left, const T& right)
{
return left < right;
}
};
template<class T>
struct greater // 模拟实现greater类
{
bool operator()(const T& left, const T& right)
{
return left > right;
}
};
template <class T, class Container = vector<T>,class Compare = less<T> >
class priority_queue
{
private:
void adjustup(int child) // 向上调整算法
{
int parent = (child - 1) / 2;
while (child)
{
if (com(con[parent], con[child]))
{
std::swap(con[child], con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
void adjustdown(int parent) // 向下调整算法
{
int son = 2 * parent + 1;
while (son < con.size())
{
if (son + 1 < con.size() && com(con[son], con[son + 1]))
{
son += 1;
}
if (com(con[parent], con[son]))
{
std::swap(con[parent], con[son]);
parent = son;
son = 2 * parent + 1;
}
else
break;
}
}
public:
priority_queue()
{ }
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
:con(first,last)
{
int cur = con.size() - 1;
int root = (cur - 1) / 2;
while (root >= 0)
{
adjustdown(root);
root--;
}
}
bool empty() const
{
return con.empty();
}
size_t size() const
{
return con.size();
}
const T& top() const
{
return con[0];
}
T& top()
{
return con[0];
}
void push(const T& x)
{
con.push_back(x);
adjustup(con.size() - 1);
}
void pop()
{
assert(con.size());
std::swap(con[0], con[con.size() - 1]);
con.pop_back();
adjustdown(0);
}
void swap(priority_queue& ctr)
{
con.swap(ctr.con);
}
private:
Container con;
Compare com;
};
}