【Leetcode】代码随想录Day14|二叉树1.0

二叉树基础

  1. 种类

    • 满二叉树
      如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。有2^k -1个节点。

    • 完全二叉树
      完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层(h从1开始),则该层包含 1~ 2^(h-1) 个节点。
      完全二叉树
      图源:代码随想录

    • 二叉搜索树
      前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树。

      • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
      • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
      • 它的左、右子树也分别为二叉排序树
    • 平衡二叉搜索树
      又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

    C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn,注意我这里没有说unordered_map、unordered_set,unordered_map、unordered_set底层实现是哈希表。

  2. 二叉树的存储方式

    • 链式储存:指针
      通过指针把分布在各个地址的节点串联一起
    • 顺序储存:数组
      元素在内存是连续分布的。如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
  3. 二叉树的遍历方式

    • 深度优先:先往深走,遇到叶子结点再往回走
      • 前序遍历 (preorder traversal):递归,迭代
        中左右:访问根结点的操作发生在遍历其左右子树之前
      • 中序遍历 (inorder traversal):递归,迭代
        左中右:访问根结点的操作发生在遍历其左右子树之中(间)
      • 后序遍历 (postorder traversal):递归,迭代
        左右中:访问根结点的操作发生在遍历其左右子树之后
      • 深度优先一般使用递归来遍历,栈就是一种递归的实现结构,可以借助栈使用递归来深度遍历
        在这里插入图片描述
    • 广度优先:一层一层遍历
      - 层次遍历:迭代
      - 广度优先一般使用队列,先进先出的结构可以一层一层来遍历。
  4. 链式储存节点定义

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

【除了递归,我们还可以用迭代法。递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。所以用栈也可以是实现二叉树的前后中序遍历了。】

144 二叉树的前序遍历

递归法

class Solution(object):
    def preorderTraversal(self, root):
        if not root:
            return []

        root_val = [root.val]
        left = self.preorderTraversal(root.left)
        right = self.preorderTraversal(root.right)

        return root_val + left + right

迭代法

  • 前序是中左右,现将根节点(中)放入,接下来以右左的顺序放入栈,出来为中左右
  • 因为要访问的元素和要处理的元素顺序是一致的,都是中间节点,代码相对简洁
class Solution(object):
    def preorderTraversal(self, root):

        if not root:
            return []

        stack = [root]
        res = []

        while stack:
            node = stack.pop()
            res.append(node.val)

            if node.right:
                stack.append(node.right)

            if node.left:
                stack.append(node.left)

        return res

94 二叉树的中序遍历

class Solution(object):
    def inorderTraversal(self, root):
        if not root:
            return []

        root_val = [root.val]
        left = self.inorderTraversal(root.left)
        right = self.inorderTraversal(root.right)

        return left + root_val + right

迭代法

  • 中序是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
  • 那么在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
class Solution(object):
    def inorderTraversal(self, root):
        if not root:
            return []

        stack = []
        res = []
        cur = root

        while cur or stack:
            if cur:
                # 遍历,一直向左,到达左面的最底部
                stack.append(cur)
                cur = cur.left
            else:
                # 处理
                # 这里是到达树或子树最左边的底部后,cur == None
                # 这个时候要往最近的(上一级的)root和它的右边找了
                cur = stack.pop() # 指向上一级root (中)
                res.append(cur.val)
                cur = cur.right # (右)

        return res

145 二叉树的后序遍历

class Solution(object):
    def postorderTraversal(self, root):
        if not root:
            return []

        root_val = [root.val]
        left = self.postorderTraversal(root.left)
        right = self.postorderTraversal(root.right)

        return left + right + root_val

迭代法

  • 后序遍历是左右中。我们可以调整前序遍历的逻辑,前序是中左右,调整左右顺序就是中右左,将最后的结果反转,即可得到左中右。
class Solution(object):
    def postorderTraversal(self, root):
        if not root:
            return []

        stack = [root]
        res = []

        while stack:
            node = stack.pop()
            res.append(node.val)

            if node.left:
                stack.append(node.left)

            if node.right:
                stack.append(node.right)

        return res[::-1]
  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值