题目描述:
翻转( 也叫颠倒 )栈的所有元素,例如输入栈 {1,2,3,4,5},其中 1 处在栈顶,翻转之后的栈为{5,4,3,2,1},其中,5处在栈顶。
思路:
最容易想到的办法是申请一个额外的队列,先把栈中的元素依次出栈放到队列中,然后把队列里的元素按照出队列顺序入栈,这样就可以实现栈的翻转。这种方法的缺点是需要申请额外的空间来存储队列,因此空间复杂度较高。
下面介绍一种空间复杂度较低的递归方法。
递归程序有两个关键因素需要注意:递归定义和递归终止条件。经过分析后,很容易得到该问题的递归定义和递归终止条件。递归定义:将当前栈的最底元素移到栈顶,其他元素顺次下移一位,然后对不包含栈顶元素的子栈进行同样的操作。终止条件:递归下去,直到栈为空
。
递归的调用过程入下图所示:
在上图中,对于栈{1,2,3,4,5},进行翻转的操作为,首先把栈底元素移到栈顶得到{5,1,2,3,4},然后对不包含栈顶元素的子栈进行递归调用(对子栈元素进行翻转),子栈{1,2,3,4}翻转的结果为{4,3,2,1},因此最终得到的翻转后的栈为{5,4,3,2,1}.
此外,由于栈后进先出的特点,使得只能取栈顶的元素,所以要把栈底的元素移动到栈顶也需要递归调用才能完成
。主要思想为,把不包含该栈顶元素的子栈的栈底元素移动到子栈的栈顶,然后把栈顶的元素与子栈栈顶的元素( 其实就是与栈顶相邻的元素 )进行交换。
为了更容易地理解递归调用,可以认为在进行递归调用的时候,子栈已经把栈底元素移动到了栈顶,在上图中,为了把栈{1,2,3,4,5}的栈底元素5移动到栈顶,首先对子栈{2,3,4,5}进行递归调用,调用结果为{5,2,3,4},然后对子栈栈顶元素5,与栈顶元素1进行交换得到栈{5,1,2,3,4},实现了把栈底元素移动栈顶。
算法分为两步:
- 递归地把栈底元素移动到栈顶
- 递归地调用除栈顶元素以外的子栈
算法性能分析:
把栈底元素移动到栈顶操作的时间复杂度为O(n),在翻转操作中对每个子栈都进行了把栈底元素移动到栈顶的操作,所以,翻转算法的时间复杂度为O(n**2)
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2020/1/20 18:27
# @Author : buu
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44321080
class Mystack: # 新建一个栈类
def __init__(self): # 模拟栈
self.items = [] # 用列表实现
def isEmpty(self): # 栈是否为空
return len(self.items) == 0
def size(self): # 栈的大小
return len(self.items)
def peek(self): # 取栈顶元素
if not self.isEmpty():
return self.items[len(self.items) - 1]
else:
return None
def pop(self): # 弹栈
if len(self.items) > 0: # 先判断栈是否为空
return self.items.pop()
else:
print('stack is empty!')
return None
def push(self, item): # 入栈
self.items.append(item)
def moveBottom2top(s):
"""
把栈底元素移动到栈顶
:param s: 栈的引用
:return:
"""
if s.isEmpty():
return
top1 = s.peek() # 获得栈顶元素
s.pop() # 弹出栈顶元素
if not s.isEmpty(): # 若不包含栈顶元素的子栈非空
moveBottom2top(s) # 递归地处理不包含栈顶元素的子栈
top2 = s.peek()
s.pop()
s.push(top1)
s.push(top2)
else:
s.push(top1)
def reverseStack(s):
"""
将栈进行翻转
:param s:栈的引用
:return:
"""
if s.isEmpty():
return
moveBottom2top(s) # 将栈底元素移动到栈顶
top = s.peek() # 获得栈顶元素
s.pop()
reverseStack(s) # 递归地对不包含栈顶元素的子栈进行翻转
s.push(top)
if __name__ == '__main__':
s = Mystack()
s.push(5)
s.push(4)
s.push(3)
s.push(2)
s.push(1)
reverseStack(s)
print('after:', end=' ')
while s.size() > 0:
print(s.peek(), end=' ')
s.pop()
结果:
引申:
如何给栈排序
思路:
对上述方法进行修改得到栈的排序算法。首先对不包含栈顶元素的子栈进行排序,如果栈顶元素大于子栈的栈顶元素,则交换这两个元素。所以在上述方法中,只需要在交换栈顶元素与子栈顶元素的时候增加一个条件判断即可实现栈的排序。
算法性能分析:
此方法的时间复杂度为O(n**2)
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2020/1/20 18:50
# @Author : buu
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44321080
class Mystack: # 新建一个栈类
def __init__(self): # 模拟栈
self.items = [] # 用列表实现
def isEmpty(self): # 栈是否为空
return len(self.items) == 0
def size(self): # 栈的大小
return len(self.items)
def peek(self): # 取栈顶元素
if not self.isEmpty():
return self.items[len(self.items) - 1]
else:
return None
def pop(self): # 弹栈
if len(self.items) > 0: # 先判断栈是否为空
return self.items.pop()
else:
print('stack is empty!')
return None
def push(self, item): # 入栈
self.items.append(item)
def moveBottom2top(s):
"""
把栈底元素移动到栈顶
:param s: 栈的引用
:return:
"""
if s.isEmpty():
return
top1 = s.peek() # 获得栈顶元素
s.pop() # 弹出栈顶元素
if not s.isEmpty(): # 若不包含栈顶元素的子栈非空
moveBottom2top(s) # 递归地处理不包含栈顶元素的子栈
top2 = s.peek()
if top1 > top2:
s.pop()
s.push(top1)
s.push(top2)
return
s.push(top1)
def sortStack(s):
"""
把栈内的元素排序
:param s: 栈的引用
:return:
"""
if s.isEmpty():
return
moveBottom2top(s) # 把栈底元素移动到栈顶
top = s.peek()
s.pop()
sortStack(s) # 递归地处理栈
s.push(top)
if __name__ == '__main__':
s = Mystack()
s.push(1)
s.push(2)
s.push(3)
sortStack(s)
print('sorted stack:', end=' ')
while not s.isEmpty():
print(s.peek(), end=' ')
s.pop()
结果:
end