首页 > 其他分享 >AVL添加和删除结点

AVL添加和删除结点

时间:2023-11-22 21:36:33浏览次数:29  
标签:lchild 左子 结点 temp getHeight AVL 添加 rchild data

删除

虽然,二叉排序树的插入都在叶子节点,但是删除却可以分为三种不同的情况;

(1)删除的节点刚好是叶子结点——直接删除

1 if ((*T)->lchild == NULL && (*T)->rchild == NULL)
2         {
3             //为叶子结点,直接删除
4             TreeNode* temp = *T;
5             *T = NULL;
6             free(temp);
7             return;//直接返回上一次循环去判断
8         }

(2)删除的节点只有左孩子或者只有右孩子,直接让其唯一的那个孩子去替代父母的位置

 1 else if ((*T)->lchild == NULL && (*T)->rchild) 
 2         {
 3             //删除结点没有左子树,将右子树上移就可以
 4             TreeNode* temp = *T;
 5             *T = (*T)->rchild;
 6             free(temp);
 7             return;
 8         }
 9         else if ((*T)->rchild == NULL && (*T)->lchild)
10         {
11             //删除结点没有右子树,将左子树上移就可以
12             TreeNode* temp = *T;
13             *T = (*T)->lchild;
14             free(temp);
15             return;
16         }

(3)删除的节点既有左孩子又有右孩子,两种删除方法

①左子树“上位”,右子树合并到左子树,因为右子树上节点肯定都比左子树上的大,所以把右子树的根接到左子树的最右下(对应下面的方法2)

②左子树最右下角作为最接近被删节点的节点之一,可以直接替代子树的父母(左子树最大直上位)

 

 1 else if ((*T)->lchild&& (*T)->rchild) 
 2         {
 3             //左右子树都存在
 4             if (getHeight((*T)->lchild) > getHeight((*T)->rchild))
 5             {
 6                 //.找到左子树中的最大值,将值赋给给节点,然后将左子树最大值这个节点删除
 7                 TreeNode* temp = Getmax((*T)->lchild);
 8                 int maxnode = temp->data;
 9                 (*T)->data = maxnode;
10                 deletenode(&(*T)->lchild, maxnode);
11             }
12             else
13             {
14                 //寻找后继节点post。
15                 TreeNode* post = (*T)->rchild;
16                 while (post->lchild)
17                     post = post->lchild;
18                 //用post替换*T。
19                 (*T)->data = post->data;
20 
21                 //删除节点post。
22                 //虽然能够确定post所属最小子树的根结点为&post,
23                 //但是不采用AVLDelete(&post,post->data)删除post,目的是方便递归更改节点的高度。
24                 deletenode(&((*T)->rchild), post->data);
25             }
26             return;
27         }

 

删除节点为叶节点。这种情况最简单,直接将其置空,释放,然后返回给父节点即可。
删除节点有左子树没有右子树。 先保存该节点的地址(方便释放),将该节点直接等于左子树地址, 相当于该节点存的就是左子树的地址,将原来节点地址覆盖了。然后释放。
删除节点有右子树没有左子树 。与2处理相同,只是将左子树换为右子树。
既有左子树又有右子树
可以有两种解决办法:
1.找到左子树中的最大值,将值赋给给节点,然后将左子树最大值这个节点删除(删除可以用递归实现)
2.找到左子树中的最小值,将值赋给给节点,然后将右子树最小值这个节点删除
当然这样会有个弊端:当一直删除时,会导致树高度失衡,导致一边高,一边低,解决这样的办法可以删除左右子树最大最小节点交替实行。或者记录一高度,主要删除,左子树或者右子树高的那一边。

平衡化(看每个图片右下角)

因为二叉排序树有变成单只树(线性表)的风险,为了保证二叉排序树的效率与log2n同数量级,所以要将二叉排序树调成平衡二叉树。
平衡二叉树:根结点的左子树深度-右子树深度的绝对值不超过1。
不平衡共有以下四种情况
平衡化关键是:找到最小的非平衡二叉树的根其平衡因子绝对值一定是2,则其之前的平衡因子绝对值一定为1,分清除不平衡的类型
(1)最小的非平衡二叉树的根(A)的左子树(AL)的左子树上加了节点导致其不平衡简称(LL型)
做法:AL上去,A下来作为AL的右孩子,AL原本的右孩子作为A的左孩子

 

