洞明算法之平衡二叉树( AVL 树)

1. 由来

平衡二叉树,是一类改进的二叉查找树,平衡指叶子节点深度趋于平衡(最大不超过 1 ),它的竞争对手当属 Hash 表。最经典的自平衡二叉树是 AVL 树(源自发明者的名字 G. M. Adelson-Velsky 和 E. M. Landis),在 AVL 树中任何节点的两个子树的高度(高度: 叶节点为 0 ,深度: 根节点为 0 )最大差别为 1,因此也被称为高度平衡树。

下面是自平衡二叉树与 Hash 表的对比:
(1)自平衡二叉树在 按序遍历 所有键值时是量级最优的,Hash 表不能。
(2)自平衡二叉树在查找一个键值时,最坏情况下时间复杂度优于 Hash 表, O(log n) 对比 O(n);
(3)自平衡二叉树的平均时间复杂度逊于 Hash表,O(log n) 对比 O(1)。
注:直观感受下 O(log n), log( 21亿 ) = 30.9,更狠的是 ln( 21亿 ) = 9.3

2. 特性

AVL 树是一种特殊的二叉搜索树(即根节点大于左子树所有节点且小于右子树所有节点,不存在值相同的两个节点)。普通二叉搜索树查找、插入和删除在最坏情况下会退化为顺序查找,即最坏情况的时间复杂度为 O(n) ,而 AVL 树在平均和最坏情况下都是 O(log n)

3. 实现平衡

3.1 影响平衡的操作

树是否平衡取决于它是否有平衡因子为 2 或 -2 的节点存在,平衡因子指该节点左右子树的高度差。由于插入和删除操作会影响 AVL 树的平衡,因此在对 AVL 树进行该类操作后需要通过旋转 AVL 树来平衡它。

3.2 旋转解析

下图主要展示了在执行插入、删除节点之后树的 4 种不同情况及其旋转方案。
(1)将绿色节点提升为根节点,即右旋图中所示子树;
(2)将黄色节点提升为根节点,即左旋图中所示子树;
(3)先以红色节点为根节点,左旋以绿色节点为根节点的子树;
然后参照(1)旋转图中子树;
(4)先以红色节点为根节点,右旋以黄色节点为根节点的子树;
然后参照(2)旋转图中子树。

这里写图片描述

4. 学习 AVL 的目的

AVL 和 红黑树都属于平衡树,但是红黑树的应用更广泛,而理解 AVL 是学习红黑树的基础。
AVL 最大的有点在于其平衡性,增加了插入和删除的代价,而红黑树则是牺牲部分平衡性以换取插入/删除操作时少量 的旋转操作(不超过 3 次,插入是 2 次) ,整体来说性能要优于 AVL 树。

红黑树的典型用途有:
(1)关联数组 (即映射( Map ) 、字典( Dictionary ) 等) ,常见于 C++ 的 STL (如 multimap (键重复) 和 map (键不重复));
(2)著名的 linux 进程调度 Completely Fair Scheduler,用红黑树管理进程控制块;
(3)epoll 在内核中的实现,用红黑树管理事件块;
(4)nginx 中,用红黑树管理 timer 等;
(5)Java 的 TreeMap 实现。

5. AVL 树实现思路

5.1 节点构造

typedef struct AVLNODE{
    int key;
    int b_factor;
    int height;
    struct AVLNODE* parent; //?是否需要
    struct AVLNODE* left;
    struct AVLNODE* right;
}AVLNODE;

5.2 类构造

class AVLTREE{
    AVLNODE *head;
    void TraversalTree();
    void InsertKey(int key);
    void DeleteKey(int key);
}

5.3 插入

5.4 删除

5.5 遍历

所要考虑的事情:
(1)递归打印;
(2)每个节点负责计算自己的未知,以及
打印下面的分支符号,若无左右子树则不需打印。(可以参考完全二叉树的打印)

5.x 完成代码

6. 扩展学习

(1)跳表;
(2)应用 AVL 树到排序算法,与传统排序算法相比较会有哪些优劣?

7. 参考链接(需翻墙访问)

AVL 树
红黑树
关联数组
二叉搜索树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值