系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
前言
【Leetcode】#144. 二叉树的前序遍历
【Leetcode】#94. 二叉树的中序遍历
【Leetcode】#145. 二叉树的后序遍历
有两种通用的遍历树的策略:
-
深度优先搜索(
DFS
)在这个策略中,我们采用
深度
作为优先级,以便从根开始一直到达某个确定的叶子,然后再返回根到达另一个分支。深度优先搜索策略又可以根据根节点、左孩子和右孩子的相对顺序被细分为
前序遍历
,中序遍历
和后序遍历
。 -
宽度优先搜索(
BFS
)我们按照高度顺序一层一层的访问整棵树,高层次的节点将会比低层次的节点先被访问到。
下图中的顶点按照访问的顺序编号,按照 1-2-3-4-5
的顺序来比较不同的策略。
使用递归方法很简单,可以通过迭代算法来解
深度遍历-方法1:递归
# 前序
def preorderTraversal(self, root):
if root is None: return []
out = [root.val]
out.extend(self.preorderTraversal(root.left))
out.extend(self.preorderTraversal(root.right))
return out
# 中序
def inorderTraversal(self, root):
if root is None: return []
out.extend(self.inorderTraversal(root.left))
out = [root.val]
out.extend(self.inorderTraversal(root.right))
return out
# 后序
def postorderTraversal(self, root):
if root is None: return []
out.extend(self.postorderTraversal(root.left))
out.extend(self.postorderTraversal(root.right))
out = [root.val]
return out
list1 = [1, 2, 3]
list2 = [2, 3, 10]
list3 = ['bg', [], 'ed']
# list1.append(list2)
# list1.append(list3)
# append:[1, 2, 3, [2, 3, 10], ['bg', [], 'ed']]
# list1.extend(list2)
# list1.extend(list3)
# extend:[1, 2, 3, 2, 3, 10, 'bg', [], 'ed']
深度遍历-方法2:迭代
以前序遍历为例,从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压右孩子再压左孩子。
在这个算法中,输出到最终结果的顺序按照 Top->Bottom
和 Left->Right
,符合前序遍历的顺序。
该算法只适用前序遍历。
def preorderTraversal(self, root: TreeNode) -> List[int]:
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
算法复杂度:
- 时间复杂度:访问每个节点恰好一次,时间复杂度为 O(N) ,其中 N 是节点的个数,也就是树的大小。
- 空间复杂度:取决于树的结构,最坏情况存储整棵树,因此空间复杂度是 O(N)。
深度遍历-方法2.1:迭代优化
- 上面的迭代代码是遇到节点直接把
节点值
存到输出数组里面,这种方法适合前序遍历,因为不用判断左孩子
和右孩子
,所以不适合中序和后序遍历。- 上面的那种方法是把
节点值
输出然后再把右孩子
和左孩子
依次压入栈中,那么我们应该也可以把根的节点值
也一并的压入栈中。- 根据
左孩子
、右孩子
、根的值
压入栈中的顺序不同,从而实现前序、中序、后序的迭代遍历
参照递归的写法,使用栈这种数据结构(使用队列也可)
:
因为栈是先进后出,前序遍历是根、左、右
所以我们先把右孩子压进去,再压左孩子,最后再把根的值压进去
这样出栈的顺序就是根–>左孩子–>右孩子,就实现了前序遍历
# 前序遍历
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)
之后判断何时可以将节点的值输出?
在栈中的数据类型一共有三种:
Null
、树节点
和树节点值
,而我们需要输出的值即为树节点值
,所以我们只需要判断何时为树节点值
即可;
也就是判断该节点不是树节点
和Null
:
if type(root) is not root_type and root is not None
# 以前序遍历为例
def preorderTraversal(self, root: TreeNode) -> List[int]:
if root is None:
return []
stack, out = [root, ], []
root_type = type(root)
while stack:
root = stack.pop()
if type(root) is not root_type and root is not None:
out.append(root)
continue
if root:
stack.append(root.right)
stack.append(root.left)
stack.append(root.val)
return out