Python实现二叉排序树与平衡二叉树的示例代码

yizhihongxing

现在让我们来详细讲解如何使用Python实现二叉排序树与平衡二叉树。

二叉排序树

二叉排序树(BST)是一种特殊的二叉树,它的每个节点最多有两个子节点,左子节点的值比父节点小,右子节点的值比父节点大。因此,二叉排序树可以很好地存储和快速查找有序数据。

实现过程

  1. 定义节点类

我们首先需要定义二叉排序树的节点类,它至少需要包含以下属性:

  • value:存储节点的值
  • left:存储左子节点的引用
  • right:存储右子节点的引用
class TreeNode:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None
  1. 插入节点

对于一个没有任何节点的空树,我们将插入第一个节点作为根节点,否则我们需要通过递归查找合适的插入位置。

def insert_node(root, value):
    if root is None:
        root = TreeNode(value)
    elif root.value > value:
        root.left = insert_node(root.left, value)
    elif root.value < value:
        root.right = insert_node(root.right, value)
    return root
  1. 删除节点

删除节点是二叉排序树中比较常见的操作,我们需要实现以下两个删除节点的函数:

  • 查找待删除节点
  • 删除节点
def find_node(root, value):
    if root is None or root.value == value:
        return root
    elif root.value > value:
        return find_node(root.left, value)
    else:
        return find_node(root.right, value)


def delete_node(root, value):
    if root is None:
        return root
    if root.value == value:
        if root.left is None:
            return root.right
        elif root.right is None:
            return root.left
        else:
            min_node = find_min_node(root.right)
            root.value = min_node.value
            root.right = delete_node(root.right, min_node.value)
    elif root.value > value:
        root.left = delete_node(root.left, value)
    else:
        root.right = delete_node(root.right, value)
    return root


def find_min_node(root):
    while root.left is not None:
        root = root.left
    return root

示例

现在让我们通过一个示例来理解二叉排序树的使用。

我们现在有一组数据[5, 6, 2, 8, 3, 1, 4],我们可以通过以下代码将它们插入二叉排序树中并进行中序遍历来验证插入操作是否正确。

def inorder_traverse(root, values):
    if root is not None: 
        inorder_traverse(root.left, values) 
        values.append(root.value) 
        inorder_traverse(root.right, values) 
    return values


if __name__ == '__main__':
    nums = [5, 6, 2, 8, 3, 1, 4]
    root = None
    for num in nums:
        root = insert_node(root, num)
    res = inorder_traverse(root, [])
    print(res)   # [1, 2, 3, 4, 5, 6, 8]
    root = delete_node(root, 5)
    res = inorder_traverse(root, [])
    print(res)   # [1, 2, 3, 4, 6, 8]

注意我们还演示了删除节点的操作。

平衡二叉树

平衡二叉树(AVL Tree)是一种二叉排序树,但相比于二叉排序树,它的左右子树的高度差不能超过1,这样可以确保树的高度平衡,插入和查找操作的时间复杂度可以保证在O(logn)。

实现过程

平衡二叉树实现起来比较复杂,我们需要先了解如何计算平衡因子,并实现旋转操作。

  1. 计算平衡因子

平衡因子:左子树的高度减去右子树的高度。

我们可以通过以下代码计算节点的平衡因子:

def get_height(root):
    if root is None:
        return 0
    return max(get_height(root.left), get_height(root.right)) + 1


def get_balance_factor(root):
    if root is None:
        return 0
    return get_height(root.left) - get_height(root.right)
  1. 实现旋转操作

旋转操作可以分为左旋和右旋两种,它们可以帮助我们调整平衡二叉树,使得节点的平衡因子恢复为-1、0或1。

def left_rotate(root):
    right_node = root.right
    root.right = right_node.left
    right_node.left = root
    return right_node


def right_rotate(root):
    left_node = root.left
    root.left = left_node.right
    left_node.right = root
    return left_node
  1. 插入节点

对于一个没有任何节点的空树,我们将插入第一个节点作为根节点,否则我们需要通过递归查找合适的插入位置。

插入节点之后,我们需要检查是否需要通过旋转操作来调整平衡。

def insert_node(root, value):
    if root is None:
        root = TreeNode(value)
    elif root.value > value:
        root.left = insert_node(root.left, value)
    elif root.value < value:
        root.right = insert_node(root.right, value)
    # 更新平衡因子
    balance_factor = get_balance_factor(root)
    # LL
    if balance_factor > 1 and value < root.left.value:
        return right_rotate(root)
    # RR
    elif balance_factor < -1 and value > root.right.value:
        return left_rotate(root)
    # LR
    elif balance_factor > 1 and value > root.left.value:
        root.left = left_rotate(root.left)
        return right_rotate(root)
    # RL
    elif balance_factor < -1 and value < root.right.value:
        root.right = right_rotate(root.right)
        return left_rotate(root)
    return root

