一、定义
-
后进先出 (Last In First Out):一种限制访问端口的线性表
-
主要操作:进栈 (push) 出栈 (pop)
二、实现
1、实现方式
-
顺序栈 (Array-based Stack)
-
栈的大小事先固定
-
存在上溢,下溢问题
-
-
链式栈(Linked Stack)
-
用单链表方式存储,大小可以动态改变
-
-
由于所有操作都只需要常数时间,顺序栈和链式栈在时间效率上难分伯仲。链式栈会有额外的空间开销。
-
实践中,顺序栈的使用更加广泛。
2、代码(顺序栈)
(1)创建
int S[maxn]; //S为顺序栈 int top=-1; //top表示栈顶的位置。初始状态时,栈为空,栈顶为-1。
(2)判断是否为空
bool emp(){ if (top==-1) return true; else return false; }
(3)进栈
//x进栈 void push(int x){ ++top; S[top]=x; }
(4)出栈
//弹出栈顶元素,并将其记在x中 bool pop(int x){ if (emp()) return false; //下溢 else { --top; x=S[top+1]; return true; } }
三、应用
1、表达式求值
计算思路(来自如何用栈实现表达式求值 | 守望的个人博客)
-
使用两个栈,stack0用于存储操作数,stack1用于存储操作符
-
从左往右扫描,遇到操作数入栈stack0
-
遇到操作符时,
-
如果优先级低于或等于栈顶操作符优先级,则从stack0弹出两个元素进行计算,并压入stack0,继续与栈顶操作符的比较优先级
-
如果遇到操作符高于栈顶操作符优先级,则直接入栈stack1
-
-
遇到左括号,直接入栈stack1,遇到右括号,则直接出栈并计算,直到遇到左括号
例题
描述:判断两个表达式在数学上是否是等价的。
输入 ①第一行:N(1<=N<=20),表示测试数据组数。 接下来每组测试数据包括两行,每行包括一个数学表达式,每个表达式的长度不超过80个字符。输入数据没有空行。 ②一个表达式可能包括: 单个英文字母表示的变量(区分大小写) 数字(只有一位数) 配对的括号 运算符加+、减-、乘* 任意数量的空格或tab(可能出现在表达式中间的任何位置) ③注意:表达式保证是语法正确的,且所有运算符的优先级相同,运算次序从左至右。变量的系数和指数保证不超过16位整数。
输出 对每个测试数据,输出一行:等价则输出“YES”,不等价则输出“NO”。
其他题目
矩阵链乘 (Matrix Chain Multiplication, UVa 442)
2、单调栈
单调栈中,从栈底到栈顶,元素单调递增或递减排列,以单调递减为例,新元素x入栈时,为了维持栈中元素的单调性,需要弹出原来在栈中小于或等于x的元素,再将x入栈。举例来说,我们有以下几个数,需要将它们放入一个单调栈中,并保证栈中元素从栈底到栈顶单调递减。
10 3 7 4 12 2
栈的变化过程如下
4 3 7 7 7 2 10 10 10 10 10 10 10 空 12 12
例题:发型糟糕的一天
描述 农夫John 的N(1 ≤ N ≤ 80,000)只奶牛中,有一些也许正在经历发型糟糕的一天。每只奶牛对自己乱糟糟的发型都有自知之明,农夫John想知道所有奶牛能看到其他奶牛头顶的数量之和。 任意奶牛i身高记为 hi (1 ≤ hi ≤ 1,000,000,000),所有奶牛面向东方(本题示意图的右面)依次站成一条线。因此,奶牛i能够看到在它前面的(奶牛i+1,i+2…)所有身高比它低的奶牛,直到被一头不比它低的奶牛挡住。用ci表示奶牛i能够看到头顶的奶牛个数;请计算c1 至cN的和。
输入 第1行:奶牛数N 第2行至N+1行:第i+1行包含一个整数,表示奶牛i的高度
输出 第1行:c1 至cN的累加和
分析:如果把每只哞的高度和前面的哞比较,时间复杂度是O(n^2),会超时,需要找更省时间的办法。这里维护一个单调栈,利用栈顶的位置来计算c1到cN的和。仍以前面的单调栈为例,现在我们只关心在有元素入栈之后栈的状态,前面所写的栈的变化过程可以简化为:
4 3 7 7 2 10 10 10 10 12 12
下面看看如何利用栈顶位置计算c1到cN的和。考虑第一只身高为10的哞。为了计算c1,我们需要找到第一只身高超过10的哞,并计算TA和身高为10的哞的距离。在本题中,第一只身高超过10的哞身高为12,TA和身高为10的哞之间有3只哞,身高分别为3,7,4,这三只即第一只哞能看见的哞。无独有偶,我们发现,在上图所示的栈的变化过程中,身高为10的哞在栈中总共待了4=3+1轮。类似的,身高为3的哞看不见其他哞(即看见0只哞),TA在栈中待了1=0+1轮……由此发现,我们用所有哞在栈中待的轮数减去哞的总数,就可以得到c1到cN的和。 于是现在问题转化成如何求所有哞在栈中待的轮数。可以看出,对于每种栈的状态,top+1表示栈中的元素个数,我们只要把上图每种状态中的top+1求和即可。