栈
一种FILO的基本数据结构
模板题主要是前中后缀表达式之间的转换问题
常见的有:
①中缀表达式转后缀表达式:
对运算符进行出入栈操作,遇到数字直接输出。与栈顶运算符进行比较时,如果有大于等于被比较的运算符优先级的,直接出栈输出,最后再入栈。如果有括号,左括号入栈,在右括号出现时将栈内元素依次全部出栈直到遇到第一个左括号为止。
主要部分:
int getLevel(char c){ switch(c){ case '(':return 0; case ')':return 0; case '+':return 1; case '-':return 1; case '*':return 2; case '/':return 2; case '^':return 3; } }
if(c==')'){ while(sk.top()!='('){ cout<<sk.top()<<' '; sk.pop(); } sk.pop(); } else{ if(c=='('||c=='^') sk.push(c); else{ if(c=='-'&&negaSign) negaNum=true; else{ while(!sk.empty()&&getLevel(sk.top())>=getLevel(c)){ cout<<sk.top()<<' '; sk.pop(); } sk.push(c); } } negaSign=true; }
②后缀表达式求值
对数字进行出入栈操作,遇符号就对栈顶两个数字进行操作即可
主要部分:
if(s[i]=='+'){ sk[top-1]+=sk[top]; top--; } else if(s[i]=='-'){ sk[top-1]-=sk[top]; top--; } else if(s[i]=='*'){ sk[top-1]*=sk[top]; top--; } else if(s[i]=='/'){ sk[top-1]/=sk[top]; top--; } else if(s[i]>='0'&&s[i]<='9'){ sk[++top]=0; while(s[i]!=' ') sk[top]=sk[top]*10+s[i++]-'0'; }
栈的常见题
①检查括号匹配:左括号入栈右括号先对比再出栈,过程中需判断空栈
②最小更改次数使得括号匹配:出栈时若匹配则正常出栈,不匹配则计数+1后出栈,遇到过程中空栈或者结尾栈非空则不可能匹配
单调栈
利用栈单调性解决问题
例题:POJ3250
一群牛排成一列全部向右看,每头牛有不同高度h,牛只能看到相邻前方的h严格比自己小的牛,求所有牛能看到的牛的数量总和
样例是6头牛,从左到右h为10 3 7 4 12 2
则第一头牛能看到3 7 4这三头
第二头看不到
第三头看到4这一头
第四头看不到
第五头看到2这一头
第六头看不到
则答案为3+1+1=5
那么定义一个结构体记录每头牛的位置p和高度h
如果入栈的牛高度小于栈顶,则入栈
如果大于等于栈顶,持续出栈到小于栈顶
最后需要全部出栈
因为需要用到一个循环变量 i 来表示牛的位置
如果当前某个栈内元素需要出栈
那么就需要加上他能看到的牛的头数
可得出栈时牛能看到的头数为 i-p-1 ,p 为栈顶牛的位置编号
最后全部出栈时 i=N 全部处理即可
代码实现:
#include<iostream> #include<stack> using namespace std; typedef struct node{ int p,h; node(int a,int b){ p=a; h=b; } }; void solve(){ int N,i,h; long long ans=0; cin>>N; stack<node> sk; for(i=0;i<N;i++){ cin>>h; if(sk.empty()) sk.push(node(i,h)); else{ while(!sk.empty()&&sk.top().h<=h){ ans+=i-sk.top().p-1; sk.pop(); } sk.push(node(i,h)); } } while(!sk.empty()){ ans+=N-sk.top().p-1; sk.pop(); } cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); solve(); return 0; }