目录
一、概念
概念来源:
栈:栈是 OI 中常用的一种线性数据结构,栈的修改是按照后进先出的原则进行的,因此栈通常被称为是后进先出(last in first out)表,简称 LIFO 表。
单调栈:单调栈即满足单调性的栈结构,其只在一端进行进出。
二、图示说明
1.数组模拟栈
tt:指向栈顶所在的位置
2.数组模拟单调栈
tt:指向栈顶位置
栈内元素满足单调增或单调减的
三、操作实现
1.栈
a.插入元素到栈顶
int stk[N]; ///用数组模拟栈
int tt; ///记录单前栈顶的位置
void push_x(int x){
stk[++tt]=x; ///先让栈顶位置后移,在插入元素(个人习惯栈顶位置从1开始)
}
b.删除栈顶元素
void pop(){
///先将栈顶元素删除,然后再将栈顶位置先前移(删除元素不一定都赋为0,赋成插入元素范围外的数即可)
stk[tt--]=0;
}
c.判断栈是否为空
bool empty(){
if(tt>0) return false; ///因为栈顶位置从1开始计算,当栈顶位置小于1时栈为空
else return true;
}
d.返回栈顶元素
int query(){
return stk[tt]; ///返回当前栈顶位置的元素即可
}
2.单调栈
以单调递增的情况为例
a.维持单调栈
int x;
cin >>x; ///插入一个元素x
while(tt&&stk[tt]>=x) tt--;///当栈不为空,同时栈顶元素大于新元素x时,将栈顶位置向前移
if(tt>0) (某种操作); ///此时若栈不为空,则说明找到一个元素比x小
stk[++tt]=x; ///然后将新元素x插入到栈中
///单调栈存储的数据,由底到顶逐渐增大,栈底为最小的元素
四、例题说明
1.栈
a.题目描述
题目来源:acwing
实现一个栈,栈初始为空,支持四种操作:
push x
– 向栈顶插入一个数 x;pop
– 从栈顶弹出一个数;empty
– 判断栈是否为空;query
– 查询栈顶元素。
现在要对栈进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。
输入格式
第一行包含整数 M,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令为 push x
,pop
,empty
,query
中的一种。
输出格式
对于每个 empty
和 query
操作都要输出一个查询结果,每个结果占一行。
其中,empty
操作的查询结果为 YES
或 NO
,query
操作的查询结果为一个整数,表示栈顶元素的值。
数据范围
1≤M≤100000,
1≤x≤1e9
所有操作保证合法。
输入样例:
10
push 5
query
push 6
pop
query
pop
empty
push 4
query
empty
输出样例:
5
5
YES
4
NO
b.解题思路
思路:按题目要求实现四种操作
c.代码实现
#include<iostream>
using namespace std;
const int N=1e5+10;
int stk[N]; ///用数组模拟栈
int tt; ///记录单前栈顶的位置
void push_x(int x){
stk[++tt]=x; ///先让栈顶位置后移,在插入元素(个人习惯)
}
void pop(){
///先将栈顶元素删除,然后再将栈顶位置先前移(删除元素不一定都赋为0,赋成插入元素范围外的数即可)
stk[tt--]=0;
}
bool empty(){
if(tt>0) return false; ///因为栈顶位置从1开始计算,当栈顶位置小于1时栈为空
else return true;
}
int query(){
return stk[tt]; ///返回当前栈顶位置的元素即可
}
int main(){
int m;
cin >>m;
while(m--){
string op;
cin >>op;
int x;
if(op=="push"){
cin >>x;
push_x(x);
}
else if(op=="pop"){
pop();
}
else if(op=="empty"){
if(empty()) puts("YES");
else puts("NO");
}
else {
cout <<query() <<endl;
}
}
return 0;
}
2.单调栈
a.题目描述
题目来源:acwing
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤N≤1e5
1≤数列中元素≤1e9
输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2
b.解题思路
思路:用单调栈来维护栈内元素的单调递增性质,每增加一个元素维护一次,并按要求输出比新增元素小且距离最近的元素。
c.代码实现
#include<iostream>
using namespace std;
const int N=1e5+10;
int stk[N],tt;
int main(){
int n;
cin >>n;
for(int i=0;i<n;i++){
int x;
cin >>x;
///当栈不为空,同时栈顶元素大于新元素x时,将栈顶位置向前移
while(tt&&stk[tt]>=x) tt--;
///此时若栈不为空,则说明找到一个元素比x小,并将该元素输出
if(tt>0) cout <<stk[tt] <<' ';
else cout <<"-1 "; ///否则输出-1
stk[++tt]=x; ///然后将新元素x插入到栈中
}
return 0;
}