1.stack和queue的使用
2.底层逻辑
2.1 stack和queue都是容器适配器,是用其他容器适配形成的
stack的逻辑是后进先出的逻辑,意味着会发生尾差和尾删,其容器就可以选择是vector和list
queue的逻辑是先进先出,意味着会发生头删和尾插,考虑到vector头插头删的效率低,其可使用list作为容器。
2.2 deque(双端队列)
实际上stack和queue使用的是deque(双端序列)容器进行存储数据。下面我们来介绍deque
deque支持常数时间的头插头删尾插尾删也支持随机访问
可谓是集vctor和list的优点于一身,但是缺点是随机访问和迭代器遍历的效率低。主要是因为他的底层结构
可见其底层结构是多个连续小段数组组成,并有映射中控数组map对这些分开的小数组调控。在map开始储存数据时是在中间端存储数据。但是在迭代器和随机访问时就涉及到通过中控计算出具体位置,因此效率低。但是在stack和queue并不需要随机访问和迭代器遍历,因此可以很好的用到deque的优点,避免了其缺点。
3.priority_queue(优先队列)
prioritty_queue也是容器适配器,其默认是用vector<int>进行适配。其默认是大堆,即排列顺序是从大到小,但是我们也可以用greater<T>仿函数,使其从小到到排序。
其底层的逻辑是利用了堆排序,每次push数据时利用adjustup排序数组,出数据时先交换头和尾数据,再尾删,再利用adjustdow排序数组,每次的时间复杂度都是O(logN)。
#pragma once
#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
namespace claus
{
using namespace std;
template<class T>
struct less
{
bool operator()(const T& x1, const T& x2)
{
return x1 < x2;
}
};
template<class T>
struct greater
{
bool operator()(const T& x1, const T& x2)
{
return x1 > x2;
}
};
template<class T, class Container = vector<T>, class Compare = less<T> >
class priority_queue
{
public:
void adjustup()
{
int child = size() - 1;
int parent = (child - 1) / 2;
while (child > 0)
{
if (Compare()(_con[parent] , _con[child]))
{
swap(_con[child], _con[parent]);
child = parent;
parent = (parent - 1) / 2;
}
else
{
break;
}
}
}
void adjustdow()
{
int parent = 0;
int child = parent * 2 + 1;
while (child < size())
{
if (child + 1 < size() && Compare()(_con[child], _con[child + 1]))
{
child++;
}
if (Compare()(_con[parent] ,_con[child]))
{
swap(_con[child], _con[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void push(const T& val) // 默认是大堆,因此需要用adjustup算法
{
_con.push_back(val);
adjustup();
}
void pop()
{
swap(_con[0], _con[size() - 1]);
_con.pop_back();
adjustdow();
}
bool empty()
{
return _con.empty();
}
size_t size()
{
return _con.size();
}
const T& top()
{
return _con.front();
}
private:
Container _con;
};
}