二叉树01 | ● 理论基础 ● *递归遍历 ● *迭代遍历

二叉树

理论基础

文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

  • 二叉树是一种数据结构,常用于递归场景
  • 二叉树:binary tree,每个节点最多有两个子节点(分支),深度为k的二叉树最多有2k-1个节点(k从1开始)
  • 二叉树的常见类型
    • 满二叉树:即节点数达到最大值的二叉树
    • 完全二叉树:除最底层节点外其它层节点均满,最底层节点从左到右连续的二叉树
    • 二叉搜索树:若有左子树,则左子树上所有节点的值比根节点小,若有右子树,则右子树上所有节点的值比根节点大
      • 二叉搜索树
    • 平衡二叉搜索树:左右无子树或左右子树的高度差小于等于1的二叉搜索树
      • 平衡二叉搜索树
  • 二叉树的存储方式
    • 链式存储:通过左右指针存储子节点(相较于顺序存储更易理解,因此更常用)
      • 二叉树链式存储
    • 顺序存储:在内存中连续存储,通常使用数组结构,当前节点i的左子节点为2i+1,右子节点为2i+2
      • 二叉树的顺序存储
  • 二叉树的遍历方式
    • 深度优先遍历:优先往深走,借助栈实现
      • 包括以下三种方式,区别在于把中间节点放在什么顺序,前序就是中左右,中序就是左中右,后序就是左右中
      • 前序遍历(递归法,迭代法)
      • 中序遍历(递归法,迭代法)
      • 后序遍历(递归法,迭代法)
      • 深度优先遍历
    • 广度优先遍历:一层一层地遍历,借助队列实现
      • 层次遍历(迭代法)
  • 二叉树节点结构的定义(这里仅展示链表存储的二叉树结构定义)
class TreeNode:
	def __init__(self, val, left = None, right = None):
		self.val = val
		self.left = left
		self.right = right

*递归遍历(对应力扣144/145/94)(二叉树的深度优先遍历)

题目链接/文章讲解/视频讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html

  • 考点
    • 前序遍历的递归法
    • 中序遍历的递归法
    • 后序遍历的递归法
  • 我的思路
    • 无思路
  • 视频讲解关键点总结
    • 递归代码三要素
      • 参数和返回值是什么
        • 二叉树深度优先遍历的参数为当前节点
        • 返回值为储存结果的列表
      • 递归终止条件是什么
        • 如果当前节点为空,则终止继续搜索,返回一个空列表,之后将开始递归、一层一层将节点储存到列表中
      • 单层递归的逻辑是什么
        • 若为前序遍历(中左右),代码返回值为
          • 当前节点的值(列表形式)
          • +
          • 以当前节点的左子节点为参数调用递归函数的返回值(列表形式)
          • +
          • 以当前节点的右子节点为参数调用递归函数的返回值(列表形式)
        • 若为中序遍历(左中右),代码返回值为
          • 以当前节点的左子节点为参数调用递归函数的返回值(列表形式)
          • +
          • 当前节点的值(列表形式)
          • +
          • 以当前节点的右子节点为参数调用递归函数的返回值(列表形式)
        • 若为后序遍历(左右中),代码返回值为
          • 以当前节点的左子节点为参数调用递归函数的返回值(列表形式)
          • +
          • 以当前节点的右子节点为参数调用递归函数的返回值(列表形式)
          • +
          • 当前节点的值(列表形式)
  • 我的思路的问题
  • 代码书写问题
    • 列表可以直接用+进行拼接,生成一个新列表
  • 可执行代码
# 前序遍历-递归-LC144_二叉树的前序遍历
# 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: TreeNode) -> List[int]:
        if not root:
            return []

        left = self.preorderTraversal(root.left)
        right = self.preorderTraversal(root.right)

        return  [root.val] + left +  right
# 中序遍历-递归-LC94_二叉树的中序遍历
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if root is None:
            return []

        left = self.inorderTraversal(root.left)
        right = self.inorderTraversal(root.right)

        return left + [root.val] + right
# 后序遍历-递归-LC145_二叉树的后序遍历
class Solution:
    def postorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []

        left = self.postorderTraversal(root.left)
        right = self.postorderTraversal(root.right)

        return left + right + [root.val]

