栈
栈概述
这里描述的是数据结构的栈,是物理栈结构的一个抽象数据类型。模仿了栈结构的特点,而做出一系列的动作。
物理中栈的本质 就是内存中的一个区域。他的特殊之处就在于,CPU从中存取数据的方式。就好像弹夹装子弹,就是先入后出,后入先出。

对于堆栈而言,如果栈顶和栈底重合,那么表示栈里面没有数据。如果需要往栈里面存放数据那么栈顶指针就往上挪一挪,然后将要存储的数据存放在栈顶 的位置。这个动作就叫做压栈\入栈 。当需要从栈中取出数据的时候,就先将数据保存到寄存器当中,然后栈顶往下挪 ,这个动作就叫做弹栈\出栈。但是要注意,出栈了以后,数据还是在堆栈中,只是这个数据就被当成了垃圾。
应用
重点是在题目中应用栈的结构思想。做题时,多数使用数组直接模拟栈或直接用C++ STL中的stack
一般是应付左右匹配类的题
栈的结构思想:
- 一边压栈的同时一边检测是否需要出栈,出栈永远是刚刚后进的数据(会连续出栈)
- 误区:
- 对于一组数据不是先一股脑全部压栈再出栈,而是一边压栈一边有选择地出栈
题目
洛谷P4387
思路:用栈模拟
按入栈顺序入栈,如果栈顶元素与出栈序列的元素相同,就将其弹出。
首先将入栈序列的第i个元素压到"stack"中,(i,j分别是入栈序列和出栈序列的下标)
判断(注意用while判断,因为可能连续弹出)"stack"中的栈顶元素是否和出栈序列中的第i个元素一致(栈为空就不用判断了)如果一致则弹出栈顶元素,j++;如果不致则继续压入入栈序列中的第i+1个元素
继续判断栈顶元素是否和出栈序列中的第j个元素一致,直到到达入栈序列的末尾。
最后如果"stack"为空或指针j到达出栈序列的末尾就输出Yes,否则输出No
力扣735
思路:用栈模拟
以下情况不会发生碰撞,可把当前行星压入栈:
- 栈为空,不管当前行星是正是负(往左还是往右)都要压入栈
- 当前行星和栈顶行星同号说明同向移动不会碰撞;
- 当前行星往右移动,栈顶行星向左移动也不会碰撞
只有一种情况会发生碰撞,需要出栈当前行星往左,栈顶行星往右,做判断:
- 栈顶元素大于abs(当前元素),当前元素被撞毁;
- 栈顶元素等于abs(当前元素),栈顶弹出和当前元素抵消,
- 栈顶元素小于abs(当前元素),栈顶弹出,并与新栈顶继续完成上述判断
最终返回栈即可
单调栈概述
栈中的元素是严格单调递增 或者递减 的,也就是说:从底到栈顶,元素的值逐渐增大或者减小 。多用于求解元素的左右大小边界问题:
- 向左找第一个比自身大的数。
- 向左找第一个比自身小的数。
- 向右找第一个比自身大的数。
- 向右找第一个比自身小的数。
注意:对于给定的序列,第1,2点从序列的左边往右找;第3,4点从右往左找
操作(以底到顶递增为例):
- 如果新的元素比栈顶元素大,就入栈
- 如果新的元素比栈顶小,那就一直把栈内元素弹出来,直到栈顶比新元素小
元素间大小判断:(以底到顶递增为例):
- 当栈中已有元素需要出栈时(遇见了比它小的新元素),说明后续这个新元素是需要出栈的元素向后找第一个比其小的元素
- 当元素出栈后,新栈顶元素是出栈元素向前找第一个比其小的元素
题目
洛谷P5788
思路:求每个数后第一个大于他的数。
底到顶 递减栈。
从后往前扫,对于每个元素:
- 弹出栈顶比它小的元素
- 此时栈顶就是答案(放到一个数组)
- 加入这个元素
输出答案数组。

力扣42
思路:按行计算我们需要寻找一个元素的 右边最大元素以及左边最大元素,来计算雨水面积。
单调栈:底到顶 递减。
当枚举的将要入栈的元素大于栈顶时,说明出现了凹槽,计算该凹槽的蓄水量:例如:栈内元素:2,1,3要入栈,3比栈顶大,出现了凹槽。凹槽右边是将入栈的元素,左边是栈顶向下第一个大于栈顶的元素。
怎么计算蓄水量:
高*宽。宽是下标的差值 ,高是下标对应的元素值,所以栈中存下标。所以:将要入栈的元素大于栈顶下标对应的元素时说明出现了凹槽。此时将栈顶记录下来之后,不断出栈,直到新的栈顶大于旧栈顶。记:新栈顶为ntop,旧栈顶为top,将入栈的下标为i,则:宽=i-top-1;高=min(h[ntop],h[i])-h[top]。


单调队列:
概念和单调栈类似。应用很少,多用于对一些算法的优化(动态规划等),除非去参加icpc,ccpc,不然基本接触不到,不再整述。
优先队列:
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出的特征。基于堆(大顶堆/小顶堆)实现。
编程中多使用C++容器:
#include <queue>
priority_queue<int>pq;//大顶堆
priority_queue<int,vector<int>,greater<int> > p;//小顶堆