数据结构—AVL树

AVL树是一种自平衡二叉搜索树,通过限制节点的平衡因子绝对值不超过1来保证高度平衡。插入操作可能导致失衡,通过单旋或双旋进行重平衡。删除操作同样需要重平衡,可能需要多次旋转。统一重平衡算法通过子树组装保持中序遍历不变,确保树的平衡。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 约束

  • 对于节点 vvv,我们定义其平衡因子为:vvv 的左、右子树的高度差。

  • AVL 树是一棵二叉搜索树,但其引入了额外的约束以保证其平衡性:树中各节点的平衡因子的绝对值不得超过 111

  • 设一共有 nnn 个节点,AVL 树始终可以将树的高度控制在 O(log⁡n)O(\log n)O(logn) 以内,且每次搜索、插入和删除操作均可在 O(log⁡n)O(\log n)O(logn) 时间内完成。

2. 插入

往 AVL 树中插入新节点可能会增加树的高度,从而导致其所在的子树失衡。

(1)首先按照二叉搜索树的插入方式插入新节点 xxx,;
(2)然后从 xxx 开始,沿着父指针逆行而上,直至找到第一个失衡的祖先节点(最低的失衡祖先),将其记为 ggg
(3)找到以 ggg 为根的子树中最高的子树,将其根记为 ppp
(4)找到以 ppp 为根的子树中最高的子树,将其根记为 vvv;可见新节点 xxx 一定位于子树 pppvvv 中(xxx 可能等于 vvv);

根据 g,p,vg,p,vg,p,v 的方向,可以分为四种情况:

(1)pppggg 的左孩子,且 vvvppp 的左孩子;
(2)pppggg 的左孩子,且 vvvppp 的右孩子;
(3)pppggg 的右孩子,且 vvvppp 的左孩子;
(4)pppggg 的右孩子,且 vvvppp 的右孩子;

其中,(1)和(4)是对称的情况,可以通过单旋操作来实现重平衡;(2)和(3)是对称的情况,可以通过双旋操作来实现重平衡。

情况(4)的重平衡操作如下所示:
在这里插入图片描述
虚线连接的两个灰色方框表示其中一个不为空(xxx 节点),另一个为空。

ggg 为轴进行 zag 旋转(设 ggg 的父节点为 pgpgpg):

(1)将 ggg 逆时针往下拉,使之成为 ppp 的新的左孩子;
(2)将 ppp 的旧的左孩子过继给 ggg,使之成为 ggg 的新的右孩子;
(3)更新 ppp 的父节点为 pgpgpgpgpgpg 的子节点为 ppp

情况(3)的重平衡操作如下所示:
在这里插入图片描述虚线连接的两个灰色方框表示其中一个不为空(xxx 节点),另一个为空。

ppp 为轴进行 zig 旋转:

(1)将 ppp 顺时针往下拉,使之成为 vvv 的新的右孩子;
(2)将 vvv 的旧的右孩子过继给 ppp,使之成为 ppp 的新的左孩子;
(3)更新 vvv 的父节点为 gggggg 的子节点为 vvv

经过上述操作后,情况(3)即变为了与情况(4)等价的情况。

由上可见,AVL 树的插入操作最多只需两次旋转操作即可使整棵树恢复平衡。

3. 删除

从 AVL 树中删除节点可能会降低树的高度,从而引发失衡情况。

(1)首先按照二叉搜索树的删除方式删除节点 xxx
(2)然后从 xxx 的父节点开始,沿着父指针逆行而上,直至找到第一个失衡的祖先节点(最低的失衡祖先),将其记为 ggg
(3)找到以 ggg 为根的子树中最高的子树,将其根记为 ppp
(4)找到以 ppp 为根的子树中最高的子树,将其根记为 vvv;如果 ppp 的左右子树等高,且 pppggg 的左孩子,则令 vvvppp 的左孩子,否则令 vvvppp 的右孩子;可见节点 xxx 一定位于子树 pppvvv 中;

