棧的壓入、彈出序列

棧的壓入、彈出序列


  棧作爲一種基本的數據結構,在各種題目裏已經是屢見不鮮了,本文來講解一下棧的基本操作,壓棧和出棧,基本概念沒什麼講的,所以就講講合法的序列關係。閱讀本文假定已經知道棧的入棧和出棧的操作。
  首先要明白出棧序列代表什麼,給定一個入棧序列,每次可以進行的操作就是序列裏的元素入棧,或者棧裏的元素出棧。然後根據這個入棧序列能得到的出棧序列。每個元素只有一次入棧和出棧的機會。當然棧一定需要先入纔有元素可出。所有的元素入棧後就只能出棧了。
  除了棧的基本入棧和出棧需要了解外,這裏還幫大家複習一個知識點,假設三個元素以i,j,ki,j,k的相對順序入棧(不要求連續入棧),則三個元素一定不能以k,i,jk,i,j的相對順序出棧,而其他相對順序都是可以的。這個問題熟悉出棧的操作應該就很好理解,首先最先出棧的元素是最後進去的,說明此時元素i,ji,j仍然在棧中,而且入棧序列iijj的前面。那麼棧內ii也是在jj的前面,所以ii要出棧,必須得等到jj出棧後方可出棧。所以上面的序列是不可能得到的。

題目描述

  輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

算法分析

  根據上面提到的知識點,現在來看問題,解決這類問題,可以先想一想如果換做人是怎麼來判斷的,那就是模擬一下,拿着出棧序列和入棧序列對應。假如:入棧序列是1,2,3,4,5,判斷出棧序列能否是4,5,3,2,1。現在來模擬一下。

剩餘入棧序列 待匹配出棧序列 當前棧內元素 分析
12345 45321 - 待匹配4,顯然4及4前面的元素都要按照次序入棧
5 45321 1234 4出棧,匹配成功
5 5321 123 待匹配5,棧頂不是5,不能選擇出棧,5及5前面的元素按照次序入棧
- 5321 1235 5出棧,匹配成功
- 321 123 待匹配3,棧頂是3,選擇出棧,匹配成功
- 21 123 待匹配2,棧頂是2,選擇出棧,匹配成功
- 1 123 待匹配1,棧頂是1,選擇出棧,匹配成功
- - - 待匹配序列爲空,入棧序列全部入棧,棧內爲空,匹配結束

  大致手動地模擬一遍,就差不多可以看到算法的思路,爲了方便理解,我們再舉一個匹配失敗的例子。

剩餘入棧序列 待匹配出棧序列 當前棧內元素 分析
12345 43125 - 待匹配4,顯然4及4前面的元素都要按照次序入棧
5 43125 1234 4出棧,匹配成功
5 3125 123 待匹配3,棧頂是3,選擇出棧,匹配成功
5 125 12 待匹配1,棧頂是2,此時查看入棧序列,如果有2,2前面的元素入棧,入棧序列沒有2,匹配失敗

  人是怎麼做的,這裏計算機就是怎麼做的。所以我們把思路進行總結,就是模擬一個棧。如果待匹配的出棧序列最前面的元素是棧頂元素,則棧頂元素出棧。如果不是棧頂元素,則去待入棧序列中查找元素,如果沒找到,匹配失敗返回;如果找到,則該元素前面的序列入棧,繼續匹配下一個元素。循環執行這個操作,直到待匹配序列和待入棧序列,棧內元素都爲空,則匹配成功。
  理清思路,開始寫代碼。

python代碼

def IsPopOrder(pushV, popV):
    if len(pushV)!=len(popV):
        return False
    stack = []
    nextPush = 0
    for i in range(len(popV)):
        tmp = popV[i]
        if stack and stack[-1] == tmp:
            stack.pop()
        else:
            try:
                k = pushV.index(tmp, nextPush) # 找下一個入棧元素的索引
            except ValueError: # 異常表示待入棧元素中沒找到待匹配元素
                return False
            stack.extend(pushV[nextPush:k])
        	nextPush = k + 1
    if not stack:
        return True

  代碼很好理解,因爲這裏使用的是列表來模擬棧,事實上列表是不適合頻繁的插入和刪除元素的,順序表(數組)實現的數據結構都不太擅長頻繁的插入和刪除元素。我就將多次連續入棧的情況統一處理,直接把一個片段加入到模擬的棧中。我大致的測試了一下,這樣確實要比循環加入的代碼快好多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章