平衡二叉树AVL删除

平衡二叉树AVL删除

平衡二叉树的插入过程: http://www.cnblogs.com/hujunzheng/p/4665451.html

对于二叉平衡树的删除采用的是二叉排序树删除的思路:

  假设被删结点是*p,其双亲是*f,不失一般性,设*p是*f的左孩子,下面分三种情况讨论:
⑴ 若结点*p是叶子结点,则只需修改其双亲结点*f的指针即可。
⑵ 若结点*p只有左子树PL或者只有右子树PR,则只要使PL或PR 成为其双亲结点的左子树即可。
⑶ 若结点*p的左、右子树均非空,先找到*p的中序前趋结点*s(注意*s是*p的左子树中的最右下的结点,它的右链域为空),然后有两种做法:
① 令*p的左子树直接链到*p的双亲结点*f的左链上,而*p的右子树链到*p的中序前趋结点*s的右链上。
② 以*p的中序前趋结点*s代替*p(即把*s的数据复制到*p中),将*s的左子树链到*s的双亲结点*q的左(或右)链上。

注:leftBalance_del 和 rightBalance_del方法是在删除节点时对左子树和右子树的平衡调整,leftBalance 和 rightBalance方法是在插入节点是对左右子树的平衡调整。 在具体调整的时候,和插入式调整时运用同样的分类方法,这里介绍一种情况,如下图所示(代码部分见代码中的提示)

 

平衡二叉树AVL删除


