python实现--二叉搜索树

什么是二叉搜索树

二叉搜索树(Binary Search Tree,BST)是一种特殊类型的二叉树,它具有以下性质:
每个节点最多有两个子节点,分别称为左子节点和右子节点。
对于任意节点,其左子树中的所有节点的值都小于该节点的值。
对于任意节点,其右子树中的所有节点的值都大于该节点的值。
对于任意节点,其左子树和右子树也分别是二叉搜索树。
在这里插入图片描述

二叉搜索树特点

有序性:二叉搜索树中的节点按照一定的顺序排列,左子树的值小于根节点的值,右子树的值大于根节点的值。这使得在树中进行搜索、插入或删除操作时具有高效性能。
快速查找:由于有序性,可以利用二叉搜索树进行快速查找操作。通过比较目标值与当前节点的值,可以根据大小关系递归地在左子树或右子树中继续查找目标值。
插入和删除操作:由于二叉搜索树的有序性,插入和删除操作可以保持树的有序性。插入操作按照节点值的大小关系找到合适的位置插入新节点。删除操作需要维护树的有序性,并根据节点的情况进行相应的调整。

二叉搜索树的常见操作

查找(Search)

在二叉搜索树中查找给定值。从根节点开始,比较目标值与当前节点的值,根据大小关系递归地在左子树或右子树中查找,直到找到目标值或遍历到叶子节点。
以下实例在二分搜索树中寻找 43 元素
在这里插入图片描述

(1) 元素 43 比根节点 42 大,需要在右子节点继续比较。

在这里插入图片描述

(2) 元素 43 比 59 小,需要在左子节点继续比较。
在这里插入图片描述

(3) 元素 43 比 51 小,需要在左子节点继续比较。
在这里插入图片描述
(4) 查找 51 的左子节点 43,正好和相等,结束。

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

def search(root, target):
    # 如果当前节点为None或者当前节点的值等于目标值,则返回当前节点
    if root is None or root.val == target:
        return root
    
    # 如果目标值小于当前节点的值,则在左子树中查找
    if target < root.val:
        return search(root.left, target)
    # 如果目标值大于当前节点的值,则在右子树中查找
    else:
        return search(root.right, target)

# 测试
# 构建二叉搜索树
root = TreeNode(5)
root.left = TreeNode(3)
root.right = TreeNode(7)
root.left.left = TreeNode(2)
root.left.right = TreeNode(4)
root.right.left = TreeNode(6)
root.right.right = TreeNode(8)

# 查找目标值为6的节点
result = search(root, 6)
if result:
    print("查找成功,找到目标值为6的节点")
else:
    print("查找失败,未找到目标值为6的节点")

插入(Insertion)

向二叉搜索树中插入新节点。按照节点值的大小关系,递归地在左子树或右子树中找到合适的位置插入新节点。
以下实例向如下二分搜索树中插入元素 61 的步骤:
在这里插入图片描述

(1)需要插入的元素 61 比 42 大,比较 42 的右子树根节点。
在这里插入图片描述

(2)61 比 59 大,所以需要把 61 移动到 59 右子树相应位置,而此时为空,直接插入作为 59 的右子节点。

在这里插入图片描述

插入操作也是一个递归过程,分三种情况,等于、大于、小于。

如果树为空,则将新节点作为根节点插入。
如果树不为空,则从根节点开始遍历:
如果新节点的值小于当前节点的值,并且当前节点的左子节点为空,则将新节点插入为当前节点的左子节点。
如果新节点的值大于当前节点的值,并且当前节点的右子节点为空,则将新节点插入为当前节点的右子节点。
如果新节点的值小于当前节点的值,并且当前节点的左子节点不为空,则将当前节点移动到其左子节点,并继续向下遍历。
如果新节点的值大于当前节点的值,并且当前节点的右子节点不为空,则将当前节点移动到其右子节点,并继续向下遍历。

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

def insert(root, val):
    # 如果树为空,则新节点作为根节点
    if not root:
        return TreeNode(val)
    
    # 如果新节点的值小于当前节点的值,则插入左子树
    if val < root.val:
        root.left = insert(root.left, val)
    # 如果新节点的值大于等于当前节点的值,则插入右子树
    else:
        root.right = insert(root.right, val)
    
    return root

# 测试
def inorder_traversal(root):
    if root:
        inorder_traversal(root.left)
        print(root.val, end=' ')
        inorder_traversal(root.right)

root = None
keys = [50, 30, 20, 40, 70, 60, 80]

for key in keys:
    root = insert(root, key)

print("插入后的中序遍历结果:")
inorder_traversal(root)

删除(Deletion)

从二叉搜索树中删除节点。删除节点时,需要考虑节点的子树情况和维护树的有序性。常见的情况包括删除叶子节点、删除只有一个子节点的节点以及删除有两个子节点的节点。
1、删除只有左孩子的节点,如下图节点 58