与插入操作类似,根据 g,p,vg,p,vg,p,v 的方向,可以分为四种情况:

(1)pppggg 的左孩子,且 vvvppp 的左孩子;
(2)pppggg 的左孩子,且 vvvppp 的右孩子;
(3)pppggg 的右孩子,且 vvvppp 的左孩子;
(4)pppggg 的右孩子,且 vvvppp 的右孩子;

其中,(1)和(4)是对称的情况,可以通过单旋操作来实现重平衡;(2)和(3)是对称的情况,可以通过双旋操作来实现重平衡。

情况(1)的重平衡操作如下所示:

在这里插入图片描述
虚线连接的两个灰色方框不能同时为空,没有虚线连接的灰色方框可为空或非空。

ggg 为轴进行 zig 旋转(设 ggg 的父节点为 pgpgpg):

(1)将 ggg 顺时针往下拉,使之成为 ppp 的新的右孩子;
(2)将 ppp 的旧的右孩子过继给 ggg,使之成为 ggg 的新的左孩子;
(3)更新 ppp 的父节点为 pgpgpgpgpgpg 的子节点为 ppp

情况(2)的重平衡操作如下所示:

在这里插入图片描述虚线连接的两个灰色方框不能同时为空。

ppp 为轴进行 zag 旋转:

(1)将 ppp 逆时针往下拉,使之成为 vvv 的新的左孩子;
(2)将 vvv 的旧的左孩子过继给 ppp,使之成为 ppp 的新的右孩子;
(3)更新 vvv 的父节点为 gggggg 的子节点为 vvv

经过上述操作后,情况(2)即变为了与情况(1)等价的情况。

与插入操作不同的是,删除操作的重平衡过程只能保证失衡的子树恢复平衡,但此重平衡操作可能降低子树的高度,从而导致失衡向上传播(如,子树 ggg 属于原先高度更小的一个分支,重平衡之后 ggg 所在的子树高度又降低了),即无法保证整棵树保持平衡。

为此,需要继续从 ggg 开始,沿着父指针逆行而上,判断祖先是否失衡,如果出现失衡情况,则继续使用上述操作将子树恢复平衡,否则即可成功返回。

由此可见,相比于插入操作而言,AVL 树的删除操作可能需要更多次数的旋转操作,最坏情况下需要多达 O(log⁡n)O(\log n)O(logn) 次的旋转。

4. 统一重平衡算法

统一重平衡算法可以实现单旋和双旋操作。

其基本思想是:对重平衡之前的失衡子树进行中序遍历所得结果,和重平衡之后所得子树的中序遍历结果是一致的。

如,
在这里插入图片描述
(a)的中序遍历结果为:{T0,p,T1,v,T2,g,T3}\{ T_0, p, T_1, v, T_2, g, T_3 \}{T0,p,T1,v,T2,g,T3}
(b)的中序遍历结果为:{T0,p,T1,v,T2,g,T3}\{ T_0, p, T_1, v, T_2, g, T_3 \}{T0,p,T1,v,T2,g,T3}

统一重平衡操作涉及到了三个节点及对应的四棵子树,其不再进行旋转操作,而是直接进行子树的组装:{((T0,p,T1),v,(T2,g,T3))}\{ ((T_0, p, T_1), v, (T_2, g, T_3)) \}{((T0,p,T1),v,(T2,g,T3))},圆括号括住的内容表示一棵子树,中间为树根,两边分别为树根的左、右子树。其 Python 实现大致如下:

def connect34(a, b, c, T0, T1, T2, T3):
    a.leftChild = T0
    a.rightChild = T1
    c.leftChild = T2
    c.rightChild = T3
    b.leftChild = a
    b.rightChild = c

    if T0:
        T0.parent = a
    if T1:
        T1.parent = a
    if T2:
        T2.parent = c
    if T3:
        T3.parent = c
    a.parent = b
    c.parent = b

如,(a)到(c)的重平衡过程为:

connect34(p, v, g, p.leftChild, v.leftChild, v.rightChild, g.rightChild)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值