二叉树的遍历
1 递归遍历
写法类似于回溯,前序 中序 后序遍历的套路一样,只是保存元素的位置不同.层序遍历的关键是要添加level参数,用于记录节点所在的层数.
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None # 经典的递归法 from typing import List class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: result_pre = [] result_in = [] result_bac = [] def recursion(root): # 如果遍历到一个分支的底了,则为空节点,返回True,继续遍历 if root == None: return # 前序遍历 result_pre.append(root.val) recursion(root.left) # 中序遍历 result_in.append(root.val) recursion(root.right) # 后序遍历 result_bac.append(root.val) recursion(root) print(result_pre) print(result_in) print(result_bac) # 这里的层序遍历是dfs,深度优先遍历 class Solution: def levelOrder(self, root): levels = [] # 如果为空节点,直接返回[] if not root: return levels def helper(node, level): # 如果相等了,说明是新加的层,则添一个[] if len(levels) == level: levels.append([]) # 将节点存入相应的层 levels[level].append(node.val) # 注意必须是先左后右,这样才能保证每层是按从左往右顺序存储的 if node.left: helper(node.left, level + 1) if node.right: helper(node.right, level + 1) helper(root, 0) return levels if __name__ == '__main__': duixiang = Solution() root = TreeNode(8) a = TreeNode(4) b = TreeNode(9) root.left = a root.right = b al = TreeNode(3) ar = TreeNode(6) a.left = al a.right = ar arl = TreeNode(5) arr = TreeNode(7) ar.left = arl ar.right = arr a = duixiang.levelOrder(root) print(a)
2 迭代遍历
中序和后序遍历比前序遍历思路一样,只不过多了对节点的记录,没有遍历过标记为1,等待遍历,遍历过的标记为0.
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None # 前序遍历的迭代法 class Solution: def preorder(self, root): res = [] if root is None: return [] stack = [] stack.append(root) # 只有前序遍历可以这样写,因为前序遍历先存储中间的节点值,是中 左 右的顺序遍历 # 而中序和后序遍历需要从最左边开始,而我们是从最上面的节点开始遍历的,所以需要记录节点是否被遍历过 while stack: x = stack.pop() res.append(x.val) if x.right: stack.append(x.right) if x.left: stack.append(x.left) return res # 层序遍历的迭代法 class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: results = [] stack_next = [] if not root: return [] stack_next.append(root) # stack_next用于记录下一层的节点,stack用于遍历当前层 while stack_next: stack = stack_next # 记录节点前先清空 stack_next = [] res = [] while stack: # 由于每一层都是从左往右依次保存,故这里用队列 k = stack.pop(0) # 注意这里的顺序 if k.left: stack_next.append(k.left) if k.right: stack_next.append(k.right) res.append(k.val) # 下次循环res被赋值为空了,为新的引用,故不用深拷贝也行 results.append(res) return results # 中序后序遍历的迭代法 class Solution: def levelOrder(self, root): res = [] stack = [] stack.append((root,1)) while stack: x,sign = stack.pop() if x is None: continue # 这里用0标记被遍历过了,1表示没有遍历,如遍历过了则存储 # 否则继续遍历,一直朝左找到底 if sign: # 中序遍历 stack.append((x.right, 1)) stack.append((x, 0)) stack.append((x.left, 1)) ## 后序遍历 # stack.append((x, 0)) # stack.append((x.right, 1)) # stack.append((x.left, 1)) else: res.append(x.val) return res if __name__ == '__main__': duixiang = Solution() root = TreeNode(8) a = TreeNode(4) b = TreeNode(9) root.left = a root.right = b al = TreeNode(3) ar = TreeNode(6) a.left = al a.right = ar arl = TreeNode(5) arr = TreeNode(7) ar.left = arl ar.right = arr a = duixiang.levelOrder(root) print(a)
中序遍历的迭代实现,这个方法非常精妙,充分利用了中序遍历的结构特点,每个节点都是进一次栈出一次栈.
# # 中序遍历的迭代方法 # https://leetcode.com/problems/binary-tree-inorder-traversal/discuss/442853/Python-recursion-simple-and-readable-beat-90.22-runtime-100-memory from typing import List class Solution: def levelOrder(self, root: TreeNode) -> List[int]: res,temp = [],[] while 1: # 先对某个节点超左遍历到底, while root: temp.append(root) root = root.left # 栈为空,说明遍历完了,返回结果 if not temp:return res # 然后一个一个弹出来, root = temp.pop() res.append(root.val) # 每弹出一个来,都要判断其是否有右子树,如果有继续压栈遍历 # 事实上这里只有两种情况,如果左边的root为空了,说明右边的root为左 中 右的左,否则为中, root = root.right
后序遍历的迭代实现,前序遍历是中 左 右,后序是左 右 中,反过来是中 右 左,利用对称性只需在前序遍历的基础上稍微改动即可.
class Solution: def postorderTraversal(self, root: TreeNode) -> List[int]: stack,res = [],[] if root is None: return [] stack.append(root) while stack: a = stack.pop() res.append(a.val) if a.left: stack.append(a.left) if a.right: stack.append(a.right) res.reverse() return res