之前參加過華北計算機研究所和優酷土豆的筆試,都考到出棧順序,之前數據結構學的不到位,遇到這類題時,還着實把我愣了一會,現在總結下,省得以后再遇到這類問題,也希望能給遇到同樣問題的兄弟們一個參考。
廢話不多說,直接上個例題。
一個棧的入棧序列是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"); }