栈及其简单应用

Posted pigzhouyb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈及其简单应用相关的知识,希望对你有一定的参考价值。

栈是什么

栈就是一个先进先出的线性表,若能够更加方便地去理解栈,我们可以跟剧具体的图来进行理解.
技术分享图片
相信这个图十分的生动形象,可以看出栈就像是一个桶,若每一个元素进栈的时候,便会存储在最底下,后来的会在上面;而如果需要取出元素,那么必须从最上面开始取,先放的便只能后来取,后放的便只能先取,因此栈的特点便是:先进后出,后进先出.


如何模拟并存储栈的操作

为了方便,我们需要用数组去模拟栈的序列.即:
技术分享图片
我们定义数组和变量来表示栈,即:
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;
}
































































以上是关于栈及其简单应用的主要内容,如果未能解决你的问题,请参考以下文章

队列及其简单应用

栈及其应用

栈的实现及其典型应用

关于栈及其应用演示样例

log4j2解密:初探插件模式及其应用

栈的基本操作及其应用