二叉树遍历方法总结
二叉树基本概念
面试的时候提到的树, 大部分都是二叉树. 所谓二叉树是树的一种特殊结构, 在二叉树中每个节点最多只能有两个子节点, 在二叉树中最重要的操作莫过于遍历, 即按照某一顺序访问树中的所有节点.
树的遍历方式
通常树有如下几种遍历方式:
- 前序遍历
- 中序遍历
- 后续遍历
每种遍历都对应三种实现方式, 基于递归和迭代(循环)实现的时间复杂度为\(O(n)\), 空间复杂度为\(O(n)\) (递归和迭代的空间复杂度是由栈的深度决定的, 通常情况下为\(O(logn)\), 最坏的情况为单链\(O(n)\)), 基于Morris算法的时间复杂度为\(O(n)\), 空间复杂度为\(O(1)\). (应聘者应该对这三种遍历的9种实现方式都了如指掌)
Morris通用解法
Morris遍历使用二叉树节点中大量指向null的指针, 将空间复杂度从\(O(n)\)优化到\(O(1)\), , 由Joseph Morris 于1979年发明, Morris的通用解法过程如下:

Morris的整体思路为: 从某个跟节点出发, 找到它的左子树的最右侧节点之后与这个跟节点进行连接. 由右图, 建立连接之后, cur这个指针可以完整的从一个节点顺着下一个节点遍历, 将整棵树遍历完毕, 直到7这个节点右侧没有指向.
基于递归的实现
前序遍历
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
return self.traversal(root, [])
def traversal(self, root, res):
if not root:
return []
res.append(root.val)
self.traversal(root.left, res)
self.traversal(root.right, res)
return res
中序遍历
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
def traversal(root):
if not root:
return []
traversal(root.left)
res.append(root.val)
traversal(root.right)
return res
res = []
return traversal(root)
后续遍历
class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
def traversal(root, res):
if not root:
return []
traversal(root.left, res)
traversal(root.right, res)
res.append(root.val)
return res
return traversal(root, [])
递归函数传参python
python传参机制为: python不允许用户在函数的参数传递中选择是值传递还是引用传递, 而是采用的对象引用传递, 如果函数收到的是一个可变对象(如列表, 字典)的引用, 就采用引用传递, 而如果收到的是一个不可变的对象(如数值, 字符串或元组) 的引用, 就采用值传递, 在函数中将无法改变参数的原始值.
问题: 如果是值传递, 怎么保证递归可以返回该值呢, 如count=0需要在递归过程中过自加一:
- 使用数组初始化并作为参数传递
- 将count作为递归函数的参数, 并且每次都要定义res=traversal(~, count)接收每一次改变.
基于迭代的实现
前序遍历
# 自己的实现, 多叉树暂时未验证
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack, res = [root], []
while stack:
node = stack.pop()
res.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return res
# 官方实现: (深入浅出) 先深入到最左侧支左子树终点, 再弹栈一次往右侧找
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack, res = [], []
node = root
while node or stack:
while node: # 一路向左
stack.append(node)
res.append(node.val)
node = node.left
node = stack.pop()
node = node.right
return res
中序遍历
和前序遍历套路差不多, 都有先一路向左的风范, 不同的是, 在一路向左的过程中, 没有记录结果, 最后弹栈一次并记录(形象一点就是深入浅出), 取道向右作为新的root
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
stack, res = [], []
node = root
while node or stack: # 这里两个条件比较巧妙, 也可以初始化为stack = [root]
while node: # 一路向左
stack.append(node)
node = node.left
node = stack.pop()
res.append(node.val) # 每次弹栈记录到res中
node = node.right # if right==None, stop
return res
后续遍历

浙公网安备 33010602011771号