AVL树和红黑树的Python代码实现
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,以及指向左右子节点的指针left和right。
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树旋转操作
为了维持平衡,我们可能需要进行树的旋转操作。主要有四种类型的旋转:右旋转、左旋转、左-右旋转和右-左旋转。
右旋转:
当一个节点的左子树比右子树高时,我们进行右旋转。 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
左旋转:
当一个节点的右子树比左子树高时,我们进行左旋转。
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
左-右旋转和右-左旋转:
这些是双旋转操作,先进行一次旋转使其成为第一种或第二种情况,然后再进行相应的旋转。
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属性以及指向父节点和子节点的链接。
红黑树旋转操作:
为了维持红黑树的特性,在插入和删除节点时可能需要进行树的旋转操作。主要有两种类型的旋转:左旋和右旋。
左旋:
当一个节点的右子节点是红色而左子节点是黑色时进行。
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
右旋:
当一个节点的左子节点是红色而左子节点的左子节点也是红色时进行。
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代码实现》
AVL树和红黑树的Python代码实现的更多相关文章
- 单例模式,堆,BST,AVL树,红黑树
单例模式 第一种(懒汉,线程不安全): public class Singleton { private static Singleton instance; private Singleton () ...
- AVL树与红黑树
平衡树是平时经常使用数据结构. C++/JAVA中的set与map都是通过红黑树实现的. 通过了解平衡树的实现原理,可以更清楚的理解map和set的使用场景. 下面介绍AVL树和红黑树. 1. AVL ...
- 论AVL树与红黑树
首先讲解一下AVL树: 例如,我们要输入这样一串数字,10,9,8,7,15,20这样一串数字来建立AVL树 1,首先输入10,得到一个根结点10 2,然后输入9, 得到10这个根结点一个左孩子结点9 ...
- 二叉树,AVL树和红黑树
为了接下来能更好的学习TreeMap和TreeSet,讲解一下二叉树,AVL树和红黑树. 1. 二叉查找树 2. AVL树 2.1. 树旋转 2.1.1. 左旋和右旋 2.1.2. 左左,右右,左右, ...
- B树,B+树,红黑树应用场景AVL树,红黑树,B树,B+树,Trie树
B B+运用在file system database这类持续存储结构,同样能保持lon(n)的插入与查询,也需要额外的平衡调节.像mysql的数据库定义是可以指定B+ 索引还是hash索引. C++ ...
- [BinaryTree] AVL树、红黑树、B/B+树和Trie树的比较
转自:AVL树.红黑树.B/B+树和Trie树的比较 AVL树 最早的平衡二叉树之一.AVL是一种高度平衡的二叉树,所以通常的结果是,维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应 ...
- AVL树,红黑树,B-B+树,Trie树原理和应用
前言:本文章来源于我在知乎上回答的一个问题 AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? 看完后您可能会了解到这些数据结构大致的原理及为什么用在这些场景,文章并不涉及具体操作 ...
- AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中?
AVL树: 最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间的管理用到了AVL树. 红黑树: 平衡二叉树,广泛用在C++的STL中.如map和set都是用红黑树实现的. ...
- 对于AVL树和红黑树的理解
AVL又称(严格)高度平衡的二叉搜索树,也叫二叉查找树.平衡二叉树.window对进程地址空间的管理用到了AVL树. 红黑树是非严格平衡二叉树,统计性能要好于平衡二叉树.广泛的在C++的STL中,ma ...
- Mysql为什么使用b+树,而不是b树、AVL树或红黑树?
首先,我们应该考虑一个问题,数据库在磁盘中是怎样存储的?(答案写在下一篇文章中) b树.b+树.AVL树.红黑树的区别很大.虽然都可以提高搜索性能,但是作用方式不同. 通常文件和数据库都存储在磁盘,如 ...
随机推荐
- 代码随想录算法训练营第二十八天| 93.复原IP地址 78.子集 90.子集II
93.复原IP地址 卡哥建议:本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了 题目链接/文章讲解:https://programmercarl.com/0093.%E5% ...
- 面霸的自我修养:ThreadLocal专题
王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群:共同富裕的Java人 今天是<面霸的自我修养>第5篇文章,我们一起来看看面试中会问到哪些关于ThreadLocal ...
- 例子:统计电影类型的个数,以及用bar绘制出来表示
import pandas as pdimport numpy as npfrom matplotlib import pyplot as plt#获取各种电影类型的数量file='./IMDB-Mo ...
- modbus转profinet网关连接ABB变频器在博图程序案例
modbus转profinet网关连接ABB变频器在博图程序案例 在博图里PLC无需编程利用兴达易控modbus转Profinet网关将ABB变频器接入到西门子网络中,用到设备为西门子1200PLC, ...
- Centos7使用s3fs-fuse挂载minio对象存储实践
Centos7使用s3fs-fuse挂载minio对象存储实践 事前准备 主机可以访问到对象存储API.例如minio默认的9000端口 主机安装好s3fs软件 已在minio上创建存储桶 安装s3f ...
- Vue element-ui 动态生成自定义table表头实现数据渲染
需求:1)表头的数据是动态的,有可能字段值很长且很多.解决方案自定义动态表头,字段长使用文字提示[el-tooltip组件]: 2)需要对表格data中的数据值进行枚举转成中文值,且显示不同的颜色. ...
- 【Unity3D】UI Toolkit样式选择器
1 前言 UI Toolkit简介 中介绍了样式属性,UI Toolkit容器 和 UI Toolkit元素 中介绍了容器和元素,本文将介绍样式选择器(Selector),主要包含样式类选择器(C ...
- 麒麟系统开发笔记(十三):在国产麒麟系统上编译OSG库、搭建基础开发环境和移植测试Demo
前言 在国产麒麟系统上实现C++三维仿真,使用OSG技术,其他基于web的技术也是可以但是交互上鼠标拽托等交互相对差一些,所以这块需要斟酌选择到底是何种技术来取舍. 本篇在厂家指定的麒麟系统上编 ...
- vscode双击没反应,后台也看不到进程的解决方案
百度找的解决方案: cmd窗口执行 netsh winsock reset 重置命令. 删除Romaing下的Code文件夹 修改Code/User/locale.json(我没找到这个文件)中的&q ...
- Gitlab仓库代码更新时Jenkins自动构建
环境说明 1.Jenkins和gitlab已经都已经安装完毕 2.Jenkins能连接到gitlab获取项目并能手动创建项目 3.Jenkins和gitlab能相互访问的到(gitlab要能连接到Je ...