平衡二叉树也叫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;
}