在介绍二叉搜索树的最后,我们提到,二叉搜索树可能会出现退化为链表的情况。在此情况下,二叉树的高度并没有因为这一数据结构的使用而带来任何减小,类似的情况下,二叉搜索树的高度也不令人满意。因此,我们需要引入AVL树来帮助解决类似“树的退化”这一问题。
AVL树的定义为每个节点的左子树和右子树的高度最多差1的二叉查找树。在这种限制下,AVL树的高度在渐进的意义上为log N。
我们不难预料到,在进行插入,删除操作后,AVL树很可能存在一个或一些节点失去“平衡性“,即这一个或这些节点的左右子树高度相差大于1。为维护AVL树的平衡性,我们需要对AVL树中的部分节点进行“重平衡”操作。我们介绍34重构这种方法,并对34重构进行实现。
首先,我们注意到,对于任何一个进行插入、删除操作前的AVL树,它应当是平衡的,因为每一次操作后都对AVL进行了重平衡操作。因此,我们只需要考虑当前的操作会引起的树的不平衡情况。
其次,我们不难发现,对一个节点的插入(此处节点指被插入节点的父结点)和删除(此处节点指被删除的节点)操作,引起的不平衡情况总是发生在该节点的父结点及其之上的父结点中。因为对该节点进行插入和删除操作并不会影响到其子树上的任何内容。
第三点,我们发现,任何一个需要被重平衡的节点下至少由两个节点(并不是两个子结点,而是由这个被重平衡的节点作为根节点的子树中至少有两个不包括根节点的节点)构成,否则不会出现不平衡的情况。
我们知道,在单、双旋转的办法中,我们把需要重平衡的情况分为四种,分别是left-left、left-right、right-left、right-right。无论这四种情况的操作方法如何,其目的是平衡节点。34重构便是直接以目标为导向的方法,这使得我们不再需要考虑单双旋转过程中很多指针的问题。
那么,34重构中的3、4分别代表什么?3为三个节点,4为四个子树。旋转的过程总是由三个节点构成,且由于他们的父子关系,这三个节点一定存在2*3-2=4个子树(可以为空)。我们最终的目标就是改变它们的相对关系使之平衡。我们可以用中序遍历的方法给这7个目标重新排序。以left-right旋转为例,我们可以得到如下转化关系
无论对于何种情况,我们只需要考虑它们旋转之后的相对位置即可。
34重构的实现如下。
ptrNode rerotate(ptrNode a, ptrNode b, ptrNode c, ptrNode T1, ptrNode T2,
ptrNode T3, ptrNode T4) {
//调整内部关系,完成34重构
if (T1)
T1->father = a;
a->lch = T1;
if