平衡二叉树的使用

平衡二叉树也叫AVL树

我记得严蔚敏老师的书上写平衡二叉树旋转写得特别乱,她说了各种向左逆时针顺时针等等。。

下面说点理解起来比较简单的

1、首先是LL型,对于LL型指的是不平衡(平衡因子绝对值大于1)节点的左子树的左节点放入了新的节点。

处理办法:对不平衡节点进行右旋转,其实是先把不平衡节点的左子树放到它的位置,然后不平衡节点当作它左子树的右节点,如果它的左子树原来就存在右节点,那么把该右节点作为原来不平衡节点的左节点。如图:


2、对于RR型,解释起来正好与LL型相反,如图。


3、对于LR型,就是先L再R,注意LL型是R,不要记混。这里的L是对于不平衡节点的左子树进行L,然后再对于原不平衡节点进行R,知道为什么吗?因为对于不平衡节点L以后,本身依旧不平衡,只是此时变成了LL型,所以要R。只要分清对谁L对谁R就行了。如图:(图比较差劲)


4、对于RL型就和LR型完全镜像了。。如图

下面介绍它的插入和删除操作,网上看到了一个神作,我就把它摘下来供大家研究:

//下面内容属于转载,原作地址看不到了。

插入和删除

    在AVL树插入和删除,实际上就是先按照普通二叉搜索树插入和删除,然后再平衡化。可以肯定的说,插入和删除需要的最多平衡化次数不同(下面会给出根本原因),但这不表明插入和删除时的平衡化的思路有很大差别。现有的教科书,仅仅从表面上看到了到了平衡化操作次数不同的假象,而没有从根本上认识到插入和删除对称的本质,搞得乱七八糟不说(铺天盖地的switch…case),还严重的误导了读者——以为删除操作复杂的不可捉摸。

AVL树体现了一种平衡的美感,两种旋转是互为镜像的,插入删除是互为镜像的操作,没理由会有那么大的差别。实际上,平衡化可以统一的这样来操作:

1.    while (current != NULL)修改current的平衡因子。

?         插入节点时current->bf += (current->data > *p)?1:-1;

?         删除节点时current->bf -= (current->data > *p)?1:-1;

?         current指向插入节点或者实际删除节点的父节点,这是普通二叉搜索树的插入和删除操作带来的结果。*p初始值是插入节点或者实际删除节点的data。因为删除操作可能实际删除的不是data。

2.    判断是否需要平衡化

if (current->bf == -2) L_Balance(c_root); else if (current->bf == 2) R_Balance(c_root);

3.    是否要继续向上修改父节点的平衡因子

?         插入节点时if (!current->bf) break;这时,以current为根的子树的高度和插入前的高度相同。

?         删除节点时if (current->bf) break;这时,以current为根的子树的高度和删除前的高度相同

?         之所以删除操作需要的平衡化次数多,就是因为平衡化不会增加子树的高度,但是可能会减少子树的高度,在有有可能使树增高的插入操作中,一次平衡化能抵消掉增高;在有可能使树减低的删除操作中,平衡化可能会带来祖先节点的不平衡

4.    当前节点移动到父节点,转1

p = &(current->data); current = current->parent;

完整的插入删除函数如下:

bool insert(const T &data)

{

       if (!BSTree<T>::insert(data)) return false; const T* p = &data;

       while (current)

       {

              current->bf += (current->data > *p)?1:-1;

              if (current->bf == -2) L_Balance(c_root);

              else if (current->bf == 2) R_Balance(c_root);

              if (!current->bf) break;

              p = &(current->data); current = current->parent;

       }

       return true;

}

bool remove(const T &data)

{

       if (!BSTree<T>::remove(data)) return false; const T* p = &r_r_data;

//在class BSTree里添加proteceted: T r_r_data,在BSTree<T>::remove(const T &data)里修改为实际删除的节点的data

       while (current)

       {

              current->bf -= (current->data > *p)?1:-1;

              if (current->bf == -2) L_Balance(c_root);

              else if (current->bf == 2) R_Balance(c_root);

              if (current->bf) break;

              p = &(current->data); current = current->parent;

       }

       return true;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值