递归
今天在做LeetCode的二叉树前序遍历题的时候,我看到题目是这样的:
给定一个二叉树,返回它的前序遍历
递归方法很简单,你可以通过迭代算法完成吗?
我当时就不乐意了,你这也太高看我了,什么叫递归方法很简单?没想到我递归方法我也不会吧
经过我冥思苦想终于把以前学数据结构的时候记忆拿回来了
其实真的很简单,如下:
# 前序
def __init__(self):
self.out = []
def preorderTraversal(self, root):
if root is None: return []
self.out.extend([root.val])
self.preorderTraversal(root.left)
self.preorderTraversal(root.right)
return self.out
# 中序
def __init__(self):
self.out = []
def inorderTraversal(self, root):
if root is None: return []
self.inorderTraversal(root.left)
self.out.extend([root.val])
self.inorderTraversal(root.right)
return self.out
# 后序
def __init__(self):
self.out = []
def postorderTraversal(self, root):
if root is None: return []
self.preorderTraversal(root.left)
self.preorderTraversal(root.right)
self.out.extend([root.val])
return self.out
这不是我这篇文章的重点,这只是前戏,还有就是递归真的很简单,我就不解释了
迭代
题目都说递归很简单了,让我用迭代的方法,那么我怎么能示弱呢?
于是我想破我的小脑袋瓜也还是没有想出来,于是我看了题解。。。终于悟到其中的奥妙
接着就有了下面的代码
def preorderTraversal(self, root):
if root is None:
return []
out = []
stack = [root]
while stack:
root = stack.pop()
if root:
out.append(root.val)
stack.append(root.right)
stack.append(root.left)
return out
这也很简单,几乎就和官方题解一模一样,也没什么好解释的吧,但是我把这个方法理解之后看到一个C++大佬的题解说改变一行代码就实现前序、中序、后序的迭代遍历,反正具体的代码我也没看,我就想我用Python来实现一个
于是我就想了想
上面那套代码是遇到节点直接把它的值存到输出数组里面,这种方法适合前序遍历,但并不适合中序和后序遍历。
上面的那种方法是把节点值输出然后再把右孩子和左孩子依次压入栈中,我就想我应该也可以把根节点的值也一并的压入栈中。
根据左孩子、右孩子、根的值压入栈中的顺序不同,从而实现前序、中序、后序的迭代遍历
因为栈是先进后出,前序遍历是根、左、右
所以我们先把右孩子压进去,再压左孩子,最后再把根的值压进去
这样出栈的顺序就是根-->左孩子-->右孩子,就实现了前序遍历
# 前序遍历
stack.append(root.right)
stack.append(root.left)
stack.append(root.val)
同理
我们先把右孩子压进去,再压根的值,最后再把左孩子压进去
这样出栈的顺序就是左孩子-->根-->右孩子,就实现了中序遍历
# 中序遍历
stack.append(root.right)
stack.append(root.val)
stack.append(root.left)
再次同理
我们先把根的值压进去,再压右孩子,最后再把左孩子压进去
这样出栈的顺序就是左孩子-->右孩子-->根,就实现了后序遍历
# 中序遍历
stack.append(root.val)
stack.append(root.right)
stack.append(root.left)
综上
前序遍历
def preorderTraversal(self, root):
if root is None:
return []
t = type(root)# 保存树的类型
out = []# 初始化输出数组
stack = [root]# 将树压入栈中
while stack:# 循环栈
root = stack.pop()# 根节点等于出栈的节点
if type(root) != t and root is not None:# 如果此时root不为树并且不为空
out.append(root)# 将这个数加入输出数组中
continue# 结束本次循环
if root: # 如果此时root是树
stack.append(root.right)# 将右孩子压入栈
stack.append(root.left)# 将左孩子压入栈
stack.append(root.val)# 将根的值压入栈
return out
中序遍历
def inorderTraversal(self, root):
if root is None:
return []
t = type(root)
out = []
stack = [root]
while stack:
root = stack.pop()
if type(root) != t and root is not None:
out.append(root)
continue
if root:
stack.append(root.right)
stack.append(root.val)# 中序遍历
stack.append(root.left)
return out
后序遍历
def postorderTraversal(self, root):
if root is None:
return []
t = type(root)
out = []
stack = [root]
while stack:
root = stack.pop()
if type(root) != t and root is not None:
out.append(root)
continue
if root:
stack.append(root.val)# 后序遍历
stack.append(root.right)
stack.append(root.left)
return out
以上就是我的思路和理解。
从本质上来说,递归遍历二叉树和迭代遍历二叉树都是一样的,递归遍历二叉树是程序帮我们管理栈,迭代遍历二叉树是我们手动去维护栈。