AVLTree的节点删除

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

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

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

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

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

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

交换后的树形变成:

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

调整后的树形变成:

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

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

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

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

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

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

其调整后的树形变成

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

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

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

时间: 2024-10-09 00:05:43

AVLTree的节点删除的相关文章

jQuery基础(DOM篇,append(),after(),prepend(),insertAfter(),节点删除,遍历方法each())

1.DOM创建节点及节点属性   创建流程比较简单,大体如下: - 创建节点(常见的:元素.属性和文本) - 添加节点的一些属性 - 加入到文档中   流程中涉及的一点方法: - 创建元素:document.createElement - 设置属性:setAttribute - 添加文本:innerHTML - 加入文档:appendChild   2.jQuery节点创建与属性的处理 创建元素节点: 可以有几种方式,后面会慢慢接触.常见的就是直接把这个节点的结构给通过HTML标记字符串描述出来

AVLTree

一.AVLTree的性质 1.左子树和右子树的高度差不超过1 2.左右子树都是AVL树 3.每一个节点都有一个平衡因子,任一点的平衡银子为(-1,0,1) 二.AVL树的效率 log2n 三.AVLTreeNode template<class K,class V> struct AVLTreeNode { AVLTreeNode<K, V>* _parent; AVLTreeNode<K, V>* _left; AVLTreeNode<K, V>* _ri

基本数据结构之AvlTree

问题描述: AvlTree 问题分析: 基本的实现 代码实现: package c04; /**  * @project: DataStructureAndAlgorithmAnalysis  * @filename: AvlTree.java  * @version: 0.10  * @author: JM Han  * @date: 15:04 2015/10/21  * @comment: Test Purpose  * @result:  */ import master.Underfl

hdu 4006/AvlTree

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4006 这道题以前用c语言写的Avltree水过了.. 现在接触了c++重写一遍... 由于没有删除操作故不带垃圾回收,具体如下: 1 #include<cstdio> 2 #include<cstdlib> 3 #include<iostream> 4 #define Max_N 1000100 5 inline int max(int &a, int &b

关于TAILQ链表节点删除问题

这两天偶遇无线驱动中对链表节点删除的问题,刚开始修改代码的时候并没有很在意,把TAILQ链表当成一般的链表来处理,虽然修改以后没有出现段错误,但是后面review代码的时候发现,这样改不对.后面花了点时间好好看了一下TAILQ的相关代码. 首先看一下这个TAILQ链表的结构,TAILQ链表包括两个部分,一个叫HEAD的头部,另外一个就是ENTRY实体部分:下面是两部分的定义: #define TAILQ_HEAD(name, type)                      \ struct

flex 节点删除

<mx:Script>        <![CDATA[            protected function btn1_clickHandler(evt:MouseEvent):void {                delete someXML.nodeToDelete;                txtArea.text = someXML.toXMLString();            }             protected function btn2_

DOM节点删除之empty和remove

刚学了新知识,虽然是一个小知识点,但还是忍不住想和大家分享. .empty()是指对该节点后代的删除,结果是清空该节点(该节点里面已无元素). .remove()是指删除该节点,结果是删除该节点(该节点及其后代元素都将不存在). 下面放代码来说明. <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8"> <title></title&g

Java实现平衡二叉树(AVLTree)的构建

最近在学习数据结构上关于平衡二叉树的知识,看了严老师的思路,感觉用java写出递归的构建方式有点困难,因为其中的递归需要把引用传进去,所以感觉是要实现起来比较麻烦,所以就首先想到使用非递归的方式来实现构建平衡二叉树. 使用非递归的方式,思路也很简单,就是为每一个结点都要定义一个平衡因子的属性,当成功向树中插入一个数据时,我就要进行回溯,看看有没有平衡因子的绝对值等于2的结点,如果有,那就需要进行旋转.当时的思路仅限于这些,接触java没有多久,目测如果实现起来,有点困难. 所以,上网查询了一个博

AVLTree的实现算法(C++实现)

#include<stack> #include<utility> #include<allocators> #include<functional> using std::pair; using std::allocator; using std::less; using std::stack; #ifndef AVLTreeH #define AVLTreeH enum {RH=-1,EH=0,LH=1}; template<typename T&