判断一个序列是否为栈的有效输出序列

栈的实际应用—判断一个序列是否为栈的有效输出序列

对于数据结构学科的初学者,栈的构建是很重要的知识,判断一个栈是否为有效输出序列是其中重要的题目。笔者整理了三种C++代码,其核心编程思想大致相同,希望能对初学者有一定帮助。

**【问题描述】**给出一个堆栈的输入序列,试判断一个序列是否能够由这个堆栈输出。如果能,则为有效输出,返回总的出栈次数,如果不能,则为无效输出,返回0。序列的输入及输出都是从左往右。

1、输入输出序列皆为正整数,可能有重复的数字

2、如果一个数字在输入序列中没有出现,但在输出序列中出现,则为无效输出。

3、如果一个数字在输入序列中出现,但在输出序列中没有出现,只要输出可以通过对输入数字进行出栈操作获取,仍然为有效输出。

**【输入形式】**第一行包含两个数字:输入序列的长度与输出序列的长度;第二行为输入序列的数字;第三行为输出序列的数字。输入数据以空格隔开。

**【输出形式】**如果是一个有效的出栈序列,则返回总的出栈次数, 否则返回0

【样例输入1】
5 5
1 2 3 4 5
4 5 3 2 1
【样例输出】5
【样例说明】可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4, push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
通过5次pop操作可以得到输出序列,因此返回5

【样例输入2】
5 5
1 2 3 4 5
4 3 5 1 2
【样例输出】0
【样例说明】1不能在2之前输出,因此返回0

**算法思想:**这个题目中涉及出栈、入栈等操作,很自然想到需要申请一个空间作为栈,进行相应的模拟操作。对于我们所要输出的序列,可以从头至尾一个个来操作,拿到最开始要输出的数字时,可以与输入序列相比较,如果恰好正确则直接输出,如果不相等则入栈,继续从前往后扫描输入序列。
举例来讲,如上述样例输入1,第一个要输出的数字是4,那么将这个数字依次与输入序列相比较,其中1、2、3与4并不相等,依次进栈,这时遇到了输入序列的4,这个4就可以输出了。下一个要输出的是5,先比较栈顶的数字3,与5并不相等,继续扫描输入序列找到5.依次类推,直到完成所有数据的输出。

算法1
这个算法利用了一个数组stack作为栈,也是笔者在拿到这个题目时做出的算法。其中代码行数比较少,思路也相对比较容易。

#include <iostream>

using namespace std;

bool pop(int sta[],int in[],int &curin,int &cur,int out);

int main()
{
    int numin,numout,current=1,total=0,currentin=0;    //需要设出两个表示下标的变量,分别代表栈的下标和输入序列读取到的下标
    cin>>numin>>numout;
    int *p,*q,*stack;
    p=new int[numin];
    q=new int[numout];
    stack=new int[numin];
    for(int i=0;i<numin;++i) cin>>p[i];  //读入输入序列
    for(int i=0;i<numout;++i) cin>>q[i]; //读入输出序列
    stack[0]=p[0];     //输入序列第一个数入栈

    for(int i=0;i<numout;++i)     //从第一个输出序列的数字依次开始寻找
       if(pop(stack,p,currentin,current,q[i])==false)   //如果没有寻找到某一个输出数字,直接输出结果0
           {total=0;break;}
       else {total+=1;currentin-=1;}   //找到输出数字,那么出栈后栈的下标数字减1
    cout<<total;
    return 0;
}

bool pop(int sta[],int in[],int &curin,int &cur,int out)   //判断并出栈的函数
{
   for(;in[cur-1]!='\0';++cur) {                           //依次遍历栈顶和输入序列剩余的数字
   if(sta[curin]==out) {sta[curin]=in[cur];return true;}   //找到则更替栈顶数字,返回true
   else{curin+=1;sta[curin]=in[cur];}
   }
   return false;                                           //没找到,返回false
}

具体的思路和代码如上。

算法2
编写一个类来代替传统的STL。代码来自笔者室友。

#include<iostream>
#include<cstdio>
using namespace std;

template<class elemType>
class ownstack
{
    private:
    elemType *elem;
    int top_p;
    int max_size;
    void doublespace();

    public:
    ownstack(int initSize=100);   //栈的构造
    ~ownstack();                  //析构
    bool empty();                 //判断栈空
    elemType top();               //取栈顶元素
    elemType pop();               //出栈
    void push(const elemType &x); //进栈
};

template<class elemType>
ownstack<elemType>::ownstack(int initSize)
{
    elem=new elemType[initSize];
    max_size=initSize;
    top_p=-1;
};

template<class elemType>
bool ownstack<elemType>::empty()
{
    return top_p==-1;
}

template<class elemType>
ownstack<elemType>::~ownstack()
{
    delete []elem;
}

template<class elemType>
elemType ownstack<elemType>::top()
{
    return elem[top_p];
}

template<class elemType>
void ownstack<elemType>::push(const elemType &x)
{
    if(top_p==max_size-1) doublespace();
    elem[++top_p]=x;
}

template<class elemType>
elemType ownstack<elemType>::pop()
{
    return elem[top_p--];
}

template<class elemType>
void ownstack<elemType>::doublespace()
{
    elemType *tmp=elem;
    elem=new elemType[2*max_size];
    for(int i=0;i<max_size;++i)elem[i]=tmp[i];
    max_size*=2;
    delete []tmp;
}

int judge(const int*pPush,const int *pPop,int length,int len)
{                                         //依次为输入、输出序列、输入序列剩余长度、输出序列剩余长度
    bool flag=false;
    if(pPush&&pPop&&length>0)
    {
        const int *pNextPush=pPush;
        const int *pNextPop=pPop;
        ownstack<int>data;
        while(pNextPop-pPop<len)  //当pop中还有数字
        {
            //当data为空,或者栈顶元素不是pop序列当前的值
            //则向data中push
            while(data.empty()||data.top()!=*pNextPop)
            {
                //如果push序列为空,则跳出!
                if(!pNextPush)
                {
                    break;
                }
                data.push(*pNextPush);
                if(pNextPush-pPush<length-1)  pNextPush++;  //如果输入序列还有数字,可以继续入栈
                else break;           //pNextPush==NULL
            }
        if(data.top()!=*pNextPop) break;
        data.pop();
        pNextPop++;
        }
    if(pNextPop-pPop==len) flag=true;}  //进栈数字的数目等于要输出数列的数字个数,则判断为正确
    if(flag) return len;             //判断正确,返回输出数列的长度
    else return 0;    //其余情况判断为错误,输出为0
}

int main()
{
    int m=0,n=0,i;
    scanf("%d%d",&m,&n);     //这里使用了scanf函数,效率高。
    cin.get();
    int push[m];
    int pop[n];
    for(i=0;i<m;i++)scanf("%d",&push[i]);
    cin.get();
    for(i=0;i<n;i++)scanf("%d",&pop[i]);
    cout<<judge(push,pop,m,n);
    return 0;
}

算法3
这种算法利用了STL。在进行栈的构建时,STL可以说是现成的工具。看到在本网站已经有了很好的STL构建,将相应的博主echo_xiao9的原文链接列出,希望读者也能关注一下这种较为方便实用的算法。
算法链接

总结来说,这道题目的大致思路是一样的,具体的算法实现和代码书写,笔者罗列了三种形式(其三为转载链接)。希望能对C++语言以及数据结构的初学者有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值