python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历

相关推荐
python coding with ChatGPT 打卡第12天| 二叉树:理论基础

文章目录

  • 递归遍历
    • Key Points
    • 相关题目
    • 视频讲解
    • 重点分析
    • 拓展
  • 迭代遍历
    • Key Points
    • 视频讲解
    • 重点分析
      • 前序遍历
      • 后续遍历
      • 中序遍历
    • 拓展:统一的迭代法
  • N叉树的遍历
    • 递归法
    • 迭代法
      • 迭代统一法

递归遍历

Key Points

递归算法三要素:

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。

  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。

  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。

相关题目

144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历

视频讲解

每次写递归都要靠直觉

重点分析

以下以前序遍历为例:

  1. 确定递归函数的参数和返回值:

    传入根节点,返回遍历顺序list

def preorderTraversal(root):
    res = []
  1. 确定终止条件:在递归的过程中,如何算是递归结束了呢,当然是当前遍历的节点是空了,那么本层递归就要结束了,所以如果当前遍历的这个节点是空,就直接return,代码如下:
    if not root:
        return []
  1. 确定单层递归的逻辑:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下:
    res.append(root.val)
    res += preorderTraversal(root.left)
    res += preorderTraversal(root.right)

完整代码:

def preorderTraversal(root):
    res = []
    if not root:
        return res
    res.append(root.val)
    res += preorderTraversal(root.left)
    res += preorderTraversal(root.right)

    return res

def inorderTraversal(root):
    res = []
    if not root:
        return res
    
    res += inorderTraversal(root.left)  # 遍历左子树
    res.append(root.val)               # 访问根节点
    res += inorderTraversal(root.right) # 遍历右子树

    return res

def postorderTraversal(root):
    res = []
    if not root:
        return res
    
    res += postorderTraversal(root.left)  # 遍历左子树
    res += postorderTraversal(root.right) # 遍历右子树
    res.append(root.val)                  # 访问根节点

    return res

拓展

ChatGPT提供的递归代码:

def preorderTraversal(root):
    def dfs(node):
        if not node:
            return
        result.append(node.val)
        dfs(node.left)
        dfs(node.right)

    result = []
    dfs(root)
    return result

python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历_第1张图片

迭代遍历

Key Points

所有递归的逻辑 都可以用栈来模拟

视频讲解

迭代法前序和后序
迭代法中序

重点分析

前序遍历

我们先看一下前序遍历。

前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。

为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。

动画如下:

def preorderTraversal(root):
    if not root:
        return []
    stack_record = [root]
    res = []
    while stack_record:
        node = stack_record.pop()
        if node.right:
            stack_record.append(node.right)
        if node.left:
            stack_record.append(node.left)
        res.append(node.val)
    return res

python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历_第2张图片

后续遍历

再来看后序遍历,先序遍历是中左右,后续遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了,如下图:

在这里插入图片描述

def postorderTraversal(root):
    if not root:
        return []
    stack_record = [root]
    res = []
    while stack_record:
        node = stack_record.pop()
        if node.left:
            stack_record.append(node.left)
        if node.right:
            stack_record.append(node.right)
        res.append(node.val)
    return res[::-1]

中序遍历

为了解释清楚,我说明一下 刚刚在迭代的过程中,其实我们有两个操作:

1. 处理:将元素放进result数组中
2. 访问:遍历节点

分析一下为什么刚刚写的前序遍历的代码,不能和中序遍历通用呢,因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。

那么再看看中序遍历,中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。

那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。

def inorderTraversal(root):
    stack_record = []
    current = root
    res = []

    while current or stack_record:
        while current:
            stack_record.append(current)
            current = current.left

        current = stack_record.pop()
        res.append(current.val)

        current = current.right

    return res

python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历_第3张图片

拓展:统一的迭代法

此时我们用迭代法写出了二叉树的前后中序遍历,大家可以看出前序和中序是完全两种代码风格,并不像递归写法那样代码稍做调整,就可以实现前后中序。

这是因为前序遍历中访问节点(遍历节点)和处理节点(将元素放进result数组中)可以同步处理,但是中序就无法做到同步!

那么问题又来了,难道 二叉树前后中序遍历的迭代法实现,就不能风格统一么(即前序遍历 改变代码顺序就可以实现中序 和 后序)?

def traverse(root, order):
    WHITE, GRAY = 0, 1
    res = []
    stack = [(WHITE, root)]

    while stack:
        color, node = stack.pop()
        if node is None:
            continue

        if color == WHITE:
            if order == "postorder":
                stack.extend([(GRAY, node), (WHITE, node.right), (WHITE, node.left)])
            elif order == "inorder":
                stack.extend([(WHITE, node.right), (GRAY, node), (WHITE, node.left)])
            elif order == "preorder":
                stack.extend([(WHITE, node.right), (WHITE, node.left), (GRAY, node)])
        else:
            res.append(node.val)

    return res

N叉树的遍历

589. N叉树的前序遍历
590. N叉树的后序遍历

前序遍历
前序遍历的顺序是“根-子节点”。首先访问根节点,然后依次递归地访问每个子节点。

后序遍历
后序遍历的顺序是“子节点-根”。首先递归地访问每个子节点,然后访问根节点。

递归法

前序

def preorder(root):
    if not root:
        return []

    res = [root.val]
    for x in root.children:
        res.extend(preorder(x))

    return res

后序

def postorder(root):
    if not root:
        return []

    res = []
    for x in root.children:
        res.extend(postorder(x))
    res.append(root.val)

    return res

迭代法

def preorder(root):
    if not root:
        return []
    stack_record = [root]
    res = []
    while stack_record:
        node = stack_record.pop()
        res.append(node.val)
        if node.children:
            stack_record.extend(node.children[::-1])
    return res
def postorder(root):
    if not root:
        return []

    stack_record = [root]
    res = []
    while stack_record:
        node = stack_record.pop()
        res.append(node.val)
        if node.children:
            stack_record.extend(node.children)
    return res[::-1]

python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历_第4张图片

迭代统一法

def traverse(root, order):
    if not root:
        return []
    WHITE = 0
    GREY = 1
    res = []
    stack_record = [(WHITE, root)]
    while stack_record:
        color, node = stack_record.pop()
        if color == WHITE:
            if order == 'pre':
                for child in node.children[::-1]:
                    stack_record.append((WHITE, child))
                stack_record.append((GREY, node))
            if order == 'post':
                stack_record.append((GREY, node))
                for child in node.children[::-1]:
                    stack_record.append((WHITE, child))
        else:
            res.append(node.val)
    return res

你可能感兴趣的:(Python,Coding,with,ChatGPT,python,开发语言,leetcode,算法,数据结构)