(三)二叉树的深度优先遍历(前中后序)的递归实现
首先, 先实现树, 构造树后, 才能遍历树的节点;
这里提供根据,层序输入列表构建 二叉树;
空节点, 使用 - 1 表示;
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
import collections
def levelInputCreateTree(nums: list) -> TreeNode:
root = TreeNode(nums[0]) # 将数组首元素 作为根节点;
que = collections.deque([root]) # 调用 collections 中的 deque, 并且将根节点 输入到其中;
i, lenNum = 1, len(nums) # i 从数组中的下标1开始, 遍历输入到队列中;
# 迭代法, 创建二叉树
while i < lenNum:
cur_Node = que.popleft() # 弹出双端队列的 左边队首的元素; 该弹出的元素是一个树的节点, 作为当前的节点;
leftVal, rightVal = nums[i], nums[i + 1] if i + 1 < lenNum else -1 # 如果下标 i + 1 超过数组下标, 则赋值为 -1 ;
if leftVal != -1 : # 输入的数组中的 -1 代表此处是 空节点; 或者超出数组下标;
leftNode = TreeNode(leftVal) # 将左值 初始化为树的 一个节点;
cur_Node.left = leftNode # 将 上述的 左值树节点 赋值为 curNode 的左子树;
que.append(leftNode) # 将该节点入队, 便于后序出队, 为他添加子树,也即子节点;
if rightVal != -1:
rightNode = TreeNode(rightVal)
cur_Node.right = rightNode
que.append(rightNode)
i += 2
return root
if __name__ == "__main__":
print("--- please input a level order list to create A Binary Tree---")
# strip 去除输入中最左边右边的 空格; split 将输入按空格分割, 返回一个列表;
# map 是将input() 输入的字符串 转换为 int 整型;
nums = list(map(int, input().strip().split()))
print("you level order Tree input list : ", nums)
# 将输入的 层序 列表 建成树;
tree1 = levelInputCreateTree(nums)
# 按照 先序遍历树;
print(" preorder Traversal the Tree: \n", preOrderTraversal(tree1))
# 18 7 11 3 4 5 6
1. 递归的三要素
-
递归函数的输出类型 和 输入参数;
-
递归的终止条件, 即满足何时递归到底, 到底后, 可以从从底往上返回了;
-
单层递归中, 应该执行的步骤;
1.1 递归函数的三要素
以前序遍历的 递归 举例:
-
递归函数的输出类型, 递归函数的输入参数:
输入参数 root , 表示当前遍历到的节点;
输出参数: 无, 最终结果 在递归函数外面; -
递归的终止条件:
递归终止的条件为碰到空节点。 -
单层递归的步骤:
首先将 root 节点的值加入答案,
然后递归调用 preorder(root.left) 来遍历 root 节点的左子树,
最后递归调用 preorder(root.right) 来遍历 root 节点的右子树即可。
2. 深度优先遍历的递归实现
2.1 前序遍历的递归实现
二叉树先序遍历的过程中,首先访问根节点,然后依次遍历其左右子树,左右子树的访问过程递归进行。
该过程是「自顶向下」的,不论是「递归」还是「迭代」,对任意一个节点,当且仅当其父节点遍历完成后,才能遍历该节点及其子树。
适用场景: 已知父节点信息, 求子节点的信息;
因此,实际问题求解中,若需要基于已求出的「父节点」信息,自顶向下地求解各个「子节点」的信息;
此时可考虑对二叉树进行先序遍历,在遍历的过程中维护所求出的信息。
例如:给定一棵二叉树,判断其是否为对称二叉树。
def preOrderTraversal(root: TreeNode) -> list:
result = []
def traversal(root: TreeNode)-> None: # 1. 递归的输入参数, 以及输出参数
if root == None : # 2. 递归终止条件: 若当前节点是个空节点, 说明递归到底了, 结束, 开始从后往前返回;
return
result.append(root.val) # 3. 单层递归需要执行的操作 , 由于是前序遍历, 故先取出当前节点的数值, 然后遍历当前节点它的左子树, 在遍历当前节点的右子树;
traversal(root.left)
traversal(root.right)
traversal(root) # 递归入口;
return result
2.2 中序遍历的递归实现
二叉树中序遍历的过程中,首先访问左子树,然后访问根节点,最后访问右子树,左右子树的访问过程递归进行。
适用场景: 求二叉搜索树的相关问题
由于「二叉搜索树」中,任意节点的值均比其左子树中各个节点的值大,均比其右子树中各个节点的值小,且左右子树同样满足此性质,因此中序遍历是常用于遍历二叉搜索树,且得到的中序遍历序列「严格递增」。
因此,若实际问题中给定二叉搜索树,可基于中序遍历进行问题求解。
例如:给定一棵二叉树,判断其是否是二叉搜索树。
def inorderTraversal(root: TreeNode) -> list:
result = []
def traversal(root: TreeNode) -> None: # 1. 递归函数的 输入参数, 输出参数
if root == None: # 2. 递归函数的 终止条件
return
# 3. 单层递归中, 应该执行的步骤
traversal(root.left) # 中序遍历,先遍历左子树;
result.append(root.val) # 然后, 保存当前节点值;
traversal(root.right) # 之后遍历右子树;
traversal(root) # 递归函数入口
return result
2.3 后序遍历的递归实现
二叉树后序遍历的过程中,首先访问左子树,然后访问右子树,最后访问根节点,左右子树的访问过程递归进行。
与二叉树的先序遍历不同,二叉树后序遍历的过程是「自底向上」的,不论是「递归」还是「迭代」,对任意一个节点,当且仅当其左子树和右子树均遍历完成后,才能遍历该节点。
适用场景: 根据左右子树的信息, 求出当前节点(或称为父节点)的信息;
因此,实际问题求解中,若需要基于已求出的「左子树和右子树」的信息,自底向上地求解各个「当前节点」的信息,此时可考虑对二叉树进行后序遍历,在遍历的过程中维护所求出的信息。例如:
给定一棵二叉树,判断其是否是平衡二叉树;
给定一棵二叉树与两个节点,返回这两个节点的最近公共祖先节点。
def postorderTraversal(root: TreeNode) -> list:
result = []
def traversal(root: TreeNode)-> None: # 1. 递归的输入 ,输出参数
if root == None: # 2. 递归的终止条件
return
# 3. 单层递归中,应该执行的步骤;
traversal(root.left)
traversal(root.right)
result.append(root.val)
traversal(root)
return result