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代码实现

AVL树和红黑树的Python代码实现的更多相关文章

  1. 单例模式,堆,BST,AVL树,红黑树

    单例模式 第一种(懒汉,线程不安全): public class Singleton { private static Singleton instance; private Singleton () ...

  2. AVL树与红黑树

    平衡树是平时经常使用数据结构. C++/JAVA中的set与map都是通过红黑树实现的. 通过了解平衡树的实现原理,可以更清楚的理解map和set的使用场景. 下面介绍AVL树和红黑树. 1. AVL ...

  3. 论AVL树与红黑树

    首先讲解一下AVL树: 例如,我们要输入这样一串数字,10,9,8,7,15,20这样一串数字来建立AVL树 1,首先输入10,得到一个根结点10 2,然后输入9, 得到10这个根结点一个左孩子结点9 ...

  4. 二叉树,AVL树和红黑树

    为了接下来能更好的学习TreeMap和TreeSet,讲解一下二叉树,AVL树和红黑树. 1. 二叉查找树 2. AVL树 2.1. 树旋转 2.1.1. 左旋和右旋 2.1.2. 左左,右右,左右, ...

  5. B树,B+树,红黑树应用场景AVL树,红黑树,B树,B+树,Trie树

    B B+运用在file system database这类持续存储结构,同样能保持lon(n)的插入与查询,也需要额外的平衡调节.像mysql的数据库定义是可以指定B+ 索引还是hash索引. C++ ...

  6. [BinaryTree] AVL树、红黑树、B/B+树和Trie树的比较

    转自:AVL树.红黑树.B/B+树和Trie树的比较 AVL树 最早的平衡二叉树之一.AVL是一种高度平衡的二叉树,所以通常的结果是,维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应 ...

  7. AVL树,红黑树,B-B+树,Trie树原理和应用

    前言:本文章来源于我在知乎上回答的一个问题 AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? 看完后您可能会了解到这些数据结构大致的原理及为什么用在这些场景,文章并不涉及具体操作 ...

  8. AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中?

    AVL树: 最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间的管理用到了AVL树. 红黑树: 平衡二叉树,广泛用在C++的STL中.如map和set都是用红黑树实现的. ...

  9. 对于AVL树和红黑树的理解

    AVL又称(严格)高度平衡的二叉搜索树,也叫二叉查找树.平衡二叉树.window对进程地址空间的管理用到了AVL树. 红黑树是非严格平衡二叉树,统计性能要好于平衡二叉树.广泛的在C++的STL中,ma ...

  10. Mysql为什么使用b+树,而不是b树、AVL树或红黑树?

    首先,我们应该考虑一个问题,数据库在磁盘中是怎样存储的?(答案写在下一篇文章中) b树.b+树.AVL树.红黑树的区别很大.虽然都可以提高搜索性能,但是作用方式不同. 通常文件和数据库都存储在磁盘,如 ...

随机推荐

  1. WPF学习 - 自定义窗体(二)

    上一篇文章写了如何创建自定义窗体:使用 WindowChrome 或者 WindowStyle="None"这两种方式.本文将讲述如何设置窗体的效果(以阴影效果为例),以及在效果模 ...

  2. git status详解

    git status详解 在使用Git进行版本控制时,git status是一个非常有用的命令,用于查看当前代码仓库的状态.它可以告诉你哪些文件已更改.添加或删除,以及是否有未提交的更改等.本篇博客文 ...

  3. 用shell命令绘制三角形

    本文旨在通过几个经典的图案来练习shell编程,涉及知识点:for循环,大小比较,基本的数学公式计算,echo小技巧.update:2019-10-17 10:13:54 初次绘制 $ for ((l ...

  4. Laf 云开发平台及其实现原理

    Laf 产品介绍 自我介绍 大家好,我是来自 Laf 团队的王子俊,很高兴今天能在这里给大家分享我们 Laf 云开发平台及其实现原理.本来想说一点什么天气之类的话作为开头,但主持人都说完啦,我就不多说 ...

  5. springBoot使用注解Aop实现日志模块

    我们在日常业务操作中需要记录很多日志,可以在我们需要的方法中对日志进行保存操作,但是对业务代码入侵性大.使用切面针对控制类进行处理灵活度不高,因此我们可以使用自定义注解来针对方法进行日志记录 1.注解 ...

  6. ContentPresenter使用DataTemplate

    在使用自定义样式内容时,有时也需要在自定义样式中绑定一下数据模板 可以使用ContentPresenter的ContentTemplate绑定定义好的资源 DateTemplate 用法代码如下 &l ...

  7. 什么是 x10 开发工具?「GitHub 热点速览」

    都听过 10x 工程师,一个人顶得过十个人.但是并不是每个人都是 10x 工程师,但是有些效率工具可能让你变成 2x.3x 的工程师.比如,这周火爆的 3D 游戏引擎 FlaxEngine 有着强大的 ...

  8. 【Azure Function App】Python Function调用Powershell脚本在Azure上执行失败的案例

    问题描述 编写Python Function,并且在Function中通过 subprocess  调用powershell.exe 执行 powershell脚本. import azure.fun ...

  9. 基于Java Swing和BouncyCastle的证书生成工具

    "Almost no one will remember what he had just not interested." - Nobody "几乎没有人会记得他所丝毫 ...

  10. 在 Linux 环境(Ubuntu)下安装 Slurm 和 OpenMPI

    安装 Slurm 从软件源安装 slurm-wlm(每个节点都需要装的执行工具).slurm-client(客户机装的提交命令的工具).munge(节点间通信插件) sudo apt install ...