二叉树的三种深度优先遍历【递归法】

一、踩坑历程

二叉树的三种深度优先遍历(前序 + 中序 + 后序)的递归法相对于迭代法来说要更好理解和记忆一些,迭代法在LeetCode刷题时遇见过,所以想着在Pycharm上实现一下递归,然而事情好像并不像我想象的那么简单:
(1)最开始实现时,直接将 root 写成数组输进去了,结果直接报错( list 类型没有 val 属性),后来问了大佬才知道节点要用add一个个添加,其实跟链表的实现一样,只是一下子没反应过来。
(2)看视频老师讲解时,根节点值是直接用 print 打印出来的print(node.val, end = ' '),考虑到 LeetCode 里没法直接用 print,故而想到用列表 result 去保存遍历到的节点值,然后好像又踩坑了……

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
        
class BinaryTree:
    def __init__(self, root=None):
        self.root = root
        self.result = []

    def add(self, value):
        """添加节点"""
        node = TreeNode(value)
        if self.root == None:
            # 如果树是空的,则把根节点指向新建节点,并且为其赋值
            self.root = node
        else:
            ##如果树不是空的,层次遍历
            # 将当前节点cur赋值为根节点root;
            # 查找cur的左子树,若为空,则赋值结束;
            # 查找cur的右子树,若为空,则赋值结束;
            # 都不为空递归上述过程,直到cur为空
            queue = []
            queue.append(self.root)
            while queue:
                cur = queue.pop(0)
                if cur.left == None:
                    cur.left = node
                    return
                elif cur.right == None:
                    cur.right = node
                    return
                else:
                    queue.append(cur.left)
                    queue.append(cur.right)

    def preorder(self, root):
        if not root:
            return
        self.result.append(root.val)
        self.inorder(root.left)
        self.inorder(root.right)
        return self.result

    def inorder(self, root):
        if not root:
            return
        self.inorder(root.left)
        self.result.append(root.val)
        self.inorder(root.right)
        return self.result

    def postorder(self, root):
        if not root:
            return
        self.inorder(root.left)
        self.inorder(root.right)
        self.result.append(root.val)
        return self.result

root = TreeNode(2)
tree = BinaryTree(root)
tree.add(1)
tree.add(8)
tree.add(6)
tree.add(4)
tree.add(3)
tree.add(5)

print(tree.preorder(root))
print(tree.inorder(root))
print(tree.postorder(root))

输出如下:

[2, 6, 1, 4, 3, 8, 5]
[2, 6, 1, 4, 3, 8, 5, 6, 1, 4, 2, 3, 8, 5]
[2, 6, 1, 4, 3, 8, 5, 6, 1, 4, 2, 3, 8, 5, 6, 1, 4, 3, 8, 5, 2]

于是问题来了,打印了三次,数组的长度越来越大,难道树会自己长大吗?并不是,仔细观察发现每次打印的结果都要保留上一次的结果,然后接着后面输出,为什么会这样呢?———— 因为 self.result 定义在初始化函数里,相当于一个全局变量,前序遍历函数使用了之后 self.result 的值就改变了,不再为空,而在调用中序遍历函数时没有清空 self.result,就会沿用它的值,所以才会出现数组长度越来越大的现象。

二、更改后的代码

将 result 传入前中后序遍历三个函数里,并在每次调用之前清空 result, 就能得到正确的结果。

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class BinaryTree:
    def __init__(self, root=None):
        self.root = root

    def add(self, value):
        """添加节点"""
        node = TreeNode(value)
        if self.root == None:
            # 如果树是空的,则把根节点指向新建节点,并且为其赋值
            self.root = node
        else:
            ##如果树不是空的,层次遍历
            # 将当前节点cur赋值为根节点root;
            # 查找cur的左子树,若为空,则赋值结束;
            # 查找cur的右子树,若为空,则赋值结束;
            # 都不为空递归上述过程,直到cur为空
            queue = []
            queue.append(self.root)
            while queue:
                cur = queue.pop(0)
                if cur.left == None:
                    cur.left = node
                    return
                elif cur.right == None:
                    cur.right = node
                    return
                else:
                    queue.append(cur.left)
                    queue.append(cur.right)

    def preorder(self, root, result):
        if not root:
            return
        result.append(root.val)
        self.inorder(root.left, result)
        self.inorder(root.right, result)
        return result

    def inorder(self, root, result):
        if not root:
            return
        self.inorder(root.left, result)
        result.append(root.val)
        self.inorder(root.right, result)
        return result

    def postorder(self, root, result):
        if not root:
            return
        self.inorder(root.left, result)
        self.inorder(root.right, result)
        result.append(root.val)
        return result

