首先我们要了解什么是 priority_queue ,priority_queue 优先队列是一种数据结构,它存储了元素以及它们的优先级。在优先队列中,元素按照其优先级的顺序进行移除,优先级较高的元素首先被移除。优先队列通常使用堆数据结构来实现,这样可以实现根据优先级高低高效地插入和移除元素。
而如何控制优先级比较就可以快速的进行建堆操作,此外,我们还可以使用不同的容器来进行实现 优先级队列。因此,看似简单的 优先级队列,我们通过 模板、仿函数 的封装,也能玩出花来。话不多说,上代码。
#include<iostream>
#include<list>
#include<vector>
using namespace std;
namespace test
{
template <class T>
struct Less// 大堆
//com(_con[parent],_con[child])
{
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>
struct GreaterPtr
{
bool operator()(const T& p1, const T& p2)
{
return *p1 > *p2;
}
};
//仿函数可以控制比较逻辑,也可以进行多种类型之间的比较
//每一次比较够可以通过 给定的 仿函数类型
//进行特定的比较
//虽然只重载了 () 但是真nb
//当然也可以对仿函数进行 特化处理 用来针对特殊参数类型
template <class T>
struct Greater<T*>
{
bool operator()(const T* x, const T* y)
{
return *x > *y;
}
};
//priority_queue
template<class T, class Container = vector<T>, class Compare = less<T>>
// Container 使用 deque 也可以适配
//优先级队列
class priority_queue//默认是大堆 less
{
public:
void adjust_up(size_t child)
{
Compare com;// less<T>
size_t parent = (child - 1) / 2;
while (child > 0)
{
//if (_con[child] > _con[parent])
// < 大堆 less > 小堆 greater
//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 push(const T& x)//尾部插入,向上调整
{
_con.push_back(x);
adjust_up(_con.size() - 1);//向上调整
}
void adjust_down(size_t parent)
{
Compare com;// less<T>
size_t child = parent * 2 + 1;//左孩子
while (child < _con.size())
{
//if (child + 1 < _con.size() && _con[child + 1] > _con[child])
//if (child + 1 < _con.size() && _con[child] < _con[child+1])
if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
{
child++;//右孩子, 大堆,取较大的
}
//if (_con[child] > _con[parent])
//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 pop()//删除堆顶,将首尾交换
{
swap(_con[0], _con[_con.size() - 1]);//首尾交换
_con.pop_back();
adjust_down(0);//向下调整
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
const T& top()
{
return _con[0];
}
private:
Container _con;
};
}
int main()
{
test::priority_queue<int,vector<int>, less<int>> pq;
// test::priority_queue<int> pq; 等价与上,采用 缺省模板
pq.push(50);
pq.push(60);
pq.push(20);
pq.push(10);
pq.push(40);
pq.push(30);
//建大堆
while (!pq.empty())
{
cout << pq.top() << " ";
pq.pop();
}
return 0;
}
运行结果:
在priority_queue的模板中:
template<class T, class Container = vector<T>, class Compare = less<T>>,
我们可以改变其中 默认 Container 的类型选择不同的容器来实现优先级队列,还可以通过 设置默认的 Compare 的仿函数来采用不同的 比较逻辑。可以看到,这个模拟实现的 priority_queue 有很强的自主性,其中仿函数的实现更是点睛之笔,一个简单的结构体就能实现多种类型的比较。
最近很喜欢苏轼的一首诗《水调歌头·黄州快哉亭赠张偓佺》赠给同学们!!!!!!!!!
落日绣帘卷,亭下水连空。知君为我新作,窗户湿青红。长记平山堂上,欹枕江南烟雨,杳杳没孤鸿。认得醉翁语,“山色有无中”。
一千顷,都镜净,倒碧峰。忽然浪起,掀舞一叶白头翁。堪笑兰台公子,未解庄生天籁,刚道有雌雄。一点浩然气,千里快哉风。