示例

现在让我们通过一个示例来理解平衡二叉树的使用。

我们现在有一组数据[5, 6, 2, 8, 3, 1, 4],我们可以通过以下代码将它们插入平衡二叉树中并进行中序遍历来验证插入操作是否正确。

if __name__ == '__main__':
    nums = [5, 6, 2, 8, 3, 1, 4]
    root = None
    for num in nums:
        root = insert_node(root, num)
    res = inorder_traverse(root, [])
    print(res)   # [1, 2, 3, 4, 5, 6, 8]
    root = delete_node(root, 5)
    res = inorder_traverse(root, [])
    print(res)   # [1, 2, 3, 4, 6, 8]

注意我们通过AVL Tree保证了二叉树的高度平衡,因此对于同样的数据,我们可以得到不同的高度,这可以节省查找操作的时间复杂度。

以上是二叉排序树与平衡二叉树的Python实现攻略,希望对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python实现二叉排序树与平衡二叉树的示例代码 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 浅谈jquery中setinterval()方法

    以下是浅谈jQuery中setInterval()方法的完整攻略,包含两个示例说明: setInterval()方法概述 jQuery setInterval()方法用于在指定的时间间隔内重复执行一个函数。它接受两个参数,第一个参数是要执行的函数,第二个参数是时间间隔(以毫秒为单位)。 setInterval()方法语法 以下是setInterval()方法…

    other 2023年5月9日
    00
  • php取整

    在PHP中,取整有多种方式,包括向上取整、向下取整、四舍五入等。本文将详细介绍PHP中取整的各种方式及其使用方法,同时提供两个示例说明。 向上取整 向上取整是将一个数值向上舍入到最接近的整数。在PHP中我们可以使用ceil()函数来实现向上取整。以下是一个示例: $num = 3.14; $ceilNum = ceil($num); echo $ceilNu…

    other 2023年5月7日
    00
  • 什么是前端开发?

    前端开发的完整攻略包含以下几个步骤: 设计和构思阶段: 在这个阶段,需要设计和构思网站或应用程序的大致架构和样式,包括页面布局,颜色和字体选择等。 示例代码: <!DOCTYPE html> <html> <head> <title>网站标题</title> <meta charset=&qu…

    其他 2023年4月19日
    00
  • vsconsole

    当然,我很乐意为您提供vsconsole的完整攻略。以下是详细的步骤和示例: 步骤1:了解vsconsole vsconsole是Visual Studio Code的终端扩展,它可以在Visual Studio Code中打开一个终端窗口,并在其中运行命令。 步骤2:安装vsconsole 以下是在Visual Studio Code中安装vsconsol…

    other 2023年5月6日
    00
  • SQLite字符串比较时的大小写问题解决方法

    SQLite字符串比较时的大小写问题解决方法攻略 在SQLite中,字符串比较时存在大小写问题。默认情况下,SQLite的字符串比较是不区分大小写的。但是,有时我们需要进行大小写敏感的字符串比较。下面是解决这个问题的两种方法示例: 方法一:使用COLLATE关键字 可以使用COLLATE关键字来指定字符串比较的规则。通过指定不同的COLLATE规则,可以实现…

    other 2023年8月16日
    00
  • Win11重启一直转圈圈进不去系统怎么办?Win11重启转圈圈两种解决方法

    针对Win11重启一直转圈圈进不去系统这个问题,一般情况下可以采取以下两种解决方法: 方法一:检查系统文件和驱动程序 第一种解决方法是检查系统文件和驱动程序是否出现问题,以及是否需要更新。具体步骤如下: 进入Win11的“设置”界面。 点击“更新和安全”选项。 点击“还原”选项。 点击“开始”按钮,然后按照提示操作。 示例:用户小张遇到了Win11重启转圈圈…

    other 2023年6月27日
    00
  • Java单例模式继承覆盖多态原理详解

    Java单例模式是一种常见的设计模式,它的目标是保证一个类只有一个实例,并且提供全局访问点。单例模式有多种实现方式,其中最常见的是饿汉式和懒汉式。不过,当单例模式需要进行继承覆盖时就需要考虑一些问题了。本篇攻略将详细讲解Java单例模式的继承、覆盖、多态原理及其应用。 一、单例模式 单例模式是Java中常用的一种设计模式,它的目的是保证一个类只有一个实例,并…

    other 2023年6月26日
    00
  • Sybase:循环调用存储过程

    Sybase:循环调用存储过程 Sybase数据库中,我们经常需要使用存储过程来实现复杂的业务逻辑。而在某些场景下,我们可能需要对一个存储过程进行循环调用,以便在不同的参数下执行相同的业务逻辑。本文将介绍如何在Sybase数据库中循环调用存储过程。 准备工作 在进行循环调用存储过程之前,我们需要创建一个需要循环调用的存储过程。以下是一个简单的示例存储过程: …

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部