root = TreeNode(2)
tree = BinaryTree(root)
tree.add(1)
tree.add(8)
tree.add(6)
tree.add(4)
tree.add(3)
tree.add(5)

result = []
print(tree.preorder(root, result))
result = []
print(tree.inorder(root, result))
result = []
print(tree.postorder(root, result))

输出如下:

[2, 6, 1, 4, 3, 8, 5]
[6, 1, 4, 2, 3, 8, 5]
[6, 1, 4, 3, 8, 5, 2]

或者也可以不写返回值,像下面这题一样。

三、【LeetCode 1305】两颗二叉搜索树中的所有元素

1. 题目描述

给你 root1 和 root2 这两棵二叉搜索树。

请你返回一个列表,其中包含两棵树中的所有整数并按升序排序。.

示例 1:
在这里插入图片描述

输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]

示例 2:

输入:root1 = [0,-10,10], root2 = [5,1,7,0,2]
输出:[-10,0,0,1,2,5,7,10]

示例 3:

输入:root1 = [], root2 = [5,1,7,0,2]
输出:[0,1,2,5,7]

示例 4:

输入:root1 = [0,-10,10], root2 = []
输出:[-10,0,10]

示例 5:

在这里插入图片描述

输入:root1 = [1,null,8], root2 = [8,1]
输出:[1,1,8,8]

提示:

每棵树最多有 5000 个节点。
每个节点的值在 [-10^5, 10^5] 之间。

2. 解题思路

核心思想: 利用二叉搜索树的中序遍历是升序序列
最好理解的思想就是先得到两棵树的中序遍历序列,然后再将这两个中序序列合并成一个数组,这时的思想就类似于【合并两个有序的链表】和【寻找两个有序数组的中位数】:
(1)初始化一个空数组 ans,用来保存合并后的序列;初始化两个指针 left1 和 left2,分别遍历两个中序序列
(2)将 res1[left1] 和 res2[left2] 比较,若res1[left1] <= res2[left2],则将 res1[left1] 添加到 ans 中,并将 left1 右移;若res1[left1] > res2[left2],则将 res2[left2] 添加到 ans 中,并将 left2 右移。
(3)若 res1 先为空,则直接将 res2 剩下的部分加到 ans 上;反之若 res2 先为空,同理。
(4)最后返回 ans 即可。

需要注意的是这个地方:

res1 = []
self.inorder(root1, res1)
res2 = []
self.inorder(root2, res2)

在每次调用中序遍历函数前,需要将 result 清空,也就是传入一个空数组,否则就会出现多出一部分值的情况。

3. 代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def getAllElements(self, root1: TreeNode, root2: TreeNode) -> List[int]:
        # result = []
        if not root1 and not root2:
            return []
        res1 = []
        self.inorder(root1, res1)
        res2 = []
        self.inorder(root2, res2)
        if root1 and not root2:
            return res1
        if not root1 and root2:
            return res2             
        left1, left2 = 0, 0
        ans = []
        n1, n2 = len(res1), len(res2)
        while left1 < n1 and left2 < n2:
            if res1[left1] <= res2[left2]:
                ans.append(res1[left1])
                left1 += 1
            else:
                ans.append(res2[left2])
                left2 += 1
        if left1 == n1:
            ans += res2[left2:]
        elif left2 == n2:
            ans += res1[left1:]
        return ans 

    def inorder(self, root, result):
        if not root:
            return []  
        if root.left: 
            self.inorder(root.left, result)
        result.append(root.val)
        if root.right:
            self.inorder(root.right, result)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值