AVL树删除算法的实现--长安大学毕业设计

AVL树的删除算法的两种实现方法

本文是本人原创,当时作为长安大学高一凡老师带的学生,我的毕业设计就是做一个AVL 算法的演示软件。其中,AVL树的删除算法在度娘和 谷歌了很久都没有找到逻辑通畅或者说是我能够看懂的。后来,闭门造成,费了十几张A4纸才把算法设计出来。实现之后得到了老师的认同。非常的开心。之前我骗了大家,用网络上能搜到的算法来敷衍大家,一直觉得我的努力成果,不能让别人剽窃。但是,这么多年过去了。我觉得,我要和CSDN上其他码农一样,需要具有分享精神。。。。

本文是当时我想投稿的一个草稿,只是当时太嫩,不敢投论文。。而且马上就毕业了,所以就一直没了下文。现,贡献该草稿,希望对要了解AVL树算法的同学有帮助。



  曾金龙                  高一凡

(长安大学信息工程学院软件工程系)

摘要:AVL树是一种重要的数据结构,凡是能够用二叉查找树的地方都能用AVL树代替,而且其效率最坏也是AVL树删除算法的实现--长安大学毕业设计 AVL树删除算法的实现--长安大学毕业设计.一般的数据结构书上通常都只介绍AVL树的插入算法。本文将讨论AVL树删除算法的递归和非递归实现及其可视化实现。

 

关键字:AVL树;删除;递归;非递归;可视化

 

 

1.删除结点的分类

对于要删除的结点设为E可以分为三种类型,如图1 所示

(1) 叶子结点

(2) 没有左子树且有右子树的结点

(3) 有左子树的结点

 

AVL树删除算法的实现--长安大学毕业设计

    对于叶子结点E可以直接删除,而对于只有右子树ER的结点可以将ER的值赋给E然后将ER释放并将E右孩子指空。

    对于第(3)种则要在EL中找到E的中序遍历的前驱结点。E的前驱结点为EL中值最大的结点。将前驱结点的值赋给E且删除前驱结点。

 

2 删除结点后的失衡类性及其调整

删除结点后可能导致其祖先结点的不平衡。由于左右对称,我们仅分析删除发生在右子树的情况。我们将各种情况删除前,删除后以及调整后整个过程的变化用图示的方法表示。

 

AVL树删除算法的实现--长安大学毕业设计

  图2.1描述的是在T的右子树TR中删除结点后导致T失衡,须进行R_Rotate(T)处理,处理之后各结点的平衡因子如图所示,且树不变矮。

AVL树删除算法的实现--长安大学毕业设计

   图2.2描述的是在T的右子树TR中删除结点后导致T失衡,须进行R_Rotate(T)处理,处理之后各结点的平衡因子如图所示,且树的高度减1 。

AVL树删除算法的实现--长安大学毕业设计

  图2.3描述的是在T的右子树TR中删除结点后导致T失衡,须进行LR_Rotate(T)处理,处理之后各结点的平衡因子如图所示,且树的高度减1 。           

AVL树删除算法的实现--长安大学毕业设计

图2.4描述的是在T的右子树TR中删除结点后导致T失衡,须进行LR_Rotate(T)处理,处理之后各结点的平衡因子如图所示,且树的高度减1 。


AVL树删除算法的实现--长安大学毕业设计

图2.5描述的是在T的右子树TR中删除结点后导致T失衡,须进行LR_Rotate(T)处理,处理之后各结点的平衡因子如图所示,且树的高度减1 。  

另外还有两种不发生失衡的情况如图2.6和图2.7所示  

AVL树删除算法的实现--长安大学毕业设计

图2.6描述的是在T的右子树TR中删除结点后的T的平衡因子变为1,树的高度不变

AVL树删除算法的实现--长安大学毕业设计

图2.7描述的是在T的右子树TR中删除结点后的T的平衡因子变为0,树的高度减1.

3 实现算法

 3.1 数据结构

template<typename T>struct BSTNode//平衡二叉树的结点类型结构体

