二叉树的遍历:
二叉树的遍历分为深度优先遍历(向下遍历到叶子再返回)和广度优先遍历(先遍历当前层再遍历下一层)
而深度优先遍历 dfs 根据读取的根节点的位置可以分为:
- 前序遍历(根左右)
- 中序遍历(左根右)
- 后序遍历(左右根)
二叉树的递归遍历:
完成递归算法分三步:(PS:被建议的是企业中不太建议用递归,边界条件和debug比较麻烦)
- 确定函数传入的参数和返回值
- 确定边界条件
- 确定正常递归下去的条件
以二叉树的前序遍历为例(python)
# Definition of TreeNode
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):
result = []
# 遍历二叉树,传入参数应当为二叉树的节点,节点的值直接记录在result中,因此不需要返回值
def pre_dfs(tree_node):
# 确定边界条件为tree_node == None
if not tree_node:
return
# 正常递归下去的条件
result.append(tree_node.val)
pre_dfs(tree_node.left)
pre_dfs(tree_node.right)
pre_dfs(root)
return result
对应的题目:
144.二叉树的前序遍历
145.二叉树的后序遍历
145.二叉树的中序遍历
二叉树的迭代遍历
使用栈完成前中后序遍历,访问二叉树结点的顺序一定是先根后孩子,那么前中后序遍历可以是结点的出栈顺序
- 前序遍历
前序遍历根左右与结点的访问顺序相同,因此是根入栈后出栈,并将其孩子结点入栈(先右后左,因为需要出栈顺序为根左右)
class TreeNode(object):
def __init__(self, val=0, left=None, right=Node)
self.val = val
self.left = left
self.right = right
class Solution(object):
def preorderTraversal(self, root):
if not root:
return []
result, stack = [], [root]
while stack:
node = stack.pop()
result.append(node.val)
if node.right: stack.append(node.right)
if node.left: stack.append(node.left)
return result
- 中序遍历
中序遍历左根右与结点访问顺序不同,因此需要使用指针指向当前访问的结点,同时出栈顺序仍然是遍历的结点。一直向左遍历当前结点,为空时出栈并访问栈顶元素,此时已经遍历了左根,再让指针指向当前结点的右孩子
class Solution(object):
def inorderTraversal(self, root):
if not root:
return []
stack, result = [root], []
cur = root
while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()
# 当前已经访问了左根,接着访问右子树
result.append(cur.val)
cur = cur.right
- 后序遍历
后序遍历左右根与结点访问顺序不同,但是可以后序遍历可以由前序遍历的代码更改得到,只需要将出栈顺序改为根右左,最后将结果反转即可
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 postorderTraversal(self, root):
result = []
if not root:
return result
stack = [root]
while stack:
node = stack.pop()
result.append(node.val)
# 需要出栈顺序为中右左
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
# 最后对result进行反转
result = result[::-1]
return result
二叉树的统一迭代遍历:
统一二叉树的前中后序遍历的代码(也即对前序代码进行修改可得到中序遍历的代码),代码不统一的问题出现在访问结点与遍历结点不同,那么我们在入栈结点时,对遍历的结点进行标记,从而出栈根据标记进行遍历。此处的标记为在遍历的结点进栈后再进栈None。同时不同遍历顺序的结点进栈顺序不同
# 中序
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
result = []
stack = []
if root : stack.append(root)
while stack:
node = stack.pop()
# node不为None,表明需要入栈结点
if node:
# 先入栈右结点
if node.right: stack.append(node.right)
# 再入栈根节点和None表明是node需要遍历的结点
stack.append(node)
stack.append(None)
# 最后入栈左结点
if node.left: stack.append(node.left)
# node为None,表明接下来是需要遍历的结点
else:
node = stack.pop()
result.append(node.val)
return result
# 前序
class Solution(object):
def preorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
result = []
stack = []
if root:stack.append(root)
while stack:
node = stack.pop()
if node:
# 入栈顺序为右左根
if node.right: stack.append(node.right)
if node.left: stack.append(node.left)
stack.append(node)
stack.append(None)
# 需要遍历的结点
else:
node = stack.pop()
result.append(node.val)
return result
# 后序
class Solution(object):
def postorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if not root:
return []
result = []
stack = [root]
while stack:
node = stack.pop()
if node:
# 入栈顺序为根右左
stack.append(node)
stack.append(None)
if node.right: stack.append(node.right)
if node.left: stack.append(node.left)
else:
node = stack.pop()
result.append(node.val)
return result
#
二叉树的层序遍历:
使用队列
对于下面这个二叉树,层序遍历返回的为[[5], [6,4], [10, 8, 12]] (逐层从左到右访问所有结点)
# 迭代
from collections import deque
class TreeNode(object):
def __init__(self, val=0, left=None, right=None)
self.val = val
self.left = left
self.right = right
def levelOrder(root):
result = []
queue = deque()
if root: queue.append(root)
while queue:
q_size = len(queue)
level_r = []
for i in range(q_size):
cur = queue.popleft()
level_r.append(cur.val)
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
result.append(level_r)
return result
# 递归实现
def levelOrder(root):
levels = []
# node是当前访问的结点,level用于标记node的层
def bfs_dfs(node, level)
# 边界条件
if not node:
return
# 正常条件
# 遇到当前层的第一个结点时,levels创建空列表
if len(levels) == level:
levels.append([])
# 将node加入当前层的结点列表中
levels[level].append(node.val)
# 递归访问左右子树
bfs_dfs(node.left)
bfs_dfs(node.right)
bfs_dfs(root, 0)
return levels
对应的题目:
102.二叉树的层序遍历
107.二叉树的层序遍历Ⅱ
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的层序遍历
515.在每个树行中找最大值
116.填充每个结点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针Ⅱ
104.二叉树的最大深度
111.二叉树的最小深度
有一些需要注意的题目:
- LeetCode 429.N叉树的层序遍历:
定义中的children是多个child的集合
from collections import deque
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution(object):
def levelOrder(self, root):
"""
:type root: Node
:rtype: List[List[int]]
"""
levels = []
queue = deque()
if root: queue.append(root)
while queue:
q_size = len(queue)
level_n = []
for _ in range(q_size):
cur = queue.popleft()
level_n.append(cur.val)
for child in cur.children:
queue.append(child)
levels.append(level_n)
return levels
- LeetCode.637. 二叉树的层平均值
每层的平均值为 level_ sum / q_size(但是之前写的代码里面直接除有点问题,要转换为float(level_sum) / float(q_size))
from collections import deque
# 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 averageOfLevels(self, root):
"""
:type root: TreeNode
:rtype: List[float]
"""
averages = []
queue = deque()
if root: queue.append(root)
while queue:
q_size = len(queue)
level_sum = 0
for _ in range(q_size):
cur = queue.popleft()
level_sum += cur.val
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
averages.append(float(level_sum) / float(q_size))
return averages
- LeetCode.116. 填充每个结点的下一个右侧结点指针
prev初始化为None,遍历当前层结点的过程中需要prev.next指向cur,且更新prev
from collections import deque
"""
# Definition for a Node.
class Node(object):
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next
"""
class Solution(object):
def connect(self, root):
"""
:type root: Node
:rtype: Node
"""
queue = deque()
if root: queue.append(root)
while queue:
q_size = len(queue)
prev = None # 初始化为None,如果要初始化为最右侧结点,那么queue需要入队prev.left和prev.right
for i in range(q_size):
cur = queue.popleft()
if prev: prev.next = cur # prev不为None时指向cur
prev = cur # 更新prev
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
return root
学习收获:
学习了二叉树的深度优先遍历,前中后序的递归、迭代和统一迭代;学习了二叉树的广度优先遍历,即层序遍历