首页 > 编程语言 >AVL树和红黑树的Python代码实现

AVL树和红黑树的Python代码实现

时间:2023-12-20 16:35:29浏览次数:38  
标签:黑树 node right Python self AVL key 节点 left

AVL树

AVL树是一种自平衡二叉搜索树。在这种树中,任何节点的两个子树的高度差被严格控制在1以内。这确保了树的平衡,从而保证了搜索、插入和删除操作的高效性。AVL树是由Georgy Adelson-Velsky和Evgenii Landis在1962年发明的,因此得名(Adelson-Velsky和Landis树)。  

平衡因子:每个节点的平衡因子是其左子树的高度减去其右子树的高度。平衡因子必须保持在-1、0或1之间。

旋转操作:为了维持平衡,在进行插入或删除操作后,可能会执行单旋转或双旋转。单旋转包括右旋(针对左重失衡)和左旋(针对右重失衡)。双旋转是一种更复杂的调整,包括左-右旋转和右-左旋转。

时间复杂度:在AVL树中,查找、插入和删除操作的时间复杂度均为O(log n),其中n是树中的节点数。 

 

AVL树节点定义

class AVLNode:
    def __init__(self, key):
        self.key = key
        self.height = 1
        self.left = None
        self.right = None

这里定义了一个AVL树的节点。每个节点有一个键值key,一个高度属性height,以及指向左右子节点的指针leftright。 

AVL树的高度和平衡因子

AVL树的关键是保持每个节点的平衡。平衡因子被定义为节点的左子树高度减去其右子树高度。这个因子应该是-1、0或1。如果在任何时候,一个节点的平衡因子不在这个范围内,我们需要通过旋转来重新平衡树。

def get_height(node):
    if not node:
        return 0
    return node.height

def get_balance(node):
    if not node:
        return 0
    return get_height(node.left) - get_height(node.right)

这两个函数帮助我们计算任何节点的高度和平衡因子。

AVL树旋转操作

为了维持平衡,我们可能需要进行树的旋转操作。主要有四种类型的旋转:右旋转、左旋转、左-右旋转和右-左旋转。

  1. 右旋转:

当一个节点的左子树比右子树高时,我们进行右旋转。

def rotate_right(z):
    y = z.left
    T3 = y.right
    y.right = z
    z.left = T3
    z.height = 1 + max(get_height(z.left), get_height(z.right))
    y.height = 1 + max(get_height(y.left), get_height(y.right))
    return y
  1. 左旋转:

当一个节点的右子树比左子树高时,我们进行左旋转。

def rotate_left(z):
    y = z.right
    T2 = y.left
    y.left = z
    z.right = T2
    z.height = 1 + max(get_height(z.left), get_height(z.right))
    y.height = 1 + max(get_height(y.left), get_height(y.right))
    return y
  1. 左-右旋转和右-左旋转:

这些是双旋转操作,先进行一次旋转使其成为第一种或第二种情况,然后再进行相应的旋转。

AVL树插入操作

插入操作类似于普通的二叉搜索树插入,但是在插入后,我们需要更新祖先节点的高度,并检查每个节点的平衡因子,以确保树保持平衡。

def insert(node, key):
    if not node:
        return AVLNode(key)
    elif key < node.key:
        node.left = insert(node.left, key)
    else:
        node.right = insert(node.right, key)

    node.height = 1 + max(get_height(node.left), get_height(node.right))
    balance = get_balance(node)

    if balance > 1 and key < node.left.key:
        return rotate_right(node)
    if balance < -1 and key > node.right.key:
        return rotate_left(node)
    if balance > 1 and key > node.left.key:
        node.left = rotate_left(node.left)
        return rotate_right(node)
    if balance < -1 and key < node.right.key:
        node.right = rotate_right(node.right)
        return rotate_left(node)

    return node

 

AVL树删除操作

删除操作也与普通的二叉搜索树类似,但在删除节点后,我们需要更新祖先节点的高度,并检查每个节点的平衡因子以重新平衡树。

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

def delete(node, key):
    if not node:
        return node

    if key < node.key:
        node.left = delete(node.left, key)
    elif key > node.key:
        node.right = delete(node.right, key)
    else:
        if node.left is None:
            temp = node.right
            node = None
            return temp
        elif node.right is None:
            temp = node.left
            node = None
            return temp

        temp = min_value_node(node.right)
        node.key = temp.key
        node.right = delete(node.right, temp.key)

    if node is None:
        return node

    node.height = 1 + max(get_height(node.left), get_height(node.right))
    balance = get_balance(node)

    if balance > 1 and get_balance(node.left) >= 0:
        return rotate_right(node)
    if balance < -1 and get_balance(node.right) <= 0:
        return rotate_left(node)
    if balance > 1 and get_balance(node.left) < 0:
        node.left = rotate_left(node.left)
        return rotate_right(node)
    if balance < -1 and get_balance(node.right) > 0:
        node.right = rotate_right(node.right)
        return rotate_left(node)

    return node