{

       T data;//结点数据类型

       int bf;//结点的平衡因子,比二叉链表结点多此项

       BSTNode<T>*lchild,*rchild;//左右孩子指针

};

 

3.2 算法

  3.2.1 递归法

递归实现AVL树的结点删除的思想如下。

   在AVL树T上删除值为E的结点步骤如下:

(1)若树T为空,返回0退出否则到(2);

(2)比较T的数据和E,若相等跳到(3),若E小于T->data跳到(4),若E大于T->data则跳到(5)

(3)分析T结点的类型

(3.1)若T是叶子结点则直接删除,树变矮即lower=1;

(3.2)若T只有右子树TR则将右子树结点的值赋给T,删除TR结点将T->rchild=NULL,lower=1;

(3.3)若T有左子树,则找到其中序遍历的前驱结点P,将P结点值用临时变量temp保存,并且用指针Tptr保存T;递归删除结点P;将Tptr所指结点即原T结点的值更新为temp;

  (4)在左子树T->lchild中递归删除值为E的结点,若删除成功检查左子树是否变矮即lower的值是否为1;若lower=0返回0退出;若lower=1则进行失衡调整各种情况上文有分析

  (5)在右子树T->rchild中递归删除值为E的结点,若删除成功检查左子树是否变矮即lower的值是否为1;若lower=0返回0退出;若lower=1则进行失衡调整,各种情况上文有分析

 

3.2.2非递归法

非递归的算法思想如下。

在AVL树T上删除值为E的结点的步骤如下:

初始化一个栈s ;

 (1) 若树T为空则返回0退出否则跳到(2);

 (2) p为工作指针p=T;比较p的数据和E,若相等则跳到(3),若E小于p->data则跳到(4),若E大于p->data则跳到(5)

 (3) 分析p结点的类型

           (3.1)若p是叶子结点则直接删除,树变矮,

(3.1.1)若p是其父结点的左子树则lower=1;

(3.1.2)若p是其父结点的右子树则lower=2;

           (3.2) 若p只有右子树pR则将右子树结点的值赋给p然后删除删除pR,树变矮,lower的值 和(3.1)一样分析,之后不再特别说明则都和(3.1)处理一样。

           (3.3) 若p有左子树pL则将p和pL入栈,且用指针tempptr指向p即tempptr=p然后执行

                   q=TL ; While(q->rchild){q=q->rchild;s.push(q);}之后可以找到p的前驱结点q,将q的值赋给原p结点即tempptr->data=q->data,若q是叶子结点则直接删除否则将q的左子树代替q。树变矮且弹栈s.pop() ;然后执行如下循环体

                       (3.3.1)若栈不空且lower不为0则执行

                                   a.弹栈 q=s.top();s.pop();及其q的父结点fa=s.top();

                                     若fa=NULL则表明q是根结点则若要执行下面 b

                                     或c时不用在给lower赋值了。

                                   b.若lower=1 则表明左子树变矮,执行相应的失衡调整,并且调整过程中若导致q树变矮也得根据q为fa的左子树还是右子树将 lower=1或为lower=2;

                                   c. 若lower=2 则表明右子树变矮,执行相应的失衡调整,并且调整过程中若导致q树变矮也得根据q为fa的左子树还是右子树将 lower=1或为lower=2;

                   退出循环后返回0退出;

 (4)将p入栈且p=p->lchild;然后跳到(2);

 (5)将p入栈且p=p->rchild;然后跳到(2);

 

 

4实例分析

 

有如图3.1所示的AVL树

AVL树删除算法的实现--长安大学毕业设计

                            图3.1 

选择删除61结点后如

AVL树删除算法的实现--长安大学毕业设计

 

 

5结束语

无论是递归还是非递归实现AVL树的删除都比较复杂,将其总结为算法并配以图形化的实现使得AVL树的在课堂上讲解更为方便,继而有力的推广AVL树的应用。

      

6参考文献

严蔚敏,吴伟民.数据结构(C语言版)[M].北京:清华大学出版社,2007.

 


上一篇:基于.NET CORE微服务框架 -谈谈surging API网关


下一篇:【NET CORE微服务一条龙应用】第三章 认证授权与动态权限配置