1 void llRotation(TreeNode* node, TreeNode** root)
2 {
3     TreeNode* temp = node->lchild;
4     node->lchild = temp->rchild;
5     temp->rchild = node;
6     node->height = max(getHeight(node->lchild), getHeight(node->rchild)) + 1;
7     temp->height = max(getHeight(temp->lchild), getHeight(temp->rchild)) + 1;
8     *root = temp;
9 }

(2)RR型
做法:AR上去,A下来作为AR的左孩子,AR原本的左孩子作为A的右孩子

1 void rrRotation(TreeNode* node, TreeNode** root)
2 {
3     TreeNode* temp = node->rchild;
4     node->rchild = temp->lchild;
5     temp->lchild = node;
6     node->height = max(getHeight(node->lchild), getHeight(node->rchild)) + 1;
7     temp->height = max(getHeight(temp->lchild), getHeight(temp->rchild)) + 1;
8     *root = temp;
9 }

(3)LR型
①ALR(A的左孩子的右孩子)上去;②AL作为ALR的左孩子,ALR左孩子放到AL的右孩子;③A作为ALR的右孩子,ALR的右孩子放到A的左孩子。

1 //LR调整
2                 rrRotation((*T)->lchild, &(*T)->lchild);
3                 llRotation(*T, T);

(4)RL型
①ARL(A的右孩子的右孩子)上去;②AR作为ALR的右孩子,ARL右孩子放到AR的右孩子;③A作为ARL的左孩子,ARL的左孩子放到A的右孩子。

1 //RL调整
2                 llRotation((*T)->rchild, &(*T)->rchild);
3                 rrRotation(*T, T);

 

 

 

 

插入(判断什么型的判断条件注意)

 1 void avlInsert(TreeNode** T, int data)
 2 {
 3     if (*T == NULL)
 4     {
 5         *T = (TreeNode*)malloc(sizeof(TreeNode));
 6         (*T)->data = data;
 7         (*T)->height = 0;
 8         (*T)->lchild = NULL;
 9         (*T)->rchild = NULL;
10     }
11     else if (data < (*T)->data)
12     {
13         avlInsert(&(*T)->lchild, data);
14 
15         int lHeight = getHeight((*T)->lchild);
16         int rHeight = getHeight((*T)->rchild);
17 
18         //计算高度差=平衡因子,左右子树不平衡就调整
19         if (lHeight - rHeight == 2)
20         {
21             if (data < (*T)->lchild->data)
22                 //LL调整
23                 llRotation(*T, T);
24             else
25             {
26                 //LR调整
27                 rrRotation((*T)->lchild, &(*T)->lchild);
28                 llRotation(*T, T);
29             }
30         }
31     }
32     else if (data > (*T)->data)
33     {
34         avlInsert(&(*T)->rchild, data);
35 
36         int lHeight = getHeight((*T)->lchild);
37         int rHeight = getHeight((*T)->rchild);
38 
39         //计算高度差=平衡因子,左右子树不平衡就调整
40         if (lHeight - rHeight == -2)
41         {
42             if (data > (*T)->rchild->data)
43                 //RR调整
44                 rrRotation(*T, T);
45             else
46             {
47                 //RL调整
48                 llRotation((*T)->rchild, &(*T)->rchild);
49                 rrRotation(*T, T);
50             }
51         }
52     }
53     //更新树结点的高度
54     (*T)->height = max(getHeight((*T)->lchild), getHeight((*T)->rchild)) + 1;
55 }

删除(重点看如何平衡化的,判断什么型最关键)

void deletenode(TreeNode** T, int key)
{
    if ((*T) == NULL)
    {
        cout << "不存在" << key << endl;
        return;
    }
    else if ((*T)->data == key)
    {
       //文章前面有
    }
    else if ((*T)->data > key)
    {
        deletenode(&(*T)->lchild, key);

        //更新树结点的高度
        (*T)->height = max(getHeight((*T)->lchild), getHeight((*T)->rchild)) + 1;

        int lHeight = getHeight((*T)->lchild);
        int rHeight = getHeight((*T)->rchild);

        //计算高度差=平衡因子,左右子树不平衡就调整
        if (lHeight - rHeight == -2)
        {
            if (getHeight((*T)->rchild->lchild) - getHeight((*T)->rchild->rchild) == -1)
                //RR调整
                rrRotation(*T, T);
            else
            {
                //RL调整
                llRotation((*T)->rchild, &(*T)->rchild);
                rrRotation(*T, T);
            }
        }
    }
    else if ((*T)->data < key)
    {
        deletenode(&(*T)->rchild, key);

        //更新树结点的高度
        (*T)->height = max(getHeight((*T)->lchild), getHeight((*T)->rchild)) + 1;

        int lHeight = getHeight((*T)->lchild);
        int rHeight = getHeight((*T)->rchild);

        //计算高度差=平衡因子,左右子树不平衡就调整
        if (lHeight - rHeight == 2)
        {
            if (getHeight((*T)->lchild->lchild) - getHeight((*T)->lchild->rchild) == 1)
                //LL调整
                llRotation(*T, T);
            else
            {
                //LR调整
                rrRotation((*T)->lchild, &(*T)->lchild);
                llRotation(*T, T);
            }
        }
    }
    
}

 

