AVLTree的节点删除

当年实现自己的共享内存模板的时候,map和set的没有实现,本来考虑用一个AVLTree作为底层实现的,为啥,因为我当时的数据结构知识里面我和RBTree不熟,只搞过AVLTree,但当时我一直没有看过删除如何实现。结果Scottxu跳出来,参考STLport的实现,迅速用RBTree搞掂了。搞得这个代码的头文件也就一直放在那儿,7-8年后,整理这个代码,看看Scottxu代码的底子,觉得挺不错的,觉得Copy改造一个AVLTree的实现应该很容易,就上手了。

AVL的插入无话可说,就是参考严蔚敏先生的《数据结构》上的手(仿佛回到十几年前的大学时代),迅速搞掂,但到删除,又哑火了。可以参考的代码不多。特别把AVLTree删除的代码讲明白的不多,有些明显存在错误,有些是用高度Height计算的平衡因子,但大部分实现计算Height都是用递归,但这种消耗性能方法在正式环境基本不具备可操作性。于是看了一些帖子,自己摸索了一下实现,完善了基于每个节点自己保存平衡因子的结构算法(严蔚敏先生的《数据结构》树中的插入也是基于平衡因子的,实现过程,发现小坑不少,总结出来。

(1)首先,仍然是找到这个要删除的节点。

(2)然后要如果这个节点是叶子节点,直接删除,如果不是叶子节点,需要将其交换成叶子节点。而交换方法是,选的其左子树的最大节点(左子节点的最右儿子节点,),或者右子树最小的节点(右子节点的最左儿子节点)。也就是选择这个节点最相邻的节点,和这个其交换。如果这个交换的位置还不是叶子节点,就继续前面的方法找个节点交换。

当这个节点成为叶子节点,就删除之。

示例一:10为要删除的节点。经过2次交换,将其调整为节点3的位置,成为叶子节点

clip_image002

交换后的树形变成:

clip_image004

示例二:10为要删除的节点。经过1次交换,将其调整为节点7的位置,成为叶子节点

clip_image006

调整后的树形变成:

clip_image008

(3)删除后,就要调整其父节点的平衡因子了。插入过程的时候,调整到平衡因子不等于0的节点就可以了。而删除过程恰恰相反,调整到一个平衡因子为0的时候(高度变化对平衡的影响只到此为止),就可以停止。发现一个节点存在不平衡,平衡因子是2或者-2,那么就需要做旋转调整。而旋转调整后,可能要继续向上调整(这个和插入不太一样),也可能停止调整(后面重点说明这个问题)。

如果是传统意义的的LL,LR,RR,RL旋转4种旋转,那么树的高度会减少,所以还是要继续向上调整平衡因子。

但有意思的是,由于删除的特点,你会发现可能出现的情况,不全是传统LL,LR,RR,RL 4种旋转。比如,下面这个示例。

节点内部的()内为平衡因子,12为要删除的节点,删除后,节点7的平衡因子是2,但其左子节点5的平衡因子是0,这和LL(左子树平衡因子为1)和LR旋转(左子树要平衡因子是-1)的情况都有一定的区别。

clip_image010

而这个树形还是可以通过LL旋转让其平衡,但平衡之后,各个节点的平衡因子和插入后的平衡因子不一样,根节点平衡因子没有调整为0,而且发生这种情况下,树的高度没有发生变化,所以在删除的情况下也不用继续向上调整了。

clip_image012

同样展示一下类似RR旋转的一种情况:

clip_image014

其调整后的树形变成

clip_image016

好了,基本情况如上所诉,参考代码放在GIT,是基于模板的,类似STLPort。

算法这个东西,没有看到明确明确说明前,碰还是谨慎一点,这次的测试过程画了一堆的树形图。最后怀旧一下,当年在话单过滤的时候也写过AVLTree(那时也没有实现删除),至今看看当年幼稚的代码,而当年的大学时代的《数据结构》课程的代码已经不知道在那张发霉的3吋软盘上了,有些唏嘘。好吧过两天要去听李宗盛的演唱会《既然青春留不住》了。

【本文作者是雁渡寒潭,本着自由的精神,你可以在无盈利的情况完整转载此文档,转载时请附上BLOG链接:http://www.cnblogs.com/fullsail/,否则每字一元,每图一百不讲价。对Baidu文库和360doc加价一倍】

原文地址:https://www.cnblogs.com/fullsail/p/3729015.html