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划掉,否则当前数列不是一个有效的出栈序列并退出判断流程。 |
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,现在数列为 3,5,2,6,1
step 3: 数列不空,回到step 1
step 1: 当前第一个数为 3
step 2: 3 后面的数按逆序排列, 划掉 3,现在数列为 5,2,6,1
step 3: 数列不空, 回到step 1
step 1: 当前第一个数为 5
step 2: 5后面的比5小的数按逆序排列,划掉 5,现在数列为 2,6,1
step 3: 数列不空,回到step 1
step 1: 当前第一个数为 2
step 2: 2 后面比2 小的数按逆序排列,划掉 2, 现在数列为 6,1
step 3: 回到step 3
step 1: 当前第一个数为 6
step 2: 6后面比6小的数按逆序排列, 划掉 6, 现在数列为 1
step 3: 当前数列不空回到 step 1
step 1: 当前第一个数为 1
step 2: 1后面没有数,划掉 1
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
# 去除第一个元素
out_stack_list = out_stack_list[1:]
print(out_stack_list)
return True
测试:
In: check_out_stack(['a','b','c','d','e','f'],['d','c','e','b','f','a']) # A
['c', 'e', 'b', 'f', 'a']
['e', 'b', 'f', 'a']
['b', 'f', 'a']
['f', 'a']
['a']
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