LeetCode---二叉树

这篇博客详细介绍了二叉树的各种类型,包括满二叉树、完全二叉树和二叉搜索树等,并探讨了如何使用广度优先和深度优先遍历策略解决LeetCode上的相关问题,如N叉树的前序遍历、二叉树的层序遍历等。文章还涵盖了平衡二叉树、二叉树的存储方式以及如何在二叉搜索树中进行搜索和插入操作。
摘要由CSDN通过智能技术生成

二叉树

二叉树种类

二叉树有两种主要的形式:满二叉树完全二叉树

满二叉树

满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
在这里插入图片描述
这棵二叉树为满二叉树,也可以说深度为k=4,有2^k-1=15个节点的二叉树。

完全二叉树

**完全二叉树:**在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h -1个节点。
在这里插入图片描述

二叉搜索树

二叉搜索树是有数值的了,二叉搜索树是一个有序树。

  1. 若它的左子树不空,则左子树上所有结点的值均小(大)于它的根结点的值
  2. 若它的右子树不空,则右子树上所有结点的值均大(小)于它的根结点的值
  3. 它的左、右子树也分别为二叉排序树

在这里插入图片描述

平衡二叉搜索树

平衡二叉搜索树:AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
在这里插入图片描述

二叉树存储

二叉树可以链式存储(类似指针的方式),也可以顺序存储(列表)。

链式存储

在这里插入图片描述

顺序存储

在这里插入图片描述

二叉树遍历

二叉树主要有两种遍历方式:

  1. 深度优先遍历:先往深走,遇到叶子节点再往回走。
    前序遍历(递归法,迭代法)
    中序遍历(递归法,迭代法)
    后序遍历(递归法,迭代法)

  2. 广度优先遍历:一层一层的去遍历。
    层次遍历(迭代法)

深度优先遍历

在这里插入图片描述

from collections import deque

# 节点类
class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left_child = None
        self.right_child = None

# 构建完全二叉树
class BinaryTree(object):
    def __init__(self, val=None):
        self.root = TreeNode(val)

    def add(self, item):
        """
        二叉树添加一个节点,每一层从左到右遍历获取可以添加节点的位置,保证完全二叉树的性质
        :param item: 节点数据
        :return:
        """
        if not self.root:
            self.root = TreeNode(item)
            return

        # 采用广度优先一层一层遍历(从左到右)找到空置的节点添加
        dq = deque([self.root])
        while dq:
            cur = dq.popleft()

            if not cur.left_child:
                cur.left_child = TreeNode(item)
                return

            if not cur.right_child:
                cur.right_child = TreeNode(item)
                return

            if cur.left_child:
                dq.append(cur.left_child)
            if cur.right_child:
                dq.append(cur.right_child)

    def _get_parent(self, item):
        """
        返回 值为item的节点的父节点
        :param item:
        :return:
        """

        if self.root.val == item:
            return None, None

        # 采用广度优先一层一层遍历(从左到右)找到空置的节点添加
        dq = deque([self.root])
        while dq:
            cur = dq.popleft()

            if cur.left_child and cur.left_child.val == item:
                return "left", cur

            if cur.right_child and cur.right_child.val == item:
                return "right", cur

            if cur.left_child:
                dq.append(cur.left_child)
            if cur.right_child:
                dq.append(cur.right_child)

        return None, None

    def delete(self, item):
        """
        删除值为item的节点
        :param item: 待删除的节点值
        :return:
        """
        if not self.root:
            return False

        site, parent = self._get_parent(item)

        if parent:
            cur = parent.left_child if site == "left" else parent.right_child

            # 1. cur节点没有子节点,则直接将父节点的子节点置为None
            if not cur.left_child and not cur.right_child:
                if site == "left":
                    parent.left_child = None
                else:
                    parent.right_child = None
                return True

            # 2. cur节点有一个子节点,则将子节点和父节点直接链接
            elif (not cur.left_child and cur.right_child) or \
                    (cur.left_child and not cur.right_child):
                cur_child = cur.left_child if cur.left_child else cur.right_child
                if site == "left":
                    parent.left_child = cur_child
                else:
                    parent.right_child = cur_child

            # 3. cur存在两个子节点,找到cur的左右子树中最左边的叶子节点替换cur节点,保证完全二叉树性质
            else:

                dq = deque([cur])
                replace_par_node = ("", None)
                while dq:
                    node = dq.popleft()
                    # 左节点存在右节点不存在,则左节点即为最下面一层最靠右的叶子节点
                    if node.left_child and not node.right_child:
                        replace_par_node = ("left", node)
                        break

                    # 记录最后一个左右子节点都存在的情况,如果是最后一层子节点都是满的,
                    # 那么要替换的就是最右边的节点
                    if node.left_child and node.right_child:
                        replace_par_node = ("right", node)

                    if node.left_child:
                        dq.append(node.left_child)
                    if node.right_child:
                        dq.append(node.right_child)

                if replace_par_node[0] == "left":
                    replace_node = replace_par_node[1].left_child
                    replace_par_node[1].left_child = None
                else:
                    replace_node = replace_par_node[1].right_child
                    replace_par_node[1].right_child = None

                cur.val = replace_node.val
                return True

        else:
            return False

    # 前序遍历---递归
    def recursion_preorder(self):
        result = []
        self._preorder(self.root, result)
        return result

    def _preorder(self, root, result):
        if not root:
            return []
        result.append(root.val)
        self._preorder(root.left_child, result)
        self._preorder(root.right_child, result)

    # 前序遍历
    def preorder(self):
        stack = deque()
        cur = self.root
        result = []
        while cur or stack:
        	# 前序遍历:中左右,先从根节点一直向左遍历,遍历过程中每个节点都加入result,
        	# 直到叶子结点,再获取每个节点的右子节点。
            while cur:
                stack.append(cur)
                result.append(cur.val)
                cur = cur.left

            cur = stack.pop()
            cur = cur.right

        return result

    # 中序遍历---递归
    def recursion_inorder(self):
        result = []
        self._inorder(self.root, result)
        return result

    def _inorder(self, root, result):
        if not root:
            return []

        self._inorder(root.left_child, result)
        result.append(root.val)
        self._inorder(root.right_child, result)

    # 中序遍历
    def inorder(self):
        result = []

        stack = deque()
        cur = self.root
        while cur or stack:
            # 中序遍历: 左中右,从根节点开始向左遍历,直到叶子节点,其中每个节点都入栈
            # 到达叶子节点后,从栈中取出节点加入result
            while cur:
                stack.append(cur)
                cur = cur.left

            cur = stack.pop()
            result.append(cur.val)
            cur = cur.right

        return result

    # 后序遍历---递归
    def recursion_postorder(self):
        result = []
        self._postorder(self.root, result)
        return result

    def _postorder(self, root, result):
        if not root:
            return []

        self._postorder(root.left_child, result)
        self._postorder(root.right_child, result)
        result.append(root.val)

    # 后序遍历
    def postorder(self):
        stack = deque()
        cur = self.root
        result = []
        # 后序遍历: 左右中
        # 前序遍历: 中左右,所以只需要得到中右左,再反转就得了左右中
        while cur or stack:
            while cur:
                stack.append(cur)
                result.append(cur.val)
                cur = cur.right

            cur = stack.pop()
            cur = cur.left

        result.reverse()
        return result


