avl树的基本概念与节点旋转

来源:互联网 发布:mac虚拟机安装win10 编辑:程序博客网 时间:2024/06/06 09:55

基本概念

avl树也是一颗二叉搜索数,所以也遵循二叉搜索树的定义,根节点的左子树永远比节点小,右子树永远比节点大。

  • 树深

根节点的最大的层次

  • 平衡因子

某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。
平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。否则这棵树就是不平衡的。

  • 旋转

节点的平衡因子大于1或者小于-1的时候就要对节点进行旋转。旋转分为四种
左单旋,右单旋,左右双旋,右左双旋

  • 左单旋

这里写图片描述
因为右支更重,所以进行左单旋。
旋转方法是那右孩子的左补自己的右,自己补孩子的左。

    /**     * 右重,左单旋     */    private AvlNode<T> leftRotate(AvlNode<T> node){        //新节点树,就是之前的右孩子节点        AvlNode<T> newNode = node.rightChild;        //拿右孩子左补自己的右        node.rightChild = newNode.leftChild;        //拿自己补孩子的左        newNode.leftChild = node;        //更新节点平衡因子        updateBalanceFactor(node);        updateBalanceFactor(newNode);        //返回旋转后的节点        return newNode;    }
  • 右单旋

这里写图片描述
因为左支更重,所以进行右单旋。
旋转方法是拿左孩子的右补自己的左,然后自己补左孩子的右。

    /**     * 左重,右单旋     * @param node     * @return     */    private AvlNode<T> rightRotate(AvlNode<T> node){        //新节点树,之前的左节点        AvlNode<T> newNode = node.leftChild;        //拿左孩子的右孩子补自己的左节点        node.leftChild = newNode.rightChild;        //拿自己补孩子的右节点        newNode.rightChild = node;        updateBalanceFactor(node);        updateBalanceFactor(newNode);        return newNode;    }
  • 左右双旋

这里写图片描述
左右双旋的诀窍就在于把节点变成可以单旋的形式。所以要经过两次旋转,第一次左孩子左单旋,把节点变成左支过重的情况,现在就可以旋转根节点了,右单旋根节点就可以使节点平衡了。

private AvlNode<T> leftRightRotate(AvlNode<T> node){    node.leftChild = leftRotate(node.leftChild);    return rightRotate(node);}
  • 右左双旋

这里写图片描述
右左双旋跟左右双旋的情况相反,右孩子右单旋,然后自己左单旋。

    /**     * 右重,右左双旋,先孩子右,后自己左     * @param node     * @return     */    private AvlNode<T> rightLeftRotate(AvlNode<T> node){        //孩子右旋,自己左旋        node.rightChild = rightRotate(node.rightChild);        return leftRotate(node);    }