*迭代遍历(对应力扣144/145/94)(二叉树的深度优先遍历)

题目链接/文章讲解/视频讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%BF%AD%E4%BB%A3%E9%81%8D%E5%8E%86.html

  • 考点
    • 深度优先遍历的迭代法实现(使用栈)
  • 我的思路
  • 视频讲解关键点总结
    • 前序(中左右)
      • 首先把根节点加入栈
      • 之后开始循环,循环的终止条件为栈是否为空
      • 循环体内,第一步弹栈,并将弹出节点的值加入储存列表
      • 第二步,如果弹出节点的右子节点不为空,将其压栈
      • 第三步,如果弹出节点的左子节点不为空,将其压栈
      • 继续下一轮循环,直到栈空
      • 返回储存列表
    • 后序(左右中)
      • 首先把根节点加入栈
      • 之后开始循环,循环的终止条件为栈是否为空
      • 循环体内,第一步弹栈,并将弹出节点的值加入储存列表
      • 第二步,如果弹出节点的左子节点不为空,将其压栈
      • 第三步,如果弹出节点的右子节点不为空,将其压栈
      • 继续下一轮循环,直到栈空
      • 返回储存列表的倒序列表
    • 中序(左中右)
      • 中序的迭代遍历思路与前后序有所不同
        • 中序的迭代遍历,所查询的元素和所操作的元素不相同
        • 此时,单纯使用一个栈能做但不好做,因此额外引入一个指针来完善思路
      • 初始指针cur指向根节点,代指所查询的节点;初始栈为空,储存待操作的节点;初始储存列表为空,储存结果(节点的值)
      • 进入while循环,循环条件为指针和栈有一个不为空就继续
      • while循环内,大体的思路是先一直向左查询直到最左节点(保存查询过程中的节点),之后逐个向回按照左中右的顺序遍历节点;为实现上述操作,需要进行if else条件判断
        • if里负责处理查询到的情况,若cur指针不为空,此时说明查询到了节点,将该节点压栈,并将cur指针指向cur.left;
        • else里负责处理没查询到的情况,如果所查询的节点为空,此时应该开始弹栈,将栈中保存的上一层节点的值遍历储存到储存列表中,因此令cur=弹栈而出的节点,并将cur.val加入储存列表,之后查询cur是否有右子节点(即cur = cur.right)
      • 循环结束,返回储存列表
  • 我的思路的问题
  • 代码书写问题
  • 可执行代码
# 前序遍历-迭代-LC144_二叉树的前序遍历
class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        # 根结点为空则返回空列表
        if not root:
            return []
        stack = [root]
        result = []
        while stack:
            node = stack.pop()
            # 中结点先处理
            result.append(node.val)
            # 右孩子先入栈
            if node.right:
                stack.append(node.right)
            # 左孩子后入栈
            if node.left:
                stack.append(node.left)
        return result
# 后序遍历-迭代-LC145_二叉树的后序遍历
class Solution:
   def postorderTraversal(self, root: TreeNode) -> List[int]:
       if not root:
           return []
       stack = [root]
       result = []
       while stack:
           node = stack.pop()
           # 中结点先处理
           result.append(node.val)
           # 左孩子先入栈
           if node.left:
               stack.append(node.left)
           # 右孩子后入栈
           if node.right:
               stack.append(node.right)
       # 将最终的数组翻转
       return result[::-1]
# 中序遍历-迭代-LC94_二叉树的中序遍历
class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        stack = []  # 不能提前将root结点加入stack中
        result = []
        cur = root
        while cur or stack:
            # 先迭代访问最底层的左子树结点
            if cur:     
                stack.append(cur)
                cur = cur.left		
            # 到达最左结点后处理栈顶结点    
            else:		
                cur = stack.pop()
                result.append(cur.val)
                # 取栈顶元素右结点
                cur = cur.right	
        return result

统一迭代(未做,主要内容是通过栈来实现统一的迭代遍历形式)

题目链接/文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%BB%9F%E4%B8%80%E8%BF%AD%E4%BB%A3%E6%B3%95.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值