目录
一.stack
二.queue
三.deque
STL中有6大组件,我们前面讲的string/vector/list是容器,还有迭代器,以及算法(比如find,swap,reverse,sort,merge函数),仿函数和空间配置器会在后面讲解,下面讲的stack和queue是配接器。
一.stack
stack就是数据结构中的栈,数据是先进后出。配接器是对特定类封装作为其底层的容器,提供函数来访问元素。简单来说栈的成员变量就是一个容器类,可以是vector也可以是list,因为这两种容器都支持栈的数据插入和删除。实现比较简单,只需要调用容器的接口即可,理解了栈就能理解调用函数的作用。
template<class T, class Con = deque<T>>//模板参数,T是数据类型,Con是容器,默认是deque,这个数据结构后面讲
class stack
{
public:
stack()
{
Con _c;//用传进来的容器类型实例化
}
void push(const T& x)
{
_c.push_back(x);//调用容器的尾插函数
}
void pop()
{
_c.pop_back();//调用容器的头删函数
}
T& top()
{
return _c.back();//输出栈顶的元素
}
const T& top()const
{
return _c.back();//const版本
}
size_t size()const
{
return _c.size();//输出当前栈里有多少个元素
}
bool empty()const
{
return _c.empty();//判断栈是否为空
}
private:
Con _c;//成员变量就是容器
};
二.queue
queue就是数据结构的队列,和栈不一样,队列的数据是先进先出,也是一种配接器,成员变量也是容器,和栈一样自身的函数接口都是调用容器的接口。但是容器不能是vector,因为先进先出的实现需要在删除时删去第一个元素,对于vector头删的时间复杂度很高,不仅需要挪动数据,在大量删除的场景下性能十分低下。实现也比较简单。
template<class T, class Con = deque<T>>//模板参数,T是数据类型,Con是容器,默认是deque,这个数据结构后面讲
class queue
{
public:
queue()//默认构造函数
{
Con _c;//用传进来的容器类型实例化
}
void push(const T& x)
{
_c.push_back(x);//调用容器的尾插函数
}
void pop()
{
_c.pop_front();//调用容器的头删函数
}
T& back()
{
return _c.back();//返回队列的尾部元素
}
const T& back()const
{
return _c.back();//const版本
}
T& front()
{
return _c.front();//返回队列的头部元素
}
const T& front()const
{
return _c.front();//const版本
}
size_t size()const
{
return _c.size();//返回队列当前元素个数
}
bool empty()const
{
return _c.empty();//判断队列是否为空
}
private:
Con _c;//成员变量就是容器
};
三.deque
vector支持下标随机访问但不支持头插头删,或者说性能很低,list头插头删效率都极高,中间插入效率也高,但是不支持下标随机访问。而deque既支持下标随机访问,头插头删效率也比较高,可以说是结合了vector和list优点。
deque是有一个存放数组指针的数组,每个数组指针指向一个数组,用来存放元素,相比于vector头插头删就不需要挪动数据,效率很高,相比于list空间利用率高,list是一块一块的占用内存,导致会出现比较多的内存碎片。
双端队列实际上是分段连续的,为了实现能随机访问其迭代器比较复杂。
但是deque终究还是不能取代vector和list,因为它不适合遍历,遍历时迭代器需要频繁检测是否移动到某段小空间的边界,导致效率低下,遍历线性结构还是适合vector和list。所以它适合栈和队列这种只进行头部尾部插入删除而不遍历的数据结构,而且相比list,deque的内存使用率也高。
以上就是STL中stack和queue的模拟实现了,这章主要还是熟悉stack和queue的使用,以及了解双端队列deque。