二叉树
二叉树的遍历主要有前序、中序、后序、层序四种遍历方式,遍历方法可以通过递归和迭代实现。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
如图,前序遍历按照根节点->左孩子->右孩子的方式遍历,因此遍历结果为:1-2-4-5-3-6-7;
中序遍历按照左孩子->根节点->右孩子的方式遍历,因此遍历结果为:4-2-5-1-6-3-7;
后序遍历按照左孩子->右孩子->根节点的方式遍历,因此遍历结果为:4-5-2-6-7-3-1;
层序遍历按照每一层从左向右的方式进行遍历,因此遍历结果为:1-2-3-4-5-6-7;
1.二叉树的前序遍历
- 递归实现
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def presearch(root):
nonlocal res
if not root:
return
res.append(root.val) #前序遍历
presearch(root.left)
presearch(root.right)
presearch(root)
return res
-
迭代实现
常规的迭代主要是通过栈来进行迭代,过程如下:1.初始化栈,并将根节点入栈;
2.当栈不为空时:弹出栈顶元素node,并将值添加到结果中;如果node的右子树非空,将右子树入栈;如果node的左子树非空,将左子树入栈。(栈的先进后出原则)
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return
stack, res = [root], []
while stack:
node = stack.pop()
if node:
res.append(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return res
也可以用模板解法,模板解法先将根节点node和所有左孩子入栈并加入结果中,直至node为空(while循环),然后每弹出一个栈顶元素tmp,就到达它的右孩子,再将这个节点当作当前的node,重复上述操作,直至栈为空(while循环)
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return
stack, node, res = [], root, []
while stack or node:
while node: #根节点和左孩子全部入栈
res.append(node.val)
stack.append(node)
node = node.left
tmp = stack.pop() #每弹出一个元素,就到达右孩子
node = tmp.right
return res
2.二叉树的中序遍历
- 递归实现
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def midsearch(root):
nonlocal res
if not root:
return
midsearch(root.left)
res.append(root.val) #中序遍历
midsearch(root.right)
midsearch(root)
return res
- 迭代实现
与前序遍历的代码一致,只是在出栈的时候才将节点tmp的值加入到结果中。
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return
stack, node, res = [], root, []
while stack or node:
while node: #所有根节点和左孩子入栈,此时不计入res中
stack.append(node)
node = node.left
tmp = stack.pop()
res.append(tmp.val) #弹出的节点加入到res中
node = tmp.right
return res
3.二叉树的后序遍历
- 递归实现
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
res = []
def postsearch(root):
nonlocal res
if not root:
return
postsearch(root.left)
postsearch(root.right)
res.append(root.val) #后序遍历
postsearch(root)
return res
- 迭代实现
利用后序遍历结果与前序遍历(根节点->右孩子->左孩子)结果输出相反的特性,迭代遍历可写成如下:
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return
stack, node, res = [], root, []
while stack or node:
while node: #所有根节点和右孩子加入栈中
stack.append(node)
res.append(node.val)
node = node.right
tmp = stack.pop() #弹出栈顶元素,访问左孩子
node = tmp.left
return res[::-1]
常规解法:
类比前序遍历的常规解法,我们只需要将输出的“根 -> 左 -> 右”的顺序改为“左 -> 右 -> 根”就可以了。
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return
stack, res = [(0, root)], []
while stack:
flag, node = stack.pop()
if not node:
continue
if flag == 1:
res.append(node.val)
else:
stack.append((1, node))
stack.append((0, node.right))
stack.append((0, node.left))
return res
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
stack, res = [], []
while stack or root:
while root: # 下行循环,直到找到第一个叶子节点
stack.append(root)
if root.left: # 能左就左,不能左就右
root = root.left
else:
root = root.right
s = stack.pop()
res.append(s.val)
#如果当前节点是上一节点的左子节点,则遍历右子节点
if stack and s == stack[-1].left:
root = stack[-1].right
else:
root = None
return res
4.二叉树的层序遍历
二叉树的层次遍历的迭代方法与前面不同,因为前面的都采用了深度优先搜索的方式,而层次遍历使用了广度优先搜索,广度优先搜索主要使用队列实现,也就不能使用前面的模板解法了。
广度优先搜索的步骤为:
1.初始化队列q,并将根节点root加入到队列中;
2.当队列不为空时:队列中弹出节点node,加入到结果中;如果左子树非空,左子树加入队列;如果右子树非空,右子树加入队列。
由于题目要求每一层保存在一个子数组中,所以我们额外加入了 level 保存每层的遍历结果,并使用for循环来实现。
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
q, res = [root], []
while q:
n = len(q)
level = []
for i in range(n):
node = q.pop(0)
level.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
res.append(level)
return res