这个删除函数处理了三种情况:要删除的节点有两个子节点、一个子节点或没有子节点。在删除节点后,它会通过旋转操作确保树保持平衡。

使用AVL树

现在我们可以创建一个AVL树的实例,并进行插入和删除操作:

avl_tree = None

keys = [20, 4, 15, 70, 50, 80, 100]
for key in keys:
    avl_tree = insert(avl_tree, key)

avl_tree = delete(avl_tree, 70)

在这个例子中,我们插入了一些数字,然后删除了一个。

红黑树

红黑树是另一种自平衡二叉搜索树,它通过确保树从根到叶子的最长可能路径不超过最短可能路径的两倍来维持大致的平衡。

红黑树的节点有两种颜色:红色或黑色。这种树遵循以下重要属性:

颜色属性:每个节点要么是红色,要么是黑色。

根属性:树的根总是黑色。

叶子属性:所有叶子(NIL节点)都是黑色。

红色节点属性:如果一个节点是红色的,那么它的两个子节点都是黑色的。

路径属性:从任一节点到其每个叶子的所有路径都包含相同数量的黑色节点。

红黑树通过旋转和重新着色来维持这些属性。虽然红黑树的平衡性不如AVL树,但它在插入和删除操作中需要更少的旋转,这使得它在某些类型的应用中更高效。

 

红黑树节点定义:

class RedBlackNode:
    def __init__(self, key, color="red"):
        self.key = key
        self.color = color
        self.left = None
        self.right = None
        self.parent = None

这里定义了一个红黑树的节点。除了常规的key外,节点还包含一个color属性以及指向父节点和子节点的链接。

红黑树旋转操作:

为了维持红黑树的特性,在插入和删除节点时可能需要进行树的旋转操作。主要有两种类型的旋转:左旋和右旋。

  1. 左旋:

当一个节点的右子节点是红色而左子节点是黑色时进行。

def rotate_left(self, x):
    y = x.right
    x.right = y.left
    if y.left != self.TNULL:
        y.left.parent = x

    y.parent = x.parent
    if x.parent == None:
        self.root = y
    elif x == x.parent.left:
        x.parent.left = y
    else:
        x.parent.right = y
    y.left = x
    x.parent = y

 

  1. 右旋:

当一个节点的左子节点是红色而左子节点的左子节点也是红色时进行。

def rotate_right(self, x):
    y = x.left
    x.left = y.right
    if y.right != self.TNULL:
        y.right.parent = x

    y.parent = x.parent
    if x.parent == None:
        self.root = y
    elif x == x.parent.right:
        x.parent.right = y
    else:
        x.parent.left = y
    y.right = x
    x.parent = y

红黑树插入操作:

插入操作首先类似于普通的二叉搜索树插入。但在插入一个节点后,可能需要进行多次颜色更改和旋转来修复可能违反的红黑树性质。

def insert(self, key):
    node = RedBlackNode(key)
    node.parent = None
    node.key = key
    node.left = self.TNULL
    node.right = self.TNULL
    node.color = 1  # 新节点必须是红色

    y = None
    x = self.root

    while x != self.TNULL:
        y = x
        if node.key < x.key:
            x = x.left
        else:
            x = x.right

    node.parent = y
    if y == None:
        self.root = node
    elif node.key < y.key:
        y.left = node
    else:
        y.right = node

    if node.parent == None:
        node.color = 0
        return

    if node.parent.parent == None:
        return

    self.fix_insert(node)

 

在插入节点后,fix_insert函数被调用以重新平衡树,确保树仍然是一个有效的红黑树。

红黑树删除操作:

删除操作比插入操作更复杂。删除节点后,可能需要进行多次颜色更改和旋转来修复可能违反的红黑树性质。

def delete_node(self, node, key):
    # 省略具体删除逻辑
    self.fix_delete(x)

在删除节点后,fix_delete函数被调用以重新平衡树。

使用红黑树:

现在我们可以创建一个红黑树的实例,并进行插入和删除操作:

rbt = RedBlackTree()
numbers = [20, 15, 25, 10, 30, 5, 35]
for number in numbers:
    rbt.insert(number)

rbt.delete_node(rbt.root, 15)

在这个例子中,我们插入了一些数字,然后删除了一个。

