Python二叉树的遍历

一、二叉树几个概念

bytetoy.cn

注意区分几个概念:

  • 二叉树的高度与层;
  • 二叉树的高度是从最底部起算,而深度是从根节点起算;

基本术语

  • 节点所在的层 level:从顶至底递增,根节点所在层为 1
  • 节点的度 degree:节点的子节点的数量。在二叉树中,度的取值范围是[ 0、1、2] 。即节点所拥有叶子节点的数量
  • 二叉树的高度 height:从根节点到最远叶节点所经过的边的数量。
  • 节点的深度 depth:从根节点到该节点所经过的边的数量。
  • 节点的高度 height:从距离该节点最远的叶节点到该节点所经过的边的数量。

树的类型

  • 完美二叉树:所有层的节点都被完全填满,满二叉树,叶节点的度为0,其余所有节点的度都为2;若树的高度为h,则节点总数为2^(h+1)-1,如一个高度h=3的满二叉树,即有根节点到底节点共有4层,一共有15个节点(第一层1个,第二层2个,第三层4个,第四层8个)
  • 完全二叉树:只有最底层的节点未被填满,且最底层节点尽量靠左填充。
  • 完满二叉树:除了叶节点之外,其余所有节点都有两个子节点,即节点的,要么为0,要么为2
  • 平衡二叉树:任意节点的左子树和右子树的高度之差的绝对值不超过 1

二、列表转换为二叉树

bytetoy.cn

将列表元素按照层顺序,逐层填满二叉树,即转换之后的二叉树是一个完全二叉树 计算公式:

  • 当前元素的下标为i,如:第0个元素;
  • 其左节点的下标为i×2+1,如:第0个元素的,左节点下标为1
  • 其右节点的效标为i×2+2,如:第0个元素,右节点的下标为2
  • 整体上通过递归方式实现,边界(返回)条件为列表下标越界,或者元素为None
  • 由于要获取元素的左、右两个子节点,因此递归中需要两次调用函数本身,获取左右子节点
# 使用递归方式,将list转换为二叉树,按层的顺序实现转换
# 先判断arr的下标start是否越界,然后再新建节点
def create_btree(arr, start):
    if start < 0 or start >= len(arr) or arr[start] is None:
        return None
    root = TreeNode(arr[start])
    root.left = create_btree(arr, start * 2 + 1)
    root.right = create_btree(arr, start * 2 + 2)

    return root

三、广度优先遍历

bytetoy.cn

广度优先(breadth-first traversal),即按层遍历二叉树的所有节点,逐层访问全部节点的方式

实现方式:(队列)

  • 使用标准库(collections)中的deque双向链表类作为列表
  • 使用while循环,当队列为None是终止循环
  • 读取根节点,同时获取左右子节点,按照顺序将左右节点加入(append)队列;append
  • 弹出(popleft)队列中节点,同时获取其左右自节点,按照顺序将左右节点加入队列;
  • 弹出队列的节点时,将节点元素内容存入列表。
# 广度优先(breadth-first traversal)方式遍历二叉树
# 以队列方式实现,按层进行遍历
def bfs_travel(root):
    res = []
    queue = deque()
    queue.append(root)
    while queue:
        node: TreeNode = queue.popleft()
        res.append(node.val)
        if node.left is not None:
            queue.append(node.left)
        if node.right is not None:
            queue.append(node.right)
    return res

四、深度优先遍历

bytetoy.cn

深度优先分为前序、中序以及后序方式,区分的依据为访问根节点的顺序,前序即为先访问根节点,然后依次访问左右节点;中序为先访问左节点,然后依次访问根、右节点;后序为依次访问左节点、右节点、根节点。 二叉树搜索即为中序方式,左节点<根节点<右节点 深度优先的实现方式依赖于递归

  • 边界(返回)条件:节点为None
  • 然后依次调用函数本身,访问左、右节点,根据前序、中序、后序需要,访问根节点元素
  1. 前序遍历

    res_pre=[]
    # 深度优先就是使用递归方式
    # 深度优先(depth-first search):前序遍历
    # 前序遍历:根节点-左子树-右子树
    # 中序遍历:左子树-根节点-右子树
    # 后续遍历:左子树-右子树-根节点
    def dfs_pre(root:TreeNode):
     # 递归边界(返回条件):节点为None
     if root is None:
         return
     # 访问根节点
     res_pre.append(root.val)
     # 递归处理左子树
     dfs_pre(root=root.left)
     # 递归处理右子树
     dfs_pre(root=root.right)
    
  2. 中序遍历

    res_mid=[]
    # 深度优先遍历:中序方式,左子树-根节点-右子树
    # 如果是一个有序的二叉树,中序遍历出来的元素就是一个有序的列表,左节点< 中节点(根节点) < 右节点
    def dfs_mid(root:TreeNode):
     if root is None:
         return
     dfs_mid(root=root.left)
     res_mid.append(root.val)
     dfs_mid(root=root.right)
    

五、完整代码

from typing import Optional
# deque是collections中的双向链表实现
from collections import deque


class TreeNode:
    def __init__(self, val: int):
        self.val: int = val
        self.left: Optional[TreeNode] = None
        self.right: Optional[TreeNode] = None

# 使用递归方式,将list转换为二叉树,按层的顺序实现转换
# 先判断arr的下标start是否越界,然后再新建节点
def create_btree(arr, start):
    if start < 0 or start >= len(arr) or arr[start] is None:
        return None
    root = TreeNode(arr[start])
    root.left = create_btree(arr, start * 2 + 1)
    root.right = create_btree(arr, start * 2 + 2)

    return root


# 广度优先(breadth-first traversal)方式遍历二叉树
# 以队列方式实现,按层进行遍历
def bfs_travel(root):
    res = []
    queue = deque()
    queue.append(root)
    while queue:
        node: TreeNode = queue.popleft()
        res.append(node.val)
        if node.left is not None:
            queue.append(node.left)
        if node.right is not None:
            queue.append(node.right)
    return res

res_pre=[]
# 深度优先就是使用递归方式
# 深度优先(depth-first search):前序遍历
# 前序遍历:根节点-左子树-右子树
# 中序遍历:左子树-根节点-右子树
# 后续遍历:左子树-右子树-根节点
def dfs_pre(root:TreeNode):
    # 递归边界(返回条件):节点为None
    if root is None:
        return
    # 访问根节点
    res_pre.append(root.val)
    # 递归处理左子树
    dfs_pre(root=root.left)
    # 递归处理右子树
    dfs_pre(root=root.right)

res_mid=[]
# 深度优先遍历:中序方式,左子树-根节点-右子树
# 如果是一个有序的二叉树,中序遍历出来的元素就是一个有序的列表,左节点< 中节点(根节点) < 右节点
def dfs_mid(root:TreeNode):
    if root is None:
        return
    dfs_mid(root=root.left)
    res_mid.append(root.val)
    dfs_mid(root=root.right)

results matching ""

    No results matching ""

    results matching ""

      No results matching ""