1 問題描述
問題1:若元素 a,b,c,d,e,f 順序進棧, 則不准許的出棧順序是
A. d,c,e,b,f,a B. c,b,d,a,e,f C. b,c,a,e,f,d D. a,f,d,e,c,b
答案:D
2 解法描述與分析
2.1 問題的解法
令 1,2,3,4,5,6… 分別對應着 a,b,c,d,e,f…, 對問題1我們有以下算法
Algorithm 1 判斷出棧順序有效性算法 |
---|
step 1: 我們從前往後把第一個數記爲M。 |
step 2: 然後在後面的數中檢查比M小的數(可以沒有)是否是按逆序排列,如果是則把M及後面的比M小的數從數列中劃掉,否則當前數列不是一個有效的出棧序列並退出判斷流程。 |
step 3: 數列是否爲空,如果不空則回到step1, 否則當前數列爲有效出棧順序並結束判斷流程。 |
例如對於選項 A. d,c,e,b,f,a 其對應的數列爲 4,3,5,2,6,1
step 1: 找到當前第一個數爲4
step 2: 4後面的比4小的數爲 3,2,1,爲逆序排列,劃掉4,及後面比4小的數,現在數列爲 5,6
step 3: 數列不空,回到step 1
step 1: 當前第一個數爲 5
step 2: 5後面的比5小的數沒有,劃掉 5,現在數列爲 6
step 3: 數列不空,回到step 1
step 1: 當前第一個數爲 6
step 2: 6後面沒有比6小的數, 劃掉 5, 現在數列爲空
step 3: 數列爲空,則當前爲有效的出棧順序
對於選項 D, 簡化一下算法運行格式,可得
1,6,4,5,3,2 —> 6,4,5,3,2 —> 由於比6 小的 4,5 沒有逆序排列,所以該序列不是有效的出棧序列。
2.2 算法分析
首先回顧一下棧的定義,棧是 先進後出(FILO) 的線性結構。這裏用反證明來證明算法的有效性。令 1,2,3,…,n分別代表n個依次入棧的元素的序號,即序號爲1的第一個入棧,序號爲n的最後一個入棧,出棧順序未知。假設當第 m 個元素出棧時,且比第 m 個元素小的元素第 i,j,… (i < j < … ) 個元素尚未出棧,如果 i 比 j 先出棧,則按照棧的FILO 性質, i 比 j 後進棧,但這與前面的對序號的解釋相矛盾。則第 m 個元素出棧時,序號比 m 小的元素的出棧順序一定按元素序號逆序進行,即 序號大的先出棧。
3 算法的程序實現
3.1 Python 實現
def check_out_stack(in_stack_list, out_stack_list):
item_dict = {v:i for i,v in enumerate(in_stack_list)}
while len(out_stack_list) > 1:
first_item = out_stack_list[0]
# 獲取比 first_item 小的的元素
smaller_items = [(i+1,v,item_dict[v]) for i,v in enumerate(out_stack_list[1:]) if v < first_item]
index = [item[2] for item in smaller_items]
for i in range(len(index) - 1):
if index[i] - index[i+1] < 0:
return False
# 通過把值改爲None, 然後去除
out_stack_list[0] = None
for i in [item[0] for item in smaller_items]:
out_stack_list[i] = None
for i in range(len(smaller_items)+1):
out_stack_list.remove(None)
print(out_stack_list)
return True
測試:
In: check_out_stack(['a','b','c','d','e','f'],['d','c','e','b','f','a']) # A
['e', 'f']
['f']
Out: True
In: check_out_stack(['a','b','c','d','e','f'],['a','f','d','e','c','b']) # D
['f', 'd', 'e', 'c', 'b']
Out: False