之前參加過華北計算機研究所和優酷土豆的筆試,都考到出棧順序,之前數據結構學的不到位,遇到這類題時,還着實把我愣了一會,現在總結下,省得以后再遇到這類問題,也希望能給遇到同樣問題的兄弟們一個參考。
廢話不多說,直接上個例題。
一個棧的入棧序列是a,b,c,d,e則棧的不可能的輸出序列是:()
A edcbd B decba C dceab D abcde
棧之根本——后進先出(Last In First Out , LIFO)初次接觸到這個問題的人,或許會認為入棧abcde,所以出棧只能是edcba所以BCD都不對。
其實是這個問題描述有歧義,應該是分段入棧的順序,也就是說,可能先入棧a,取出a,入棧b,取出b……,所以D也是可能的。
知道這個意思了以后,就要明確這個問題的矛盾根本所在:第一次出棧d,說明什么?說明a,b,c一定早已入棧(入棧順序決定的)。那么在出棧d以后,a,b,c的出棧順序一定是c,b,a,而不用理會中間穿插着出棧了d后面的字符(因為可以再入棧,再出棧嘛)。所以立即選中C,不用猶豫,理由簡單:d出棧了,abc一定已經入棧,那么abc只能以cba的順序出棧,C不符合,OK!
舉一個更加直觀的例子:
如棧順序是:1 2 3 4 ,如何正確理解出棧?
(1)入棧順序是1 2 3 4,就是指這四個數依次入棧:
數據4入棧之前,1 2 3肯定已經入棧了;
數據3入棧之前,1 2肯定已經入棧了,而4還沒入棧;
數據2入棧之前,1肯定已經入棧了,而2 3 4還沒入棧;
數據1最先入棧,2 3 4還沒入棧。
(2)既然入棧順序是1 2 3 4,3 4入棧的時候,1 2 肯定已經入棧了,怎么會在后面再入棧。
(3)先拿4 3 1 2這個出棧序列來說,4最先出來,說明此時1 2 3(底到頂順序)還都在棧中;接下來只有3能出棧,3出來后,棧中為1 2(底到頂順序);再接下來只有2能出棧,所以如果出棧序列前兩個是4 3的話,后兩個只能是2 1。
再看個正確的出棧序列:2 4 3 1;2最先出來,說明它出來時,3 4還沒入棧,而1已入棧且還在棧中;接着是4出來,說明此時3也在棧中(3要比4先入棧),此時棧中有1 3(底到頂順序);然后只能3出棧,最后是1出棧。
總之,挨個看出棧序列的數據,根據入棧順序,分析它出來時,棧中應該還有誰,而有誰還沒入棧,然后分析此時可不可能是它出棧。
下面針對具體問題,編程來進行分析。
輸入一個壓棧序列,判斷第二個序列是否為其出棧序列。 例如:入棧序列:1 2 3 4 5 6,出棧序列,4,3,5,2,6,1
算法思想,1:根據出棧序列,入棧,直到其棧頂等於出棧元素,棧s:4,3,2,1
2:棧頂與出棧序列相同出棧,否則break
根據入棧序列入棧:(左為棧頂)
棧:1 2 3 4 1 2 3 1 2 5 1 2 1 6 1 |空
出棧元素: 4 3 5 2 6 1 , 4 3 5 2 6 1 ,4 35 2 6 1,4 3 5 2 6 1 ,4 3 5 26 1 ,4 3 5 2 61 ,完
#include <iostream>
#include <stack>
using namespace std;
bool IsStackPopOrder(int *pushorder,int *poporder,int len)
{
bool isorder = false;
if(pushorder!=NULL && poporder != NULL && len > 0)
{
stack<int> s;
int *pnextpush = pushorder;
int *pnextpop = poporder;
while((pnextpop - poporder) < len)
{
while(s.empty()||s.top()!=*pnextpop)
{
if((pnextpush - pushorder)==len)
break;
s.push(*pnextpush);
pnextpush++;
}
if (s.top() == *pnextpop)
{
s.pop();
pnextpop++;
}
else
break;
}
if ((pnextpop - poporder)==len && s.empty())
isorder = true;
}
return isorder;
}
void main()
{
int array1[7] = {1,2,3,4,5,6,7};
int array2[7] = {4,3,5,6,7,1,2};
if(IsStackPopOrder(array1,array2,7))
cout<<"是"<<endl;
else
cout<<"否"<<endl;
system("pause");
}
