带你深入理解STL之Stack和Queue
上一篇博客,带你深入理解STL之Deque容器中详细介绍了deque容器的源码实现方式。结合前面介绍的两个容器vector和list,在使用的过程中,我们确实要知道在什么情况下需要选择恰当的容器来满足需求和提升效率。一般选择的准则有如下几条:
- 如果需要随机访问一个容器,vector比list要好
- 如果需要经常插入和删除操作的话,list比vector要好
- 如果既要随机存取,又要关心两端数据的插入和删除,则选择deque
好了,复习完前面的知识后,开始介绍今天的两个容器stack和queue。由于stack和queue都是基于deque来实现的,所以相应的代码会比较简单,也是比较轻松易实现的,下面一起去看看吧。
stack
如果把deque比作一个管道,两头都可进可出的话,stack就是一个桶!只能一头进一头出,而且,压在下面的东西你看不到,你要是想看,只能把上面的东西拿出来再去看。
stack是一种先进后出的数据结构,允许新增元素、移除元素和取得最顶端的元素,除了最顶端,没有任何其他方法可以存取stack中的元素,也就是说stack没有遍历行为,因此,stack是没有迭代器的!!!!!
以deque为底层容器来实现stack这种数据结构,简直不能再简单,基本的操作函数都已经定义好了,deque可以为它完成所有工作。与其说stack是一种容器,倒不如说它是一种配接器,一种容器适配器。
下面我们就来看看stack的源码,真的没骗你,超级简单。
template <class T, class Sequence = deque<T> // 以deque作为缺省底层容器
class stack
{
// #define __STL_NULL_TMPL_ARGS <>
friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; // 底层容器,stack全靠它来实现
public:
// 以下函数直接调用底层容器的接口即可实现
// 判断stack是否为空
bool empty() const { return c.empty(); }
// stack中元素个数
size_type size() const { return c.size(); }
// 返回栈顶元素, 注意这里返回的是引用!!!
reference top() { return c.back(); }
const_reference top() const { return c.back(); }
// 在栈顶追加新元素
void push(const value_type& x) { c.push_back(x); }
// 移除栈顶元素, 注意不返回元素的引用,
// 很多初学者随机用此容器时经常误认为pop()操作同时会返回栈顶元素的引用
void pop() { c.pop_back(); }
};
// 判断两个stack是否相等, 就要测试其内部维护容器是否相等
// x.c == y.c会调用容器重载的operator ==
template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c == y.c;
}
// 比较两个迭代器的大小,即比较底层容器的大小
template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y)
{
return x.c < y.c;
}
你没有看错,stack的源码就只有上面几句话,全是调用底层容器的接口。下面再来看看它的同胞queue,同样很简单。
queue
queue是一种先进先出的数据结构,上面说道,dequeu是个双向可进可出的管道,stack是一个桶,queue就是一个单向的水管,只能一端进,一端出。
queue允许新增元素、移除元素、从最底端插入元素,从最顶端取得元素,但是,从了最底端插入,最顶端取出之外,没有任何其他方法可以存取queue里面的元素,queue和stack一样,不允许有遍历行为,因此,queue也没有迭代器!!!!
queue和stack一样,也是一种容器适配器,只需要调用底层容器的接口就能实现。下面来看看它的源码吧。
template <class T, class Sequence = deque<T> >
class queue
{
friend bool operator== __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
friend bool operator< __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
public:
// 由于queue仅支持对队头和队尾的操作, 所以不定义STL要求的
// pointer, iterator, difference_type
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; // 底层容器
public:
// 以下操作和stack一样
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { return c.back(); }
const_reference back() const { return c.back(); }
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_front(); }
};
// 重载==操作符,比较底层容器即可
template <class T, class Sequence>
bool operator==(const queue<T, Sequence>& x, const queue<T, Sequence>& y)
{
return x.c == y.c;
}
// 同上
template <class T, class Sequence>
bool operator<(const queue<T, Sequence>& x, const queue<T, Sequence>& y)
{
return x.c < y.c;
}
后记
这篇博客的两个”容器“比较容易理解,因为底层都已经学过了,只需要调用接口即可。最后再啰嗦两句,stack是一个先进后出的容器,queue是一个先进先出的容器,在使用过程中,需要根据你的需求来选择。我在刷leetcode的时候,碰到遍历二叉树的问题,基本上前、中后序遍历的非递归实现中,都会用到stack,而树的层序遍历中,会采用queue,具体的做法可以参考我的这片博文,全面剖析树的各类遍历方法,相信看完你会对stack和queue的使用有进一步的理解!
参考:
- 侯捷先生的《STL的源码剖析》
- C++ STL源码剖析
带你深入理解STL之Stack和Queue的更多相关文章
- 带你深入理解STL之Set和Map
在上一篇博客带你深入理解STL之RBTree中,讲到了STL中关于红黑树的实现,理解起来比较复杂,正所谓前人种树,后人乘凉,RBTree把树都种好了,接下来就该set和map这类关联式容器来" ...
- 带你深入理解STL之Vector容器
C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...
- 带你深入理解STL之迭代器和Traits技法
在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...
- 带你深入理解STL之RBTree
最近一直忙于校招的笔试,STL的深入理解系列也耽搁了好几天,再加上!红黑树真的是超级超级难理解,超级超级复杂,参考了好多博客上的大神的理解才稍微明白一点,勉强入个门,下面请以一个菜鸟的角度跟着我一起学 ...
- 带你深入理解STL之Deque容器
在介绍STL的deque的容器之前,我们先来总结一下vector和list的优缺点.vector在内存中是分配一段连续的内存空间进行存储,其迭代器采用原生指针即可,因此其支持随机访问和存储,支持下标操 ...
- 带你深入理解STL之List容器
上一篇博客中介绍的vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,很好的支持了随机存取,但由于是连续空间,所以在中间进行插入.删除等操作时都造成了内存块的拷贝和移动,另外在内存空间 ...
- 带你深入理解STL之空间配置器(思维导图+源码)
前不久把STL细看了一遍,由于看得太"认真",忘了做笔记,归纳和总结这步漏掉了.于是为了加深印象,打算重看一遍,并记录下来里面的一些实现细节.方便以后能较好的复习它. 以前在项目中 ...
- C++ STL:stack和queue
http://blog.csdn.net/wallwind/article/details/6858634 http://blog.csdn.net/chao_xun/article/details/ ...
- [STL]deque和stack、queue
怎么说呢,deque是一种双向开口的连续线性空间,至少逻辑上看上去是这样.然而事实上却没有那么简单,准确来说deque其实是一种分段连续空间,因此其实现以及各种操作比vector复杂的多. 一.deq ...
随机推荐
- Evensgn 捡树枝
问题 A: Evensgn 剪树枝 时间限制: 1 Sec 内存限制: 128 MB 题目描述 繁华中学有一棵苹果树.苹果树有 n 个节点(也就是苹果),n − 1 条边(也就 是树枝).调皮的 E ...
- [SDOI2016]生成魔咒
题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1, ...
- [Tjoi2013]最长上升子序列
Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一 ...
- TopCoder SRM 561 Div 1 - Problem 1000 Orienteering
传送门:https://284914869.github.io/AEoj/561.html 题目简述: 题外话: 刚开始看题没看到|C|<=300.以为|C|^2能做,码了好久,但始终解决不了一 ...
- bzoj 2560: 串珠子
Description 铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子.现在铭铭想用绳子把所有的珠子连接成一个整体. 现在已知所有珠子互不相同,用整数1到n编号.对于第i个珠子和第j个珠子,可以选择不 ...
- bzoj 2229: [Zjoi2011]最小割
Description 小白在图论课上学到了一个新的概念--最小割,下课后小白在笔记本上写下了如下这段话: "对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同 ...
- bzoj 3751: [NOIP2014]解方程
Description 已知多项式方程: a0+a1x+a2x^2+...+an*x^n=0 求这个方程在[1,m]内的整数解(n和m均为正整数). 解题报告: 这题比较诡,看到高精度做不了,就要想到 ...
- 【Codeforces Round 431 (Div. 2) A B C D E五个题】
先给出比赛地址啦,感觉这场比赛思维考察非常灵活而美妙. A. Odds and Ends ·述大意: 输入n(n<=100)表示长度为n的序列,接下来输入这个序列.询问是否可以将序列划 ...
- 如何在Windows系统中设置Python程序定时运行
文章出处:http://blog.csdn.net/wwy11/article/details/51100432 首先,我们肯定是要用到Windows下的[计划任务]功能 之后点击右侧的[创建基本任务 ...
- 视频人脸检测——OpenCV版(三)
视频人脸检测是图片人脸检测的高级版本,图片检测详情点击查看我的上一篇<图片人脸检测——OpenCV版(二)> 实现思路: 调用电脑的摄像头,把摄像的信息逐帧分解成图片,基于图片检测标识出人 ...