标签:lchild,左子,结点,temp,getHeight,AVL,添加,rchild,data
From: https://www.cnblogs.com/saucerdish/p/17850340.html

相关文章

  • android studio 添加按钮事件实现加一操作
    androidstudio添加按钮事件实现加一操作要在AndroidStudio中为按钮添加一个加一(+1)的操作,你可按照下列步骤实现:通过在XML布局中添加按钮,导入一个Button组件: XML复制代码<Buttonandroid:id="@+id/add_button"android:layout_width="wrap_content"andro......
  • 添加索引 yii获取sql
    //添加索引sqlALTERTABLE`work_map`ADDINDEXidx_wmp_region_id(`wmp_region_id`)仓库工作单方案准备列表,展示角色所配置城市的工作单信息短信消息模版调整gitremoteupdateorigin--pruneyii2获取当前sql$query->createCommand()->getRawSql();......
  • 我的世界1.20.1模组开发---9.添加作物
    介绍  这次我们来添加以下作物,类似于马铃薯、小麦之类的农作物,当我们种下种子后就会慢慢生长,当长到成熟阶段后,破坏农作物我们可以获取到对应的种子和果实。这次我们来添加一个玉米作物,大致流程就是种下玉米种子后等待一定时间后就会成熟,我们破坏掉成熟的作物后,就会掉落玉米和玉......
  • 如何在Python中向一个集合添加值
    用Set.add()函数向一个集合只添加一个值从数学上讲,集合是一个在逻辑上有联系的不同对象的集合。在Python中,集合是一个内置的数据类型,它是无索引的和不可变的。这意味着我们可以通过一些特定的索引来访问集合项,而且我们不能修改集合内的现有数据。我们可以通过在Python中创建一个......
  • Linux系统用户如何添加到用户组
    新增一个用户并添加到指定用户组#检查用户组是否存在,如果组存在则会输出组信息,否则没有任何输出grep<用户组名称>/etc/group#如果用户组不存在则使用如下命令新建用户组:groupadd<用户组名称>#新建用户并将其加入指定用户组,作为其主用户组(每个用户有且只有一个主用户组)useradd......
  • C语言数据结构_查找并删除单链表中最大值结点并返回值
    代码实现1#include<stdio.h>2#include<stdlib.h>34typedefstructNode//定义一个结构体5{6floatdata;7structNode*next;8}Node;910Node*Chuangzao_LinkedList()//创建一个链表11{12Node*head=NULL;//......
  • 2023-11-21 hexo next主题 如何在博客网站底部添加备案号
    主题:NexT.Pisces v5.1.4找到路径:博客目录名称\themes\hexo-theme-next\layout\_partials找到文件:footer.swig,并在里面添加备案号,如图:未改变前:<divclass="copyright">{##}{%setcurrent=date(Date.now(),"YYYY")%}{##}&copy;{%iftheme.footer.since......
  • C# 动态类添加属性
    1.定义JsonDataObject publicsealedclassJsonDataObject:DynamicObject{privatereadonlyDictionary<string,object>_properties;publicJsonDataObject(Dictionary<string,object>properties){_properties=properties;......
  • element-ui全局添加加载遮罩层
    创建loading.js文件import{Loading}from'element-ui';letloadingCount=0;letloading;conststartLoading=()=>{loading=Loading.service({lock:false,spinner:'el-icon-loading',background:'rgba(0,0,0,.5)......
  • 资深运营在公众号文章中添加附件的方法
    微附件支持用户上传多种格式的文件到其平台,并生成一个可在公众号中使用的链接。读者点击该链接便可直接下载或查看附件,实现了信息传递和共享的便利。通过提供这种专业、全面且对用户友好的附件服务,微附件不仅拓展了微信公众号的功能,还增强了公众号与用户的互动体验,成为信息传递中......