赞
踩
栈是只在一段进行插入和删除操作的线性表
特点:先进后出
栈就像一段封闭的羽毛球桶一样,羽毛球只能从一段进入,也只能从这段输出,而且后进入的羽毛球会先被取出,最先进去的羽毛球最后才能被拿出
栈有栈顶和栈底:
栈顶:允许进行插入和删除操作的一段,可以理解为羽毛球桶的开口处
栈底:固定不动的一段,可以理解为羽毛球桶封闭的一段
核心操作:pop(弹出栈顶元素) push(将一元素压入栈中)
例题:洛谷P4387 验证栈序列
思路:怎么样的出栈顺序才叫合法呢??
比如入栈顺序是1,2,3,4,5
出栈的顺序可以为5,4,3,2,1,
也可以为3,2,1,5,4
甚至可以是1,2,3,4,5
第一种情况好理解,就是把数据全部压入栈,再顺序弹出
但第二,三中出栈顺序为什么合法呢?因为我可以先把1,2,3压入栈中,再让它们依次弹出,再压入4和5,再弹出,这就是第二种出栈顺序,故第三种也就好理解了,即压入一个数后立刻将他弹出
那么具体怎么写呢?
模拟方法:
每次入栈一个数,然后用while循环判断,如果栈顶等于现有出队序列的第i个数(i一开始为1),则弹出栈顶,并把i加1,直到把所有元素入栈。
入栈完后,如果栈非空,则flag=0。(flag一开始为1)
最后,如果flag则输出No,否则输出Yes
#include <cstdio> #include <iostream> using namespace std; int top, zhan[100010], n, jin[100010], chu[100010]; void push(int x) { zhan[++top] = x; } void pop() { top--; } int main() { cin >> n;//读入。 int len, js = 1; for(int i=0;i<n;i++) { cin >> len;//输入访问序列长度。 //读入不再多说。 for (int j = 1; j <= len; j++) cin>>jin[j]; for (int j = 1; j <= len; j++) cin>>chu[j]; for (int j = 1; j <= len; j++) { push(jin[j]);//进栈。 while (zhan[top] == chu[js] && zhan[top] && chu[js]) { pop(); js++; } }//之所以用while循环,是因为可以简单直接的让相同元素出栈。 if (top != 0) puts("No");//如果栈非空,失败。 else puts("Yes"); //初始化,进入下一轮访问。 top = 0; js = 1; } return 0; }
顾名思义:栈内元素单调上升或者下降的栈
尝试:O(1)实现一个栈的插入,删除,查询最大值
思路:我们可以同时开两个栈,一个普通栈sta1,一个单调栈(单调递增)sta2
例如:入栈序列:1,5,4,6
第一次入栈:
sta1:1
sta2:1
第二次入栈:
sta1: 1,5
sta2: 1,5
第三次入栈:
sta1: 1,5,4
sta2: 1,4(发现4比5小,不满足单调栈定义,弹出栈顶元素,将4入栈)
第四次入栈:
sta1: 1,5,4,6
sta2: 1,4,6
这样如果插入和删除用sta1,查询最大值就弹出sta2的栈顶,就达到O(1)复杂度
例题:洛谷P1901
#include<iostream> using namespace std; const int maxn=1e6+10; int s1[maxn],h[maxn],v[maxn],sum[maxn],ans,n,top; int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>h[i]>>v[i]; while(top&&h[s1[top]]<h[i])sum[i]+=v[s1[top--]]; sum[s1[top]]+=v[i]; s1[++top]=i; } for(int i=1;i<=n;i++)ans=max(ans,sum[i]); cout<<ans; return 0; }
所谓后缀表达式,就是一种不需要括号的表达式
比如:9+(3-1)*3+10/2的后缀表达式为9 3 1 - 3 * + 10 2 / +
这样的表达看起来是很难受的,但是有机器会喜欢,就是聪明的计算机
计算机怎么方便的算一个表达式呢?
规则:从左到右遍历表达式,遇到数字就进栈,如果遇到符号,就将栈顶两个元素出栈,进行运算,运算结果进栈,一直到最终获得结果
以上面的式子为例,先让9,3,1进栈,遇到减号,将栈中1作为减数出栈,3作为被减数出栈,(这里注意:在处理减号和除号时,一定是栈顶第二个元素减(除)第一个元素)计算结果为2入栈,又读入3,遇到乘号,2和3出栈相乘得6,入栈,以此类推
这里看一道例题:洛谷P1449
代码如下
#include <bits/stdc++.h> using namespace std; stack<int> n; char ch; int s,x,y; int main() { while(ch!='@') { ch=getchar(); switch(ch) { case '+':x=n.top();n.pop();y=n.top();n.pop();n.push(x+y);break; case '-':x=n.top();n.pop();y=n.top();n.pop();n.push(y-x);break; case '*':x=n.top();n.pop();y=n.top();n.pop();n.push(x*y);break; case '/':x=n.top();n.pop();y=n.top();n.pop();n.push(y/x);break; case '.':n.push(s);s=0;break; default :s=s*10+ch-'0';break; } } printf("%d\n",n.top()); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。