前面我们已经写了STL中string,vector,list三个容器和stack,queue两个容器适配器的简单实现,感兴趣的小伙伴可以去看一看,基本没有什么难的地方,今天我们来实现priority_queue优先级队列的实现
目录
1.STL标准库中的优先级队列的方法
要自己实现,我们可以先看人家有什么,我们对照着,实现个大概,那也就差不多了
priority_queue - C++ Reference (cplusplus.com)
c++11里面的我们不管,我们只实现c++98里面的这几个就行了
2.堆的简单理解
数据结构:堆(Heap) - 简书 (jianshu.com)这篇文章篇幅不长,但我相信可以让大家对于堆都能有一个清醒的认识
堆删除的简单说明
为了防止知道什么是堆的小伙伴们忘记什么是堆删除,我再啰嗦一遍,堆删除是指,把堆顶元素和最后一个元素交换位置,然后对最后一个元素进行向下调整,对堆的有效元素减一
3.模板声明
我们要写的是一个堆的模板,所以需要模板声明,这个也很简单,我们直接抄作业,用STL标准库中的就行
我们可以看到,总共有三个模板类型
第一个是要存储的数据的类型,你要存储int型,T就是int
第二个是对哪个容器进行包装(对,同stack和queue一样,priority也是容器适配器,意思就是很简单了),我们看到,是对vector进行的包装
第三个是排序的类型,我们知道,堆是分为大堆和小堆的,这种默认的less就是以小于的方式排大堆,那有人就要问了,那我要想以大于的方式排小堆怎么办?你把其他的都别变,把less换成greater就行了,当然,别忘了加头文件functional,最后,如果你问我为什么是以小于的方式排大堆,那我告诉你,我也不知道,这个是我测试出来的,鬼知道为什么...
4.堆的代码实现
命名空间和堆名
namespace czz {
template <class T, class Container = vector<T>, class Compare = less<T>>
class priority_queue {}
}
私有属性的设置
private:
Container c; //构造一个类型Container的对象,Container默认是vector容器
Compare comp; //构造一个Compare的对象,有人会说它不是排序方式么?
//它就是排序方式,但是是一种很特殊的排序方式,你知道它可以用来排序就行了
私有方法的设置
private:
void AdjustDown(int root) { //向下调整
int parent = root;
int child = parent * 2 + 1;
while (child <= c.size()) {
if (child + 1 < c.size() && comp(c[child], c[child + 1])) {
child += 1;
}
if (comp(c[parent], c[child])) {
std::swap(c[parent], c[child]);
parent = child;
child = parent * 2 + 1;
}
else {
return;
}
}
}
void AdjustUp(int root) { //向上调整
int child = root;
int parent = (child - 1) / 2;
while (child > 0) {
if (comp(c[parent], c[child])) {
std::swap(c[parent], c[child]);
child = parent;
parent = (child - 1) / 2;
}
else {
return;
}
}
}
这两个玩意就是对堆里面的元素进行调整,比如说一个大堆只有堆顶不符合堆的特性,就要对它进行向下调整
公共方法的复用
public:
priority_queue()
:c()
{}
template <class InputIterator>
priority_queue(InputIterator first, InputIterator last)
: c(first, last) {
int n = c.size();
for (int i = ((n - 2) / 2); i >= 0; i--) {
AdjustDown(i);
}
}
bool empty() const {
return c.empty();
}
size_t size() const {
return c.size();
}
T& top() const {
return c.front();
}
void push(const T& x) {
c.push_back(x);
AdjustUp(c.size() - 1);
}
void pop() { //记住堆删除的思想
if (c.empty()) return;
std::swap(c[0], c[c.size() - 1]);
c.pop_back();
AdjustDown(0);
}
总结
其实也就是对一个vector进行包装,然后自己再实现一点,就成了所谓优先级队列,要是有什么疑问,可以在下方留言