#include<iostream> #include<cstring> #include<string> #include<queue> #include<map> #include<cstdio> #define LH 1 //左高 #define EH 0 //等高 #define RH -1 //右高 using namespace std; template <typename ElemType> class BSTNode{ public: ElemType data;//节点的数据 int bf;//节点的平衡因子 BSTNode *child[2]; BSTNode(){ child[0] = NULL; child[1] = NULL; } }; typedef BSTNode<string> BSTnode, *BSTree; template <typename ElemType> class AVL{ public: BSTNode<ElemType> *T; void buildT(); void outT(BSTNode<ElemType> *T); void deleteAVL(BSTNode<ElemType>* &T, ElemType key, bool &shorter); bool insertAVL(BSTNode<ElemType>* &T, ElemType key, bool &taller); private: void deleteNode(BSTNode<ElemType>* T, BSTNode<ElemType>* &s, BSTNode<ElemType>* p, bool flag, bool &shorter); void rotateT(BSTNode<ElemType>* &o, int x);//子树的左旋或者右旋 void leftBalance(BSTNode<ElemType>* &o); void rightBalance(BSTNode<ElemType>* &o); void leftBalance_del(BSTNode<ElemType>* &o); void rightBalance_del(BSTNode<ElemType>* &o); }; template <typename ElemType> void AVL<ElemType>::rotateT(BSTNode<ElemType>* &o, int x){ BSTNode<ElemType>* k = o->child[x^1]; o->child[x^1] = k->child[x]; k->child[x] = o; o = k; } template <typename ElemType> void AVL<ElemType>::outT(BSTNode<ElemType> *T){ if(!T) return; cout<<T->data<<" "; outT(T->child[0]); outT(T->child[1]); } template <typename ElemType> void AVL<ElemType>::buildT(){ T = NULL; ElemType key; while(cin>>key){ if(key==0) break; bool taller = false; insertAVL(T, key, taller); } } template <typename ElemType> void AVL<ElemType>::deleteNode(BSTNode<ElemType>* T, BSTNode<ElemType>* &s, BSTNode<ElemType>* p, bool flag, bool &shorter){ if(flag){ flag = false; deleteNode(T, s->child[0], s, flag, shorter); if(shorter){ switch(s->bf){ case LH: s->bf = EH; shorter = false; break; case EH: s->bf = RH; shorter = true; break; case RH: rightBalance_del(s); shorter = false; break; } } } else { if(s->child[1]==NULL){ T->data = s->data; BSTNode<ElemType>* ss = s; if(p != T){ p->child[1] = s->child[0]; } else { p->child[0] = s->child[0]; } delete ss;//s是引用类型,不能delete s shorter = true; return ; } deleteNode(T, s->child[1], s, flag, shorter); if(shorter){ switch(s->bf){ case LH://这是上面配图的情况 leftBalance_del(s); shorter = false; break; case EH: s->bf = LH; shorter = true; break; case RH: s->bf = EH; shorter = false; break; } } } } template <typename ElemType> bool AVL<ElemType>::insertAVL(BSTNode<ElemType>* &T, ElemType key, bool &taller){ if(!T){//插入新的节点,taller=true 那么树的高度增加 T = new BSTNode<ElemType>(); T->data = key; T->bf = EH; taller = true; } else { if(T->data == key){ taller = false; return false; } if(T->data > key){//向T的左子树进行搜索并插入 if(!insertAVL(T->child[0], key, taller)) return false; if(taller){// switch(T->bf){ case LH://此时左子树的高度高,左子树上又插入了一个节点,失衡,需要进行调整 leftBalance(T); taller = false;//调整之后高度平衡 break; case EH: T->bf = LH; taller = true; break; case RH: T->bf = EH; taller = false; break; } } } if(T->data < key) {//向T的右子树进行搜索并插入 if(!insertAVL(T->child[1], key, taller)) return false; switch(T->bf){ case LH: T->bf = EH; taller = false; break; case EH: T->bf = RH; taller = true; break; case RH: rightBalance(T); taller = false; break; } } } return true; } template <typename ElemType> void AVL<ElemType>::deleteAVL(BSTNode<ElemType>* &T, ElemType key, bool &shorter){ if(T->data == key){ BSTNode<ElemType>*q, s; if(!T->child[1]){//右子树为空,然后重接其左子树 q = T; T = T->child[0]; shorter = true;//树变矮了 delete q; } else if(!T->child[0]){//左子树为空,重接其右子树 q = T; T = T->child[1]; shorter = true;//树变矮了 delete q; } else {//左右子树都非空 ,也就是第三种情况 deleteNode(T, T, NULL, true, shorter); shorter = true; } } else if(T->data > key) {//左子树 deleteAVL(T->child[0], key, shorter); if(shorter){ switch(T->bf){ case LH: T->bf = EH; shorter = false; break; case RH: rightBalance_del(T); shorter = false; break; case EH: T->bf = RH; shorter = true; break; } } } else if(T->data < key){//右子树 deleteAVL(T->child[1], key, shorter); if(shorter){ switch(T->bf){ case LH://这是上面配图的情况 leftBalance_del(T); shorter = false; break; case RH: T->bf = EH; shorter = false; break; case EH: T->bf = LH; shorter = true; break; } } } } template <typename ElemType> void AVL<ElemType>::leftBalance(BSTNode<ElemType>* &T){ BSTNode<ElemType>* lchild = T->child[0]; switch(lchild->bf){//检查T的左子树的平衡度,并作相应的平衡处理 case LH://新节点 插入到 T的左孩子的左子树上,需要对T节点做单旋(右旋)处理 T->bf = lchild->bf = EH; rotateT(T, 1); break; case RH://新节点 插入到 T的左孩子的右子树上,需要做双旋处理 1.对lchild节点进行左旋,2.对T节点进行右旋 BSTNode<ElemType>* rdchild = lchild->child[1]; switch(rdchild->bf){//修改 T 及其左孩子的平衡因子 case LH: T->bf = RH; lchild->bf = EH; break; case EH: T->bf = lchild->bf = EH; break;//发生这种情况只能是 rdchild无孩子节点 case RH: T->bf = EH; lchild->bf = LH; break; } rdchild->bf = EH; rotateT(T->child[0], 0);//不要写成 rotateT(lc, 0);//这样的话T->lchild不会改变 rotateT(T, 1); break; } } template <typename ElemType> void AVL<ElemType>::rightBalance(BSTNode<ElemType>* &T){ BSTNode<ElemType>* rchild = T->child[1]; switch(rchild->bf){//检查T的左子树的平衡度,并作相应的平衡处理 case RH://新节点 插入到 T的右孩子的右子树上,需要对T节点做单旋(左旋)处理 T->bf = rchild->bf = EH; rotateT(T, 0); break; case LH://新节点 插入到 T的右孩子的左子树上,需要做双旋处理 1.对rchild节点进行右旋,2.对T节点进行左旋 BSTNode<ElemType>* ldchild = rchild->child[0]; switch(ldchild->bf){//修改 T 及其右孩子的平衡因子 case LH: T->bf = EH; rchild->bf = RH; break; case EH: T->bf = rchild->bf = EH; break;//发生这种情况只能是 ldchild无孩子节点 case RH: T->bf = LH; rchild->bf = EH; break; } ldchild->bf = EH; rotateT(T->child[1], 1); rotateT(T, 0); break; } } template <typename ElemType> void AVL<ElemType>::leftBalance_del(BSTNode<ElemType>* &T){ BSTNode<ElemType>* lchild = T->child[0]; switch(lchild->bf){ case LH: T->bf = EH; lchild->bf = EH; rotateT(T, 1); break; case EH: T->bf = LH; lchild->bf = EH; rotateT(T, 1); break; case RH://这是上面配图的情况 BSTNode<ElemType>* rdchild = lchild->child[1]; switch(rdchild->bf){ case LH: T->bf = RH; lchild->bf = rdchild->bf = EH; break; case EH: rdchild->bf = T->bf = lchild->bf = EH; break; case RH: T->bf = rdchild->bf = EH; lchild->bf = LH; break; } rotateT(T->child[0], 0); rotateT(T, 1); break; } } template <typename ElemType> void AVL<ElemType>::rightBalance_del(BSTNode<ElemType>* &T){ BSTNode<ElemType>* rchild = T->child[1]; BSTNode<ElemType>* ldchild = rchild->child[0]; switch(rchild->bf){ case LH: switch(ldchild->bf){ case LH: ldchild->bf = T->bf = EH; rchild->bf = RH; break; case EH: ldchild->bf = T->bf = rchild->bf = EH; break; case RH: rchild->bf = T->bf = EH; ldchild->bf = LH; break; } rotateT(T->child[1], 1); rotateT(T, 0); break; case EH: //outT(this->T);e EH: T->bf = RH; rchild->bf = EH; rotateT(T, 0); break; case RH: T->bf = EH; rchild->bf = EH; rotateT(T, 0); break; } } int main(){ AVL<int> avl; avl.buildT(); cout<<"平衡二叉树先序遍历如下:"<<endl; avl.outT(avl.T); cout<<endl; bool shorter = false; avl.deleteAVL(avl.T, 24, shorter); avl.outT(avl.T); return 0; } /* 24 37 90 53 0 24 37 90 53 12 26 0 */

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/109047.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 数据建模与数仓建模_数仓建模的几种方式

    数据建模与数仓建模_数仓建模的几种方式数据模型是抽象描述现实世界的**一种工具和方法**,是通过抽象的实体及真实的实体之间**联系的形式**,来表示现实世界中事务的相互关系的一种映射(也就是说模型对应着显示世界的一组关系或者一个事物)在这里,数据模型表现的抽象的是实体和实体之间的关系,**通过对实体和实体之间关系的定义和描述,来表达实际的业务中具体的业务关系**。所以总结下来,数据模型是用来描述数据、组织数据和对数据进行操作,是对现实世界数据特征的描述。其实就像是函数一样,例如给你一批数据让你分析,这个时候最好的方式是能建立一个数学模型

    2025年6月6日
    2
  • 面试题—5种单例模式写法以及单线程和多线程下的区别

    面试题—5种单例模式写法以及单线程和多线程下的区别闲来无事看之前的博客,发现单例模式只会写2中。所以再重新开一篇博客,将目前自己所能理解的几种单例模式全部总结下。______________________________________________________________________________________________________________________1、懒汉式(最基本的) 单线程版写单例模式(饿汉式)的步骤: 1):必须在该类中,自己先创建出一个对象。 2):私有化自身的…

    2022年6月13日
    28
  • pip怎么卸载安装包_pip卸载所有库

    pip怎么卸载安装包_pip卸载所有库$pip2installxxx$pip2unstallxxx

    2022年8月30日
    3
  • js保留两位小数四舍五入_js保留两位小数不四舍五入

    js保留两位小数四舍五入_js保留两位小数不四舍五入首先我们来看2个方法:1、tofixed方法toFixed()方法可把Number四舍五入为指定小数位数的数字。但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则。银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。如…

    2025年6月19日
    2
  • 四足机器人|机器狗|仿生机器人|多足机器人|Adams仿真|Simulink仿真|基于CPG的四足机器人Simulink与Adams虚拟样机|源码可直接执行|绝对干货!需要资料及指导的可以联系我!

    四足机器人|机器狗|仿生机器人|多足机器人|Adams仿真|Simulink仿真|基于CPG的四足机器人Simulink与Adams虚拟样机|源码可直接执行|绝对干货!需要资料及指导的可以联系我!四足机器人、行走控制。附带源码及虚拟样机设计方案。针对目前仿生四足机器人控制中存在的稳定性低、控制精度不高、可控性差等问题,本文引入一种基于CPG(中央模式发生器)的步态控制算法模型,CPG生成的节律运动具有独立性与稳定性,还具有反馈调整功能,对波形调制处理后,能够实现仿生机器人的前进、后退、转弯、侧移、原地踏步等运动控制。针对仿生机器人研发周期长与成本高的问题,本课题利用Simulink与Adams构建虚拟样机对步态控制模型进行联合仿真验证。

    2022年5月2日
    65
  • cuda卸载与安装

    cuda卸载与安装cuda卸载1.正常卸载操作在cuda的安装目录下,有卸载脚本1.运行卸载脚本cd/usr/local/cuda/binsudo./uninstall_cuda_9.0.pl2.删除安装文件夹sudorm-rfcudasudorm-rcuda-9.0找不到uninstall的卸载操作1.正常卸载操作sudoapt-get–purgeremovecuda:卸载软件及其配置sudoapt-getautoremovecuda

    2025年9月22日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号