AVL树及关于插入的说明

基本概念

       AVL树是带有平衡条件的二叉查找树,这个平衡条件必须保持:一棵AVL树的每个结点的左子树和右子树的高度最多差1。

struct AvlNode
{
  ElementType Element;
  AvlNode Left;
  AvlNode Right;
  int Height;
};

       当进行插入操作时,需要更新通向根节点路径上节点的平衡信息,而且插入一个节点后可能破坏AVL树的特性,这时通过对树进行简单的修正即可,称其为旋转。
       把需要重新平衡的节点叫做α,当出现不平衡时,有以下四种情况:

1. 对α的左儿子的左子树进行了一次插入;
2. 对α的左儿子的右子树进行了一次插入;
3. 对α的右儿子的左子树进行了一次插入;
4. 对α的右儿子的右子树进行了一次插入;

       情形1和4、2和3是关于α点的对称,所以只需要解决的只有两种情况。第一种情况是插入发生在“外边”的情况(左-左或者右-右),该情况通过对树的一次单旋转而完成调整;第二种情况是插入发生在“内部”的情形(右-左或者左-右),该情况通过双旋转来处理。

单旋转

        我们先假设情形1的情况:节点k1是k2的左子树,X是k1的左子树并且X下还有一层,Y是k1的右子树,Z是节点k2的右子树,这时不满足AVL树的平衡特性。为了使树恢复平衡,我们把X上移一层,并把Z下移一层,但这样实际上超出了AVL特性的要求,为此我们重新安排节点以形成一颗等价的树,如此一来形成了新的树:k2变成了k1的右儿子,X和Z仍然分别是k1的左儿子和k2的右儿子,子树Y包含原树中介于k1和k2之间的那些节点,可以将它放在新树中k2的左儿子的位置上,这样,所有对顺序的要求都得到满足。
       上面的操作只需要一部分的指针改变,结果我们得到另外一棵AVL树,因为X向上移动了一层,Y停留在原来的水平上,而Z下移一层,k1和k2不仅满足AVL的要求,而且它们的子树都恰好处在同一高度上,不仅如此,整个树的新高度恰恰与插入前原树的高度相同,而插入操作却使得子树X长高了,因此,通向根结点的路径的高度不需要进一步的修正,因而也不需要进一步的旋转。

AvlNode *SingleRotateWithLeft(AvlNode *k2)
{
  AvlNode *k1;
  k1 = k2->Left;
  k2->Left = k1->Right;
  k1->Right = k2;
  k2->Height = Max(Height(k2->Left), Height(k2->Right)) + 1;
  k1->Height = Max(Height(k1->Left), k2->Height) + 1;
  return k1;
}

       情形4是情形1的对称,其操作方式与情形1的方式相同。

双旋转

       现在考虑情形2的情况:k1是k2的左子树,Z是k2的右子树,X是k1的左子树,Y是k1的右子树并且Y下还有一层。如果对于上述情形进行一次那个单旋转,会得到情形3的情况,所以单旋转对情形2和情形3是不适用的。我们将上述的情形2细化如下:k1是k3的左子树,D是k3的右子树,A是k1的左子树,k2是k1的右子树,A和C分别是k2的左右子树。
       为了重新平衡,不能再让k3作为根了,而在k3和k1之间的旋转又解决不了问题,唯一的选择就是把k2用作新的根,这迫使k1是k2的左儿子,k3是它的右儿子,从而完全确定了这四棵树的最终位置。容易看出,最后得到的树满足AVL树的特性,与单旋转的情形一样,也将树的高度恢复到插入以前的水平,这就保证所有的重新平衡和高度更新是完善的。

AvlNode *DoubleRotateWithLeft(AvlNode *k3)
{
  k3->Left = SingleRotateWithRight(k3->Left);
  return SingleRotateWithLeft(k3);
}

       同样的,情形3是情形2的对称,其操作与上述过程类似。

插入操作的实现

       我们考虑上面两种旋转应对在插入中AVL树会出现的四种情形,现在就是要完善整个插入操作。为了将关键字是X的一个新节点插入到一棵AVL树T中去,我们递归地将X插入到T的相应的子树中去,如果子树的高度不变,那么插入完成;否则,如果在T中出现高度不平衡,那么我们根据X以及T和子树中的关键字做适当的单旋转或双旋转,更新这些高度并解决好与树的其余部分的连接,从而完成插入。

AvlNode *Insert(ElementType X, AvlNode *T)
{
  if (T == NULL)
  {
T = new AvlNode;
if (T == NULL)
  std::cout << “Out of space!” << std::endl;
else
{
  T->Element = X;
  T->Height = 0;
  T->Left = T->Right = NULL;
}
  }
  else if (X < T->Element)
  {
T->Left = Insert(X, T->Left);
if (Height(T->Left) – Height(T->Right) == 2)
  if (X < T->Left->Element)
    T = SingleRotateWithLeft(T);
  else
    T = DoubleRotateWithLeft(T);
  }
  else if (X > T->Element)
{
  T->Right = Insert(X, T->Right);
  if (Height(T->Right) – Height(T->Left) == 2)
    if (X > T->Right->Elment)
      T = SingleRotateWthRight(T);
    else
      T = DoubleRotateWithRight(T);
}
T->Height = Max(Height(T->Left), Height(T->Right)) + 1;
return T;
}

       对于AVL树的其他操作笔者暂时不作说明,当最近一段时间的学习过程结束之后,会做一个总结将这些操作通过C++实现。

    原文作者:AVL树
    原文地址: https://blog.csdn.net/mr_avin/article/details/53465673
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