目录
1. priority_queue的介绍
1. 是一种容器适配器
2. 优先使用vector作为其底层存储数据的容器。
3. 使用了堆算法将vector中元素构造成堆的结构,所以priority_queue类似于堆,用的到堆的地方都可以考虑使用priority_queue。
4. 默认情况下priority_queue建立的是大堆。
5. 使用时只需包含#include<queue>即可
其底层容器需要支持随机访问迭代器(Random-access iterators)以便自身在内部始终保持堆结构。这些由容器适配器自动完成,通过自动调用算法函数make_heap、push_heap、pop_heap,完成操作
priority_queue的模板参数有三个
上图中的
1. T为存储的数据类型
2. Container为存储数据的底层容器
3. Compare为仿函数
2. 仿函数
(1). 概念
就是模仿函数的对象,它们可以通过重载operator() 来使得对象可以像函数一样被调用,即可以使用圆括号()来传递参数,返回结果
(2). 特点
-
通过重载operator(),仿函数对象可接收参数并返回结果,看起来类似于普通的函数
-
与普通函数不同,仿函数作为对象,可以拥有成员变量。这意味着它更加灵活
-
与模板结合提供类型安全的泛型编程。算法接收仿函数作为参数,已实现算法的灵活性
使用如下所示
#include<algorithm>
#include<vector>
#include<iostream>
int main()
{
std::vector<int> vec = { 3, 1, 4, 1, 5, 9, 2 };
sort(vec.begin(), vec.end());
for (int n : vec)//auto也可以
{
std::cout << n << ' ';
}
std::cout << std::endl;
// 使用 greater 对 vec 进行降序排序
sort(vec.begin(), vec.end(), std::greater<int>());
for (int n : vec)
{
std::cout << n << ' ';
}
std::cout << std::endl;
return 0;
}
以上代码中的greater就是仿函数(模板函数对象)通常用来比较大于,与之相对的less用来比较小于,我们上面传参数相当于传了个匿名对象
3. priority_queue的使用
函数声明 | 接口说明 |
priority_queue()/priority_queue(first,last) | 构造一个空的优先级队列/根据迭代器(左开右闭)构造空间 |
empty() | 检测优先级队列是否为空 |
top() | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中最大(最小)元素,即为堆顶元素 |
代码如下所示
#include<algorithm>
#include<vector>
#include<iostream>
#include<queue>
using namespace std;
int main()
{
vector<int> v{ 1,6,5,9,8,7,3,4 };
priority_queue<int> pq1;
priority_queue<int, vector<int>, greater<int>> pq2(v.begin(), v.end());
for (auto vv : v)
{
pq1.push(vv);
}
//默认创建的是大堆,由下输出可得
while(!pq1.empty())
{
cout << pq1.top() << " ";
pq1.pop();
}
cout << endl;
//可以通过greater<int>来创建小堆
while (!pq2.empty())
{
cout << pq2.top() << " ";
pq2.pop();
}
return 0;
}
输出结果如下
如果利用我们自己写的仿函数呢?
#include<algorithm>
#include<vector>
#include<iostream>
#include<queue>
using namespace std;
template <class T>
class greaternum
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
int main()
{
vector<int> v{ 1,6,5,9,8,7,3,4 };
priority_queue<int> pq1;
priority_queue<int, vector<int>, greaternum<int>> pq2(v.begin(), v.end());
for (auto vv : v)
{
pq1.push(vv);
}
//默认创建的是大堆,由下输出可得
while(!pq1.empty())
{
cout << pq1.top() << " ";
pq1.pop();
}
cout << endl;
//可以通过greater<int>来创建小堆
while (!pq2.empty())
{
cout << pq2.top() << " ";
pq2.pop();
}
return 0;
}
运行结果依然为
4. priority_queue模拟实现
(1). 如何插入时构建堆,删除时维持堆
这里我们就需要使用向上调整算法和向下调整算法了
namespace Pc
{
template<class T,class container=vector<T>,class compare=greater<T>>
class priority_queue
{
public:
void AdjustUp(int child)
{
compare adjust;
int parent = (child - 1) / 2;
while (child > 0)
{
//if(con[child]> con[parent])
if (adjust(con[child] , con[parent]))
{
swap(con[child] ,con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
break;
}
}
void AdjustDown(int head)
{
compare adjust;
int parent = head;
int child = parent * 2 + 1;
int n = con.size();
while (child < con.size())
{
//if (con.size()<child + 1 && con[child + 1]< con[child])
if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
{
child ++;
}
//if (con[child]< con[parent])
if (adjust(con[child] , con[parent]))
{
swap(con[child], con[parent]);
parent = child;
child = child * 2 + 1;
}
else
break;
}
}
private:
container con;
};
}
这里应用了仿函数,实现如下
template <class T>
class lessnum
{
public:
bool operator()( T a,T b)
{
return a < b;
}
};
template <class T>
class greaternum
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
比起用C语言实现堆少了一些参数,具体思路并没发生改变
(2). 成员函数实现具体功能
插入,删除,返回堆顶元素,判空,返回队列里元素个数
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);
}
T& top()
{
return con.back();
}
const T& top() const
{
return con.back();
}
bool empty()
{
return con.empty();
}
size_t size()
{
return con.size();
}
//void print()//用来方便观测优先级队列
//{
//for (int i = 0; i < size(); i++)
// {
// cout << con[i] << " ";
// }
// cout << endl;
}
5. 全部代码
(1). priority_queue.h
namespace Pc
{
template<class T,class container=vector<T>,class compare=greater<T>>
class priority_queue
{
public:
priority_queue() {}
void AdjustUp(int child)
{
compare adjust;
int parent = (child - 1) / 2;
while (child > 0)
{
//if(con[child]> con[parent])
if (adjust(con[child] , con[parent]))
{
swap(con[child] ,con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
break;
}
}
void AdjustDown(int head)
{
compare adjust;
int parent = head;
int child = parent * 2 + 1;
int n = con.size();
while (child < con.size())
{
//if (con.size()<child + 1 && con[child + 1]< con[child])
if (adjust(con.size() , child + 1) && adjust(con[child + 1], con[child]))
{
child ++;
}
//if (con[child]< con[parent])
if (adjust(con[child] , con[parent]))
{
swap(con[child], con[parent]);
parent = child;
child = child * 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);
}
T& top()
{
return con.back();
}
const T& top() const
{
return con.back();
}
bool empty()
{
return con.empty();
}
size_t size()
{
return con.size();
}
void print()
{
for (int i = 0; i < size(); i++)
{
cout << con[i] << " ";
}
cout << endl;
}
private:
container con;
};
}
(2). test.cpp
priority_queue.h中的代码在以下代码#include"priority_queue.h" 处展开
#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;
#include"priority_queue.h"
template <class T>
class lessnum
{
public:
bool operator()( T a,T b)
{
return a < b;
}
};
template <class T>
class greaternum
{
public:
bool operator()(T a, T b)
{
return a > b;
}
};
int main()
{
//Pc::priority_queue<int, vector<int>, lessnum<int>> pq;
//Pc::priority_queue<int, vector<int>, greaternum<int>> pq;
Pc::priority_queue<int, vector<int>> pq;
pq.push(1);
pq.push(12);
pq.push(123);
pq.push(1234);
while (!pq.empty())
{
pq.print();
cout << "最后一个元素: " << pq.top() << " 元素还有:"<<pq.size() << endl;
pq.pop();
}
return 0;
}
到此为止了
(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