代码随想录算法训练营第十三天|递归遍历 迭代遍历 统一迭代 层序遍历

写在前边的话

        今天开启了二叉树的训练,对于二叉树是不太熟悉了,注定今天是任重道远的一天,加油加油!

ps:由于这部分知识学的不好,所以打算按照先看视频然后写代码的形式学了。

二叉树的理论基础

种类

  • 满二叉树
  • 完全二叉树
  • 二叉搜索树
  • 平衡二叉搜索树

存储方式

  • 链式存储
  • 线性存储(下标i的左右孩子分别为2*i+1, 2*i+2

遍历方式

1. 深度优先遍历

    一般迭代法借助栈实现。

  • 前序遍历(递归、迭代)
  • 中序遍历(递归、迭代)
  • 后续遍历(递归、迭代)

2. 广度优先遍历

     一般使用队列实现。

  • 层序遍历(迭代法)

定义方式

python

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

java

public class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(){};
    TreeNode(int val){
        this.val = val;
    }
    TreeNode(int val,  TreeNode left, TreeNode right){
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

更详细的基础理论:代码随想录二叉树理论基础 

递归遍历

文章讲解

        代码随想录递归遍历文章讲解

视频讲解

        代码随想录递归遍历视频讲解

递归算法三要素

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

        2. 确定终止条件

        3. 确定单层递归的逻辑

        在遍历二叉树的时候,递归函数的参数一般都是一个根结点,一个数组(用于存储遍历的结果),一般没有返回值终止条件是遇到空节点;递归逻辑写在下边三种遍历中。

前序遍历

题目链接

        力扣144.二叉树前序遍历 

 递归逻辑

        先将中节点保存到数组中,然后遍历左子树,最后遍历右子树。

代码编写
python
# 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
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        
        res = []
        def dsf(root):
            if not root:
                return
            res.append(root.val)
            dsf(root.left)
            dsf(root.right)

        dsf(root)
        return res
 java

中序遍历

题目链接

        力扣94. 二叉树中序遍历

递归逻辑

        先将中节点保存到数组中,然后遍历左子树,最后遍历右子树。

代码编写
python
# 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
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res = []

        def dsf(root):
            if not root:
                return
            dsf(root.left)
            res.append(root.val)
            dsf(root.right)
        
        dsf(root)
        return res
java 

后序遍历

题目链接

      力扣145. 二叉树后序遍历  

递归逻辑

        先将中节点保存到数组中,然后遍历左子树,最后遍历右子树。

代码编写
 python
# 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
class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res = []

        def dsf(root):
            if not root:
                return

            dsf(root.left)
            dsf(root.right)
            res.append(root.val)

        dsf(root)
        return res
java

迭代遍历

文章讲解

        代码随想录迭代遍历文章讲解

视频讲解

        代码随想录迭代遍历视频讲解---前序后序

        代码随想录迭代遍历视频讲解---中序

代码编写

        python
        前序遍历

        思路:借助栈,1. 初始化栈为根结点  2. 循环出栈处理节点,处理的是中节点,将val存储到返回列表中,然后依次判断右左子孩子是否为空不为空则依次右左入栈,这样保证出栈存入列表中的顺序是中左右。

# 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
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []

        stack = [root]
        res = []
        while stack:
            tmp = stack.pop()
            res.append(tmp.val)
            if tmp.right:
                stack.append(tmp.right)
            if tmp.left:
                stack.append(tmp.left)
        return res
        后序遍历

        思路:同前序遍历,不同的是,入栈的顺序是左右,这样存入列表中的数据是中右左,再翻转一下数组(可以使用python切片或者使用双指针翻转)就可以得到左右中了,即后序遍历的结果。

# 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
class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []

        stack = [root]
        res = []
        while stack:
            tmp = stack.pop()
            res.append(tmp.val)
            if tmp.left:
                stack.append(tmp.left)
            if tmp.right:
                stack.append(tmp.right)
        return res[::-1]
        中序遍历

        思路:一路向左,判断左孩子是否为空,不为空存储到栈中,直到左孩子为空,然后出栈获取val存入列表中,然后判断当前节点的右孩子是否为空不为空则入栈,然后重复上述操作。

# 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
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []

        stack = []
        res = []
        cur = root
        while cur or stack:
            if cur:
                stack.append(cur)
                cur = cur.left
            else:
                cur = stack.pop()
                res.append(cur.val)
                cur = cur.right
        return res
        java

统一迭代 ---暂时放过啦

层序遍历

文章讲解

        代码随想录层序遍历文章讲解

视频讲解

        代码随想录层序遍历视频讲解

题目链接

        力扣102.二叉树层序遍历

代码编写

python
   用列表实现---迭代法(没有使用队列)
# 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
class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []

        res = []
        cur = [root]
        while cur:
            tmp1 = []
            tmp2 = []
            for i in cur:
                tmp1.append(i.val)
                if i.left:
                    tmp2.append(i.left)
                if i.right:
                    tmp2.append(i.right)
            cur = tmp2
            res.append(tmp1)
        return res
用队列实现--deque
# 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
class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []

        res = []
        queue = collections.deque([root])
        while queue:
            tmp = []
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(tmp)
        return res
用列表模拟队列
# 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
class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []

        res = []
        queue = [root]
        while queue:
            tmp = []
            n = len(queue)
            for i in range(len(queue)):
                node = queue.pop(0)  # 模拟队列需要pop(0)
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(tmp)
        return res

总结:上边的实现方式,时间复杂度都是O(n),空间复杂度都是O(w)(w是二叉树的最大宽度),但是由于deque有比较高效的内存管理机制,在实际应用中可能会有更好的性能表现。 

java
层序遍历拓展题目
107.二叉树的层序遍历||
题目链接 

107. 二叉树的层序遍历 II

题目难度 

        中等

代码编写
        --python

        这道题目就是在层序遍历获取到结果以后,然后进行翻转就行了,我直接用的列表切片翻转,也可以使用双指针进行翻转。 

# 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
class Solution:
    def levelOrderBottom(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []

        res = []
        queue = collections.deque([root])
        while queue:
            tmp = []
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                tmp.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(tmp)
        return res[::-1]
--java 
199. 二叉树的右视图 
题目链接

        力扣199. 二叉树的右视图 

题目难度

        中等

代码编写 
        --python

        使用列表实现,利用层序遍历的原理,列表每次都保存二叉树每层数据然后将最后一个数据保存到返回列表中(即每一层右视图看到的其实是最右的数据)。

# 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
class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        
        res = []
        cur = [root]
        while cur:
            tmp = []
            res.append(cur[-1].val)
            for node in cur:
                if node.left:
                    tmp.append(node.left)
                if node.right:
                    tmp.append(node.right)
            cur = tmp
        return res

使用队列:

# 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
class Solution:
    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []
        
        queue = collections.deque([root])
        res = []
        while queue:
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                if i == n-1:  # 遍历到最后一个数据保存到返回列表中
                    res.append(node.val)
                
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return res

总结:上边的两种实现方式,时间复杂度都是O(n),空间复杂度都是O(w)(w是二叉树的最大宽度),但是由于deque有比较高效的内存管理机制,在实际应用中可能会有更好的性能表现。 

        --java
637.二叉树的层平均值
题目链接

力扣题目链接

题目难度

        简单

代码编写
--python

        使用队列实现,层序遍历,统计每层数据之和以及数据数量,然后求平均值。

# 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
class Solution:
    def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
        if not root:
            return []

        res = []
        queue = collections.deque([root])
        while queue:
            n = len(queue)
            node_sum = 0
            for i in range(n):
                node = queue.popleft()
                node_sum += node.val
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(node_sum/n)
        return res
--java
429.N叉树的层序遍历
题目链接

        力扣题目链接

题目难度

        中等

代码编写
--python
"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def levelOrder(self, root: 'Node') -> List[List[int]]:
        if not root:
            return []

        res = []
        queue = collections.deque([root])
        while queue:
            n = len(queue)
            this_level = []
            for i in range(n):
                node = queue.popleft()
                this_level.append(node.val)
                if node.children:
                    queue.extend(node.children)  # 也可以使用循环添加
            res.append(this_level)
        return res
--java
515.在每个树行中找最大值
题目链接

        力扣题目链接

题目难度

        中等

代码编写
--python

        使用队列层序遍历,查找每树行最大值。

# 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
class Solution:
    def largestValues(self, root: Optional[TreeNode]) -> List[int]:
        if not root:
            return []

        res = []
        queue = collections.deque([root])
        while queue:
            n = len(queue)
            max_num = -float('inf')
            for i in range(n):
                node = queue.popleft()
                if node.val > max_num:
                    max_num = node.val

                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            res.append(max_num)
        return res
--java
116.填充每个节点的下一个右侧节点指针
题目链接

        力扣题目链接

题目难度

        中等

代码编写
--python

        依然使用层序遍历。

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:
            return root

        queue = collections.deque([root])
        while queue:
            n = len(queue)
            if n == 1:  # 如果本层只有一个节点则直接指向None,然后还需要判断下一层
                node = queue.popleft()
                node.next = None
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            else:  # 如果本层大于一个节点,则先将第一个节点指定为pre节点,然后遍历本层节点
                pre_node = queue.popleft()
                for i in range(1, n):
                    node = queue.popleft()
                    pre_node.next = node
                    if i == n-1:
                        node.next = None

                    if pre_node.left:
                        queue.append(pre_node.left)
                    if pre_node.right:
                        queue.append(pre_node.right)
                    if node.left:
                        queue.append(node.left)
                    if node.right:
                        queue.append(node.right)
                    pre_node = node
        return root

        看了卡哥的代码,觉得更加简洁,在遍历每层节点的时候前置设置一个空节点。

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
        if not root:
            return root

        queue = collections.deque([root])
        while queue:
            n = len(queue)
            pre_node = None
            for i in range(n):
                node = queue.popleft()
                if pre_node:
                    pre_node.next = node

                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
                pre_node = node
        return root
--java
117.填充每个节点的下一个右侧节点指针II
题目链接

        力扣题目链接

题目难度

        中等

代码编写
--python

        与上一个题目不同的是,上个题目是完全二叉树,这个题目是二叉树,但本质没什么区别,代码也一样。

"""
# Definition for a Node.
class Node:
    def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return root

        queue = collections.deque([root])
        while queue:
            n = len(queue)
            pre_node = None
            for i in range(n):
                node = queue.popleft()
                if pre_node:
                    pre_node.next = node

                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
                pre_node = node
        return root
--java
104.二叉树的最大深度
题目链接

        力扣题目链接

题目难度

        简单

代码编写
--python

        依然是层序遍历,初始化一个返回值0,然后每遍历一层就加1。

# 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
class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0

        res = 0
        queue = collections.deque([root])
        while queue:
            res += 1
            n = len(queue)
            for i in range(n):
                node = queue.popleft()
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return res
--java
111.二叉树的最小深度
题目链接

        力扣题目链接

题目难度

        简单

代码编写
--python

        还是层序遍历,不同的是求的是最小深度,因此在遍历过程中如果本层有一个节点它的左右子节点都为空,则遍历停止。

# 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
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0

        res = 0
        queue = collections.deque([root])
        while queue:
            n = len(queue)
            res += 1
            flag = 0
            for i in range(n):
                node = queue.popleft()
                if node.left == None and node.right == None:
                    flag = 1
                    break
                
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
                    
            if flag:
                break
        return res

        我是设置了个标志位来查看是否当前层存在左右孩子均为空的节点,看了卡哥的思路是直接return结果,感觉更加简洁。

# 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
class Solution:
    def minDepth(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0

        res = 0
        queue = collections.deque([root])
        while queue:
            n = len(queue)
            res += 1
            for i in range(n):
                node = queue.popleft()
                if node.left == None and node.right == None:
                    return res
                
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return res
--java

今日总结

        今日主要学习了通过递归法迭代法来获取二叉树的前中后序遍历数据以及层序遍历法来获取二叉树数据,总的来说相比之前熟悉了很多,尤其是层序遍历后边十道题的训练,看到层序遍历的题目能够很快的反应过来。由于二叉树不太熟因此只看了python的,而且统一迭代法也暂时放过了,java的还没来得及看,后边有时间再补上吧。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值