红黑树是一种复杂的数据结构,它通过一系列精心设计的规则和操作来确保树的平衡。尽管它的实现比普通的二叉搜索树复杂得多,但它在插入、删除和查找操作上提供了良好的最坏情况性能。这种平衡是通过确保任何路径上的黑色节点数目大致相同来实现的。红黑树广泛应用于计算机科学的许多领域,尤其是在那些需要快速查找操作的场景中,如数据库和文件系统。

实现红黑树要求对它的性质和操作有深入的理解。上述代码提供了一个基本的框架,但它并不完整。在实际应用中,您可能还需要处理更多的边界情况和优化。每个操作背后都有复杂的逻辑和数学原理,这是理解和实现红黑树的关键部分。

From:BigQuant量化平台 —— 《AVL树和红黑树的Python代码实现

标签:黑树,node,right,Python,self,AVL,key,节点,left
From: https://www.cnblogs.com/bigquant/p/17916776.html

相关文章

  • 【Python&目标识别】Yolo v5-7.0版本中文标签显示方法(附字体链接)
    ​    Yolo的程序之前已经定制化输出过了,但是最近业主突然想要中文的标签,所以赶紧去修改了一下源代码,从网上发现很多资料都改这改那,搞四五个文件结果还没成功。所以自己研究了一下,现在已经完美解决了。今天就和大家分享一下Yolov5-7.0版本的目标识别如何添加中文的标签......
  • 利用Python进行数据分析_Pandas_Numpy高级应用
    Numpy高级应用1.ndarray对象内部机理importpandasaspdimportnumpyasnpfrompandasimportSeries,DataFrameimportwarningswarnings.filterwarnings("ignore")略2.高级数组操作arr=np.arange(8)arrarray([0,1,2,3,4,5,6,7])arr_new=arr.reshape......
  • Python中配置Excel导出模板
    定义Excel列对象classExcelColumn:"""定义Excel中的列参数:name(str):列的名称。width(int|None,可选):列的宽度。默认为None。required(bool,可选):指示列是否必需。默认为False。mapping_factory(Callable......
  • Python语言实现两台计算机用TCP协议跨局域网通信
    成果展示:(这张图是在我本地电脑上用pycharm运行两个程序测试,实际可以在两台电脑上分别运行。)设备要求和实现的功能:实现的功能:跨局域网通信(仅支持两台计算机)跨局域网收发小文件,支持缓存在服务器,再一键接收(仅支持两台计算机)使用方法:在服务器上运行server.py程序,在两台客户......
  • python中的 时间、日期写法。
    python打印当前日期时间 一、打印 带日期与时间点 方法一:使用datetime模块:importdatetimenow=datetime.datetime.now()print(now)效果如下: 方法二:使用time模块:importtimenow=time.strftime("%Y-%m-%d%H:%M:%S",time.localtime())print(now) ......
  • 提高Python开发效率的实用方法
    Python作为一种简洁而强大的编程语言,广泛应用于各种领域的软件开发。提高Python开发效率是开发者们关注的重要课题。本文将分享一些实用的方法,帮助您在Python开发中更高效地完成任务,提高代码质量和开发速度。1.使用虚拟环境:在项目开发中,使用虚拟环境是一种良好的实践。虚拟环境可以......
  • 使用Python进行Firefox证书上传和删除证书的步骤
    在Web开发和测试过程中,有时需要在Firefox浏览器中管理证书,包括上传证书和删除证书。本文将介绍如何使用Python和Selenium库进行这些操作,以便更方便地处理证书管理。1.安装Selenium库和WebDriver:首先,确保已安装Selenium库和相应浏览器的WebDriver。可以使用以下命令安装Selenium:```b......
  • Python爬虫框架推荐及其特点
    在网络爬虫开发中,选择适合的爬虫框架可以大大提高开发效率和爬取数据的质量。Python作为一种广泛应用于爬虫开发的编程语言,有许多优秀的爬虫框架可供选择。本文将介绍几个好用的Python爬虫框架,并列举它们的特点,帮助您选择适合自己的框架。1.Scrapy:Scrapy是一个强大的开源爬虫框架,被......
  • CentOS安装Python3
    前置准备检查是否已经安装Python3:命令行直接输入Python3下载Python3的安装包https://www.python.org/ftp/python/安装安装依赖yuminstallzlib-develbzip2-devellibffi-developenssl-develncurses-develsqlite-develreadline-develtk-develgccmake下载Pyth......
  • 利用Python进行数据分析_Pandas_数据规整
    数据规整1.时间序列以及截面对齐importpandasaspdimportnumpyasnpfrompandasimportSeries,DataFrameimportwarningswarnings.filterwarnings("ignore")#设置一个日期范围date_range=pd.date_range(start="2023-01-01",end="2023-01-10",freq=......