目录
一、queue的简介
二、queue的模拟实现
三、priority_queue的简介
四、仿函数
五、priority_queue的模拟实现
1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列
4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。
函数声明 |
接口说明 |
queue() |
构造空的队列 |
empty() |
检测队列是否为空,是返回true,否则返回false |
size() |
返回队列中有效元素的个数 |
front() |
返回队头元素的引用 |
back() |
返回队尾元素的引用 |
push() |
在队尾将元素val入队列 |
测试代码
void test_queue()
{
queue q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
q.push(5);
while(!q.empty())
{
cout<
与上一篇stack的博文一样,我们此处不再手搓写queue,而是复用已有的代码。同时我们在上一篇博文中已经介绍过适配器的概念,这里我们不再做解释
C++【STL】【stack类的使用】【stack类的模拟实现】_桜キャンドル淵的博客-CSDN博客
想要手搓queue可以参考这篇博文
队列的实现(c语言数据结构)_桜キャンドル淵的博客-CSDN博客
namespace zhuyuan
{
//加入Container模板参数
//我们的STL底层默认是用deque,也就是双端队列实现的。
//支持头插头删,也支持随机访问
//像是vector和list的合集
template>
class queue
{
public:
void push(const T&x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
T& back()
{
//访问尾部的数据.back()
return _con.back();
}
T& front()
{
//访问尾部的数据.back()
return _con.front();
}
const T& back() const
{
//访问尾部的数据.back()
return _con.back();
}
const T& front() const
{
//访问尾部的数据.back()
return _con.front();
}
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
private:
//封装一个vector
// vector _con;
//任何的类型模板,主要满足上面的那些条件(push等等功能),就可以变成container
Container _con;
};
}
#endif //STACK_QUEUETEST_QUEUE_H
1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素
5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
函数声明 |
接口说明 |
priority_queue()/priority_queue(first, last) |
构造一个空的优先级队列 |
empty( ) |
检测优先级队列是否为空,是返回true,否则返回 false |
top( ) |
返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) |
在优先级队列中插入元素x |
pop() |
删除优先级队列中最大(最小)元素,即堆顶元素 |
也就是说priority_queue其实就是一个堆
测试代码
void test_priority_queue()
{
//默认大的优先级高
priority_queue pq;
pq.push(3);
pq.push(1);
pq.push(2);
pq.push(5);
pq.push(7);
pq.push(0);
pq.push(3);
//不支持迭代器遍历,这里我们让其逐个出堆,得到顺序
while(!pq.empty())
{
cout<,greater> heap(a,a+sizeof (a)/sizeof(int));
while(!heap.empty())
{
cout<
可以知道默认是一个大根堆,也就是说参数是less
就像上面的测试代码中的一样,如果我们想要实现一个大根堆,就在构造的时候传入参数less
在下面的代码中我们就创建了两个仿函数分别为less和greater(其实就是两个类)
less在l
其中我们都是用operator()()来重载的。
仿函数的目的就是让类对象能够像函数一样去被使用!
//仿函数/函数对象 —类,重载operator()
//类对象可以像函数一样去使用
namespace zhuyuan
{
template
class less{
public:
bool operator()(const T&l,const int & r) const
{
return l
class greater{
public:
bool operator()(const T&l,const int & r) const
{
return l>r;
}
};
}
测试代码
int main() {
zhuyuan::less lsFunc;
cout< gtFunc;
cout<
与堆相关的知识还可以参考
堆和堆排序的实现(C语言数据结构)_桜キャンドル淵的博客-CSDN博客
#ifndef STACK_QUEUETEST_PRIORITYQUEUE_H
#define STACK_QUEUETEST_PRIORITYQUEUE_H
#pragma once
namespace zhuyuan
{
//大堆
//ComPare是一个进行比较的仿函数 less ->大堆
//ComPare是一个进行比较的仿函数 greater ->小堆
template,class ComPare=std::less>
class priority_queue
{
public:
priority_queue()
{
}
//使用迭代器进行范围拷贝构造
template
priority_queue(InputIterator first ,InputIterator last)
{
while(first!=last)
{
_con.push_back(*first);
++first;
}
//第一个-1因为数组下表从0开始,再-1然后/2是为了找到叶子结点的上面那一层的最后一个结点
for(int i=(_con.size()-1-1)/2;i>=0;--i)
{
//挨个向下调整
adjust_down(i);
}
}
void adjust_up(size_t child)
{
ComPare com;
size_t parent=(child-1)/2;
//当孩子结点还没有被换到根节点的时候不断进行循环
//logN
while(child>0)
{
//由于我们默认的仿函数是less,所以我们需要调整为<,也就是小于号
// if(_con[child]>_con[parent])
// 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 push(const T& x)
{
_con.push_back(x);
//向上调整
adjust_up(_con.size()-1);
}
//最多向下调整logN次
void adjust_down(size_t parent)
{
//创建仿函数
ComPare com;
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]))
{
std:swap(_con[child],_con[parent]);
parent=child;
child=parent*2+1;
}
else
{
break;
}
}
}
//;支持删除堆顶的数据
void pop()
{
std::swap(_con[0],_con[_con.size()-1]);
_con.pop_back();
//从根开始调整
adjust_down(0);
}
//取出栈顶元素
const T& top()
{
return _con[0];
}
//判断是否为空
bool empty() const
{
return _con.empty();
}
//判断大小
size_t size() const
{
return _con.size();
}
private:
Container _con;
};
}
#endif //STACK_QUEUETEST_PRIORITYQUEUE_H
测试代码
void test_mypriority_queue()
{
//默认大的优先级高
// std::priority_queue pq(std::less());
zhuyuan:priority_queue pq;
pq.push(3);
pq.push(1);
pq.push(2);
pq.push(5);
pq.push(7);
pq.push(0);
pq.push(3);
//不支持迭代器遍历
while(!pq.empty())
{
cout<,greater> heap(a,a+sizeof (a)/sizeof(int));
while(!heap.empty())
{
cout<
【LeetCode】【数组中的第K个最大元素】_桜キャンドル淵的博客-CSDN博客