目录
一.priority_queue的介绍
在文档中可以看到,对于priority_queue类有三个模板参数,第一个模板参数接收优先队列中的数据类型,第二个模板参数为优先队列的容器适配器,默认为vector,第三个模板参数来接收控制优先级队列为大堆或小堆的仿函数,默认为less,即大堆。
优先队列其实就可以看作之前学过的数据结构堆。
二.仿函数
1.仿函数的介绍
仿函数(Functor)也被称作函数对象,它是一种行为类似于函数的对象。要实现仿函数,可通过定义一个类或结构体,并且在其中重载()
运算符。如此一来,这个类的对象就能够像函数一样被调用。
2.仿函数的特点
<1>可定制性高:仿函数可依据需求定制其行为,通过重载()
运算符实现不同的逻辑。这使得仿函数在算法中能根据具体需求灵活调整行为。
<2>可作为模板参数:在泛式编程里,仿函数可以当作模板参数使用,从而实现通用算法。
3.实现两个简单的仿函数
以优先队列为例,如果我们想要控制优先队列为大堆或小堆,我们就要实现对应的仿函数:less与greater,优先队列中大堆对应less,小堆对应greater。
template<class T>
class less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
三.priority_queue的接口实现
1.成员变量
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
private:
Container _con; // 容器适配器
Compare com; // 在初始化列表构建仿函数对象
};
2.push
void push(const T& x)
{
_con.push_back(x);
adjustup(_con.size() - 1);
}
在尾插后进行向下调整算法,由于向下调整与向上调整只在类内部使用,所以定义为私有的成员函数:
void adjustup(size_t child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
std::swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
关于向下调整与向上调整算法的原理,在堆——从理论到代码的深度拆解中有进行讲解,可以前往学习,这里由于通过仿函数进行比较,对于父子结点之间的比较可以通过实例化的仿函数对象进行调用。
由于大堆对应less,小堆对应greater,向上和向下调整算法中的比较顺序也要相应调整。
3.pop
void pop()
{
std::swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjustdown(0);
}
void adjustdown(size_t parent)
{
size_t child = 2 * parent + 1;
while (child < _con.size())
{
//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child++;
}
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
std::swap(_con[child], _con[parent]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
4.top
const T& top() const
{
return _con[0];
}
5.size
size_t size() const
{
return _con.size();
}
6.empty
bool empty() const
{
return size() == 0;
}
7.构造函数
priority_queue()
{}
// 迭代区间构造优先队列
// 遍历,逐个push
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
push(*first);
++first;
}
}
四.代码总览
priority_queue.h
#include<vector>
namespace my_priority_queue
{
template<class T>
class less
{
public:
bool operator()(const T& x, const T& y)
{
return x < y;
}
};
template<class T>
class greater
{
public:
bool operator()(const T& x, const T& y)
{
return x > y;
}
};
template<class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue
{
public:
priority_queue()
{}
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
{
while (first != last)
{
push(*first);
++first;
}
}
void push(const T& x)
{
_con.push_back(x);
adjustup(_con.size() - 1);
}
void pop()
{
std::swap(_con[0], _con[_con.size() - 1]);
_con.pop_back();
adjustdown(0);
}
const T& top() const
{
return _con[0];
}
size_t size() const
{
return _con.size();
}
bool empty() const
{
return size() == 0;
}
private:
void adjustup(size_t child)
{
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
std::swap(_con[child], _con[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void adjustdown(size_t parent)
{
size_t child = 2 * parent + 1;
while (child < _con.size())
{
//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child++;
}
//if (_con[parent] < _con[child])
if (com(_con[parent], _con[child]))
{
std::swap(_con[child], _con[parent]);
parent = child;
child = 2 * parent + 1;
}
else
{
break;
}
}
}
private:
Container _con;
Compare com; // 在初始化列表构建仿函数对象
};
}
test.cpp
#include<iostream>
#include<deque>
using namespace std;
#include"priority_queue.h"
int main()
{
my_priority_queue::priority_queue<int, deque<int>, my_priority_queue::greater<int>> pq1;
pq1.push(1);
pq1.push(0);
pq1.push(8);
pq1.push(-1);
pq1.push(3);
pq1.push(6);
while (!pq1.empty())
{
cout << pq1.top() << " ";
pq1.pop();
}
cout << endl;
vector<int> v = { 1,0,8,-1,3,6 };
my_priority_queue::priority_queue<int, vector<int>, my_priority_queue::less<int>> pq2(v.begin(), v.end());
while (!pq2.empty())
{
cout << pq2.top() << " ";
pq2.pop();
}
return 0;
}