if __name__ == '__main__':
    b = BinaryTree(13)
    b.add(12)
    b.add(18)
    b.add(7)
    b.add(11)
    b.add(14)
    b.add(17)
    b.add(3)
    b.add(8)
    b.add(9)
    b.add(10)
    
    b.delete(10)
    b.delete(9)
    b.delete(11)

    print(b.preorder())
    print(b.recursion_preorder())
    
    print(b.inorder())
    print(b.recursion_inorder())
    
    print(b.postorder())
    print(b.recursion_postorder())

LeetCode

589. N 叉树的前序遍历

题目链接

解一:递归

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        result = []
        self._preorder(root, result)
        return result

    def _preorder(self, root, result):
        if not root:
            return []
        result.append(root.val)
        for child in root.children:
            self._preorder(child, result)

解二:迭代

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        result = []
        stack = deque([root])
        while stack:
            cur = stack.pop()
            result.append(cur.val)
            # 倒序遍历每个子节点
            for i in range(len(cur.children)-1, -1, -1):
                stack.append(cur.children[i])
        return result

590. N 叉树的后序遍历

题目链接

解一:递归

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def postorder(self, root: 'Node') -> List[int]:
        result = []
        self._postorder(root, result)
        return result

    def _postorder(self, root, result):
        if not root:
            return []
        for child in root.children:
            self._postorder(child, result)
        result.append(root.val)

解二:迭代

"""
# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution:
    def postorder(self, root: 'Node') -> List[int]:
        if not root:
            return root
        result = []
        stack = deque([root])
        # 先序遍历是"中左右",后续遍历是"左中右";
    	# 则调整代码左右顺序,然后将结果result反转就得到左右中。
        while stack:
            cur = stack.pop()
            result.append(cur.val)
            for child in cur.children:
                stack.append(child)

        result.reverse()
        return result

102. 二叉树的层序遍历

题目链接

解:广度优先

# 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: TreeNode) -> List[List[int]]:
        if not root:
            return []

        result = []
        # 层序遍历,采用广度优先
        dq = deque()
        # 第二个参数标记是否同一层
        dq.append((root, 0))
        temp = []

        while dq:
            cur, flag = dq.popleft()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值