在这里插入图片描述

删除掉元素 58,让左子树直接代替 58 的位置,整个二分搜索树的性质不变。
在这里插入图片描述
2、删除只有右孩子的节点,如下图节点 58

在这里插入图片描述

删除掉元素 58,让右子树直接代替 58 的位置,整个二分搜索树的性质不变。
在这里插入图片描述

3、删除左右都有孩子的节点,如下图节点 58
在这里插入图片描述

(1)找到右子树中的最小值,为节点 59
在这里插入图片描述在这里插入图片描述

(2)节点 59 代替待删除节点 58
在这里插入图片描述

搜索要删除的节点:首先,我们需要在二叉搜索树中搜索要删除的节点。如果节点存在,我们就可以执行删除操作;如果节点不存在,则无需进行任何操作。

确定删除节点的类型:被删除的节点可能是叶子节点(没有子节点)、只有一个子节点的节点、或者有两个子节点的节点。

删除叶子节点:如果要删除的节点是叶子节点,只需将其父节点指向它的指针置为 None。

删除只有一个子节点的节点:如果要删除的节点只有一个子节点,我们可以将其父节点指向它的指针指向其唯一的子节点。

删除有两个子节点的节点:如果要删除的节点有两个子节点,我们需要找到它的后继节点(或者前驱节点),将其值替换到要删除的节点上,然后递归删除后继节点。

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

def delete_node(root, key):
    if root is None:
        return root

    if key < root.val:
        root.left = delete_node(root.left, key)
    elif key > root.val:
        root.right = delete_node(root.right, key)
    else:
        if root.left is None:
            temp = root.right
            root = None
            return temp
        elif root.right is None:
            temp = root.left
            root = None
            return temp

        temp = find_min(root.right)
        root.val = temp.val
        root.right = delete_node(root.right, temp.val)

    return root

def find_min(node):
    current = node
    while current.left is not None:
        current = current.left
    return current

最小值和最大值(Minimum and Maximum)

最小值在树的最左边叶子节点上,最大值在树的最右边叶子节点上。

遍历(Traversal)

按照一定的顺序遍历二叉搜索树的所有节点。常见的遍历方式包括深度优先遍历和广度优先遍历。

前序遍历:

在这里插入图片描述

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

def preorder_traversal(root):
    if root is None:
        return
    print(root.value, end=" ")  # 访问根节点
    preorder_traversal(root.left)  # 递归前序遍历左子树
    preorder_traversal(root.right)  # 递归前序遍历右子树

# 测试
# 构造一个二叉搜索树
root = TreeNode(5)
root.left = TreeNode(3)
root.right = TreeNode(8)
root.left.left = TreeNode(2)
root.left.right = TreeNode(4)
root.right.left = TreeNode(7)
root.right.right = TreeNode(9)

print("前序遍历结果:", end=" ")
preorder_traversal(root)

中序遍历:

在这里插入图片描述

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

def inorder_traversal(root):
    if root is None:
        return []
    result = []
    stack = []
    current = root
    while current or stack:
        while current:
            stack.append(current)
            current = current.left
        current = stack.pop()
        result.append(current.value)
        current = current.right
    return result

# 测试
root = TreeNode(5)
root.left = TreeNode(3)
root.right = TreeNode(8)
root.left.left = TreeNode(2)
root.left.right = TreeNode(4)
root.right.left = TreeNode(6)
root.right.right = TreeNode(9)

print("中序遍历结果:", inorder_traversal(root))  # 输出:[2, 3, 4, 5, 6, 8, 9]

后序遍历:

在这里插入图片描述

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

def postorder_traversal(root):
    if root:
        postorder_traversal(root.left)
        postorder_traversal(root.right)
        print(root.val, end=" ")

层序遍历:

通过引入一个队列来支撑层序遍历:
如果根节点为空,无可遍历;
如果根节点不为空:
先将根节点入队;
只要队列不为空:
出队队首节点,并遍历;
如果队首节点有左孩子,将左孩子入队;
如果队首节点有右孩子,将右孩子入队;

(1)先取出根节点放入队列
在这里插入图片描述

(2)取出 29,左右孩子节点入队

在这里插入图片描述

(3)队首 17 出队,孩子节点 14、23 入队。

在这里插入图片描述

(4)31 出队,孩子节点 30 和 43 入队

在这里插入图片描述

(5)最后全部出队
在这里插入图片描述

from collections import deque

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

def level_order_traversal(root):
    if not root:
        return []

    result = []
    queue = deque([root])

    while queue:
        level_size = len(queue)
        current_level = []

        for _ in range(level_size):
            node = queue.popleft()
            current_level.append(node.val)

            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        result.append(current_level)

    return result

# 测试
# 构建一个二叉搜索树
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)

# 执行层序遍历
print("层序遍历结果:", level_order_traversal(root))

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值