AVL的插入,删除操作

在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

AVL树可以是空树,也可以是具有以下性质的树:
(1):他的左右子树都是AVL树
(2):左子树和右子树高度之差(平衡因子)的绝对值不超过1

特点:
AVL树本质上还是一棵二叉搜索树,它的特点是:
1.本身首先是一棵二叉搜索树。
2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。
也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

操作:

旋转

AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的”AVL 旋转”。
假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点的指针为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行进行的规律可归纳为下列四种情况:

单向左旋平衡处理R:由于在*a的右子树根结点的右子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行一次左旋转操作;

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

单向右旋平衡处理L:由于在*a的左子树根结点的左子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行一次右旋转操作;

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

双向旋转(先左后右)平衡处理LR:由于在*a的左子树根结点的右子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行两次旋转(先左旋后右旋)操作。

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

双向旋转(先右后左)平衡处理RL:由于在*a的右子树根结点的左子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

插入

在向一棵本来高度平衡的AVL树中插入一个新节点时,如果树中某个结点的平衡因子的绝对 值>1,则出现了不平衡。设新插入结点为P,从结点P到根节点的路径上,每个结点为根的子 树的高度都可能增加1,因此在每执行一次二叉搜索树的插入运算后,都需从新插入的结点 P开始,沿该结点插入的路径向根节点方向回溯,修改各结点的平衡因子,调整整棵树的高 度,恢复被破坏的平衡性质。

在AVL树中插入结点P(key)结点算法:

步骤一:如果是空树,插入后即为根节点,插入后直接返回
步骤二:如果树不空,寻找插入位置,若在寻找的过程中找到key,则插入失败直接返回
步骤三:插入结点
步骤四:更新平衡因子,对树进行调整

新节点P的平衡因子为0,但其双亲结点Pr的平衡因子有三种情况:

1、结点Pr的平衡因子为0 在Pr的较矮的子树上插入新节点,结点Pr平衡,其高度没有增加,此时从Pr到根路径
上各结点为根的子树的高度不变,即各结点的平衡因子不变,结束平衡化处理。

2、结点Pr的平衡因子的绝对值为1;    插入前Pr的平衡因子为0,插入后以Pr为根的子树没有失去平衡,但该子树的高度增
    加,需从该结点Pr向根节点方向回溯,继续查看Pr的双亲结点的平衡性。

3、结点Pr的平衡因子的绝对值为2
新节点在较高的子树插入,需要做平衡化处理:
若Pr =2,说明右子树高,设Pr的右子树为q
当q的平衡因子为1,执行左单旋转
当q的平衡因子为-1,执行先右后左双旋转
若Pr = -2,说明左子树高,设Pr的左子树为q
当q的平衡因子为-1,执行右单旋转
当q的平衡因子为1,执行先左后右双旋转
旋转后Pr为根的子树高度降低,无需继续向上层回溯

*

删除:

从AVL树中删除一个节点,首先必须检测该结点是否存在,若存在删除该结点之后可能会破 坏AVL树的高度平衡,因此需要做平衡化旋转。
被删除的结点P存在以下情况:

1、被删除的结点P有两个孩子
首先搜索P在中序遍历中的直接前驱q(或直接后继)。再把结点q的内容传送给P,问题由删除节点P转移到删除节点q,它是只有一个孩子的结点。

2、被删除的结点P最多只有一个孩子q
把P的双亲结点Pr中原来指向P的指针该指向q;如果P没有孩子,直接将Pr的相应指针 置为NULL。然后将原来以Pr为根的子树的高度减1,并沿Pr通向根的路径反向追踪高度的变化对路径上的各个结点的影响。

考查结点q的双亲结点P,若q是Pr的左孩子,则Pr的平衡因子增加1,否则减少1,根据修改后的 Pr的平衡因子值,分三种情况处理:

1、Pr平衡因子原来为0,在其左(或右)子树删除结点后,它的平衡因子增加(减少)1,Pr高度不变,因此从Pr到根所有节点高度均不变,不用调整。

2、Pr原来的平衡因子不为0,且较高的子树被缩短,Pr的平衡因子变成0,此时Pr为根的子 树平衡,其高度减1,但需要检查Pr的双亲结点的平衡性。

3、结点Pr的平衡因子不为0,且交矮子树被缩短,则Pr发生不平衡,需要进行平衡化旋转令使其平衡。令Pr较高子树的根为q,根据q的平衡因子,分一下三种情况
a、如果q的平衡因子为0,执行单旋转恢复Pr
b、如果q的平衡因子与Pr平衡因子(正负)号相同,则执行一个单旋转恢复Pr
c、如果q的平衡因子与Pr平衡因子(正负)号相反,则执行一个双旋转恢复Pr

代码实现:

#include<iostream>  

using namespace std;  

template<class K,class V>  
struct AVLtreeNode    //结点结构体  
{  
    typedef AVLtreeNode<K, V> Node;  
    Node* _pLeft;  
    Node* _pRight;  
    Node* _pParent;  

    K _key;  
    V _value;  
    int _bf;  
    AVLtreeNode(const K& key,const V& value)  
        :_key(key)  
        , _value(value)  
        , _pLeft(NULL)  
        , _pRight(NULL)  
        , _pParent(NULL)  
        , _bf(0)    //平衡因子  
    {}  
};  

template<class K,class V>  
class AVLtree  
{  
    typedef AVLtreeNode<K, V> Node;  
public:  
    AVLtree()  
        :_pRoot(NULL)  
    {
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值