栈的实际应用—判断一个序列是否为栈的有效输出序列
对于数据结构学科的初学者,栈的构建是很重要的知识,判断一个栈是否为有效输出序列是其中重要的题目。笔者整理了三种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++语言以及数据结构的初学者有所帮助。