算法,请不要这么经典 - 平衡二叉搜索树AVL

来源:互联网 发布:nginx配置ssl证书密码 编辑:程序博客网 时间:2024/04/29 10:50

AVL 实现: https://code.csdn.net/hp_truth/data_structure_and_algorithm/tree/master/tree/AvlTree.h
之前的一篇文章简单地介绍了二叉树的可视化,有了这个工具,可以更直观地对二叉搜索树进行理解。

二叉搜索树的查找比较简单,效率取决于树的左右子树是否平衡,对于平衡的二叉搜索树,查找的时间复杂度是O(n)。

而树是否平衡取决于主要是在插入和删除时是否保持平衡状态。

平衡的定义有很多中,比如AVL树和红黑树就各有不同的定义。本文主要讨论一下AVL树的插入和删除。


对于普通的二叉搜索树,插入可能会导致树退化成链表,比如将排序的数组元素插入到普通二叉搜索树,就会出现这样的情况,这种查找效率是线性的。

AVL树是通过限制每个节点的左右子树的高度差不能大于1来保证平衡性的。如果插入或删除后,某个节点的左右子树高度差大于1(等于2),

则会通过旋转来调整这棵树,使其重新达到平衡。


具体的实现代码可以参考我的git 代码。通过可视化输出,你可以自己来验证算法。


一些实现细节:

为了实现可视化功能的通用性,我们将这部分代码提取到一个工具类中TreeDumper。

同时我们定义了一个二叉树节点的基类模板BaseTreeNode<Comparable>,这样任何二叉树,只需继承这个基类就可以用TreeDumper来可视化了。

代码中bst.h是普通的二叉搜索树的模板实现,它是直接使用BaseTreeNode<Comparable>作为其节点。

bst2.h和bst.h很类似,它们的主要区别在一些成员函数的实现上,一个是使用指针的引用来实现,

而另一个是使用指针的指针来实现。

AvlTree.h中的AvlTreeNode则是继承了BaseTreeNode<Comparable>, 增加了一个成员height。

在类AvlTree的一些成员函数中,需要用到指针的引用,而递归的时候,left/right是基类类型,这里需要进行一次强制类型转换。


插入的例子:

比如,对于[1 .. 12]这个有序数组,插入普通的二叉搜索树会变成一个链表了:



而插入到AVL, 则是平衡的:



删除的例子:

比如,对于[6, 2, 8, 1, 3, 7, 4], 插入到AVL中后是:


删除6这个节点后变成:


0 0