数据结构--AVL树

AVL树


AVL树是带有平衡条件的二叉查找树。一颗AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树

当进行插入操作时,我们需要更新通向根节点路径上那些节点的所有平衡信息,而插入操作隐含着困难的原因在于,插入一个节点可能破坏AVL树的特性。如果发生这种情况,那么就要在考虑这一步插入完成之前恢复平衡的性质。事实上,这总可以通过对树进行简单的修正来做到,我们称其为选择

我们把必须重新平衡的节点叫做a。由于任意节点最多有两个儿子,因此出现高度不平衡就需要a点的两颗子树的高度差2。容易看出有下面4中情况:

  • 对a的左儿子的左子树进行一次插入
  • 对a的左儿子的右子树进行一次插入
  • 对a的右儿子的右子树进行一次插入
  • 对a的右儿子的左子树进行一次插入

    因为情况1和4,以及2和3是两组关于a点的镜像对称。因此,理论上只有两种情况,当然从编程的角度来看还是四种情况

    第一种情况是插入发生在“外边”的情况(即左-左的情况或者右-右的情况),该情况通过对树的一次单旋转而完成调整。

    第二种情况是插入发生在“内部”的情形(即左-右的情况或者右-左的情况),该情况通过稍微复杂些的双旋转来处理。

private static class AvlNode<AnyType>{
    AvlNode(AnyType theElement)
    {this(theElement, null, null);}

    AvlNode(AnyType theElement, AvlNode<AnyType> lt, AvlNode<AnyType rt)
    {element = theElement; left = lt; right = rt; height = 0;}

    AnyType element;
    AvlNode<AnyType> left;
    AvlNode<AnyType> right;
    int height;
}



单旋转


为使树恢复平衡,我们把X上移一层,并把Z下移一层。即搜寻到不符合AVL的性质(左右子树高度差为1)节点k2,使其左子树k1上升,并且k2自身下降,并且k1的右子树称为为k2的左子树。

private AvlNode<AnyType> rotateWithLeftChild(AvlNode<AnyType k2){

    AvlNode<AnyType> k1 = k2.left;
    k2.left = k1.right;
    k1.right = k2;
    k2.height = Math.max(height(k2.left), height(k2.right)) + 1;
    k1.height = Math.max(height(k1.left), height(k2.right)) + 1;
    return k1;
}



双旋转


节点k2上升至k1,k1作为k2的左子树且获得k2的左子树,k3作为k2的右子树且获得k2的右子树。相当于进行了两次单旋转,第一为右旋转,第二次为左旋转,所以称为双旋转。

private AvlNode<AnyType> doubleWithLeftChild(AvlNode<AvlType> k3){

    k3.left = rotateWithRightChild(k3.left);
    return rotateWithLeftChild(k3);
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页