如何模拟并存储栈的操作
为了方便,我们需要用数组去模拟栈的序列.即:
我们定义数组和变量来表示栈,即:
Stack表示栈的序列,top代表栈的元素个数,那么自然:
Stack[1]表示栈的底部,stack[top]表示栈顶.那么,如图(c),a,b,c,d,e分别表示Stack[1,2,3,4,5].
添加与删除栈内的元素
添加元素
我们只需要用在顶端放上元素即可,设需要存储的元素为k,即:
top++;
Stack[++top]=k;
删除元素
去掉栈顶元素,其实只需要将元素个数减去1就可以,并不需要要去掉的元素重新赋值为0,因为若要重新插入元素,那么必然新的值会覆盖原来的值.因此只要一句简单的话就可以完成栈的操作:
top--;
栈的实际操作与运用
学习好栈并不只是学会简单的模拟和运用,还要更多地知道一道题为什么需要栈,需要栈来维护什么,这也是需要栈的原因.接下来会有一些实际的例题,可以更好地去理解栈的操作
火车进站
有一个车站,每天都会有N辆车进站,进站按从1到N的顺序进站。现在车站的站长想让这些火车按照特定的顺序出站,问可以做到吗?
当N为5时,出站顺序若为1 2 3 4 5,可以做到,但是顺序若为5 4 1 2 3,则不行。
输入格式
一个N,在1000之内,下接一些出站序列,当读到一个0时,则这个测试数据结束。
输出格式
对每个序列输出一行“Yes”或“No”。
input
5
1 2 3 4 5
5 4 1 2 3
0
output
Yes
No
数据规模与约定
时间限制:1s
空间限制:256MB
这道题目其实难度并非很大,最主要的是模拟,需要用数据结构栈来模拟:
给定一个数列,和栈进行以此配对,即:用1,2,3,4,5进栈,若栈顶元素等于a[first],first表示未被匹配过的初始序列的开头,若匹配成功,则出栈,而匹配的序列也转移到下一个.最后便只要去判断栈是否为空即可.为空没说明匹配完,否则则说明没有匹配完,即该序列不成立.代码很好实现.
代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[1000000]={},st[10000000]={};
int main()
{
int n,cnt_st,cnt_a;
cin>>n;
for (;;)
{
cnt_st=0;cnt_a=1;
for (int i=1;i<=n;i++)
{
cin>>a[i];
if (a[i]==0&&i==1) return 0;
}
for (int i=1;i<=n;i++)
{
st[++cnt_st]=i;
if (st[cnt_st]==a[cnt_a])
while (st[cnt_st]==a[cnt_a]&&cnt_st>0)
{
cnt_st--;
cnt_a++;
}
}
if (cnt_st==0)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
计算表达式的值
题目描述
小明在你的帮助下,破译了Ferrari设的密码门,正要往前走,突然又出现了一个密码门。
门上有一个算式,其中只有“(”、“)”、“0-9”、“+”、“-”、“”、“/”、“^”,求出的值就是密码。小明的数学学得不好,还需你帮他的忙。(“/”用整数除法)
输入格式
只有一行是一个算式(算式长度<=30)。
输出格式
对于每组数据,输出算式的值(所有数据在2^31-1内)。
样例数据input
1+(3+2)(7^2+6*9)/(2)
output
258
数据规模与约定
时间限制:1s
1s
空间限制:256MB
256MB
方法1:
这是一道大模拟,需要用栈进行维护.一个栈储存数字,一个栈储存符号.
这道题目有一个难点,那就是优先级的处理,这个时候我们就需要用栈维护,即:
如果当前符号的优先级大于或等于栈顶,那么直接进栈,否则将栈顶进行计算,以此来处理复杂的优先级的问题,以1+2×4-3为例.我们设数字和字符的栈分别是stc1和stc2,栈顶是top1和top2
1.数字1进栈 stc1={1}
2.符号+进栈 stc1={1} stc2={+}
3.数字2进栈 stc1={1,2} stc2={+}
4.符号×进栈,stc1={1,2} stc2={+,×}
5.数字4进栈,stc1={1.2.4} stc2={+,×}
6.现在我们判断到了-,比符号栈顶×的优先级要小,要进行计算,因此将2,4与符号×进行计算,那么栈的序列为,然后重新入栈:stc1={1,8,3} stc2={+,-}
因此最后答案是:(1+8)-3=6
然后最后留下+和-,顺序地做一遍即可.
处理括号:
1.左括号:直接进栈.
2.右括号:强制计算,知道向左计算的时候枚举到了第一个左括号为止
倒序处理加法或减法的BUG:
例如在做1-2+1,栈是这样的:
stc1={1,2,1} stc2={-,+}
那么下一步,便是:stc1={1,3} stc2={-}
那么最后的答案是:1-3=-2而显然这个算式的答案是0因此我们需要在最后一步进行顺序的处理
但是有一个问题就是:最有会留下乘除号怎么办:补0
即,如果原式是2+5(4+69)^2 那么,我们就可以修改成:2+5(4+69+0)^2+0
代码如下:
#include<bits/stdc++.h>
using namespace std;
int stc1[1000],top1=0;
char stc2[1000];int top2=0;
inline int Math(int x)
{
if (x=='+'||x=='-') return 1;
if (x=='*'||x=='/') return 2;
if (x=='^') return 3;
return 0;
}//千万不要忘记加上“int"
int main()
{
string s,s2;
cin>>s2;
for (int i=0;i<s2.length();i++)
if (s2[i]==')') s=s+"+0"+s2[i];
else s+=s2[i];
s+="+0";//补0
for (int i=0;i<s.length();i++)
{
if (s[i]>='0'&&s[i]<='9')
{
if (i==0) stc1[++top1]=s[i]-'0';
else if (s[i-1]<'0'||s[i-1]>'9')stc1[++top1]=s[i]-'0';
else if (s[i-1]>='0'&&s[i-1]<='9')stc1[top1]=stc1[top1]*10+s[i]-'0';
continue;
}//处理数字
if (Math(s[i])>0)
{
int math1=Math(s[i]);
int math2=Math(stc2[top2]);
if (top2==0)
{
stc2[++top2]=s[i];
continue;
}//如果没有存放字母
if (math2>0&&math1<math2)
{
char ch=stc2[top2];
if (ch=='+') stc1[top1-1]+=stc1[top1];
if (ch=='-') stc1[top1-1]-=stc1[top1];
if (ch=='*') stc1[top1-1]*=stc1[top1];
if (ch=='/') stc1[top1-1]/=stc1[top1];
if (ch=='^') stc1[top1-1]=pow(stc1[top1-1],stc1[top1]);
top1--;stc2[top2]=s[i];
}//如果优先级比原来大
if (math2>0&&math1>+math2)
stc2[++top2]=s[i];//如果优先级比原来小
if (stc2[top2]=='(')
stc2[++top2]=s[i];//如果上一个字符是左括号
}
if (s[i]=='('||s[i]==')')
{
if (s[i]==')'&&stc2[top2]=='(')
{
top2--;
continue;
}//如果左右括号内只有数子
if (s[i]=='(')
stc2[++top2]=s[i];//如果是左括号
if (s[i]==')')
{
while (stc2[top2]!='(')
{
char ch=stc2[top2];
if (ch=='+') stc1[top1-1]+=stc1[top1];
if (ch=='-') stc1[top1-1]-=stc1[top1];
if (ch=='*') stc1[top1-1]*=stc1[top1];
if (ch=='/') stc1[top1-1]/=stc1[top1];
if (ch=='^') stc1[top1-1]=pow(stc1[top1-1],stc1[top1]);
top1--;top2--;
}
top2--;
}//如果是右括号就进行强制处理
}
}
for (int i=1;i<=top2;i++)
{
int ch=stc2[i];
if (ch=='+') stc1[i+1]=stc1[i]+stc1[i+1];
if (ch=='-') stc1[i+1]=stc1[i]-stc1[i+1];
}//正序处理结果
cout<<stc1[top1];
return 0;
}