AVL

来源:互联网 发布:大数据 通用 解决方案 编辑:程序博客网 时间:2024/06/05 16:54

AVL

目录

    • AVL
    • 概述
    • 单旋转
      • 右旋转
      • 左旋转
    • 双旋转
      • 左-右旋转
      • 右-左旋转
    • 代码实现
    • Summary

概述

二叉搜索树(BST)可能会造成如下图所示的问题:

性能很差的BST

查找的时间复杂度会达到O(N),这个时候AVL树就派上用场了。
一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉搜索树(空树的高度定义为-1)。

把失去平衡的节点叫做α,由于任意节点最多有两个孩子,因此出现高度不平衡的α的两棵子树的高度差为2。容易看出,这种不平衡可能会出现以下四种情况:

  • 对α的左孩子的左子树进行一次插入
  • 对α的左孩子的右子树进行一次插入
  • 对α的右孩子的左子树进行一次插入
  • 对α的右孩子的右子树进行一次插入

情形1和4是对称的,2和3也是对称的。因此,理论上只有两种情形。


单旋转

右旋转

情形1如下图所示:

情形1

在k2的左孩子k1的左子树插入一个元素,导致k2的左右子树不平衡了(插入前是平衡的),此时以k1为轴,进行一次右旋转(顺时针)即可达到平衡。

左旋转

同理,就很容易得出对称的情形4:

情形4

在k1的右孩子k2的右子树插入一个元素,导致k1的左右子树不平衡(插入前是平衡的),此时以k2为轴,进行一次左旋转(逆时针)即可达到平衡。


双旋转

左-右旋转

情形2如图所示:

情形2

假设在k3的左孩子k1的右子树上k2插入一个元素,导致B或者C比D深两层,那么此时只需要:

  1. 以k1为轴,先做一次左旋转(情形1)
  2. 再次k3为轴,做一次右旋转(情形4)

即可让整棵树再次达到平衡,也就是两次单旋转即可。

右-左旋转

同样,对于情形3,如图:

情形3

在k1的右孩子k3的左子树k2上插入一个元素,导致B或者C比A深两层,那么此时只需要:

  1. 以k3为轴,先做一次右旋转(情形4)
  2. 再以k1为轴,做一次左旋转(情形1)

即可让整棵树再次达到平衡,也是两次单旋转。


代码实现

已经明白了旋转的原理,剩下的就是编码实现了,弄清楚指针指向就行了。

public class AVLTreeTest {      public static void main(String[] agrs) {        AVLTree tree = null;        for(Integer i = 1; i < 10; i++) {            tree = AVLTreeUtils.insert(i, tree);        }        System.out.println("preOrder: ");        AVLTreeUtils.preOrder(tree);        System.out.println();        System.out.println("inOrder: ");        AVLTreeUtils.inOrder(tree);        System.out.println();        System.out.println("postOrder: ");        AVLTreeUtils.postOrder(tree);    }       }class AVLTree {    public Integer element;    public AVLTree lchild;    public AVLTree rchild;    public Integer height;    public AVLTree() {}}class AVLTreeUtils {    public static AVLTree insert(Integer ele, AVLTree root) {        if(root == null) {// 如果是空节点,就插入            root = new AVLTree();            root.element = ele;            root.lchild = root.rchild = null;            root.height = 0;        } else if(ele < root.element) {// 在左子树插入            root.lchild = insert(ele, root.lchild);            // 插入后,检查一下是否已经失衡            if(getHeight(root.lchild) - getHeight(root.rchild) == 2) {                if(ele < root.lchild.element)                    // 左孩子的左子树——情形1                     root = singleRotateWithLeft(root);                else                    // 左孩子的右子树--情形2                    root = doubleRotateWithLeft(root);            }                   } else if(ele > root.element)   {            root.rchild = insert(ele, root.rchild);            if(getHeight(root.rchild) - getHeight(root.lchild) == 2) {                if(ele > root.rchild.element)                     // 右孩子的左子树--情形3                    root = singleRotateWithRight(root);                else                    // 右孩子的右子树--情形4                    root = doubleRotateWithRight(root);            }           }        // 调整完成后,更新一下整棵树的高度        root.height = Math.max(getHeight(root.lchild), getHeight(root.rchild)) + 1;        return root;            }       private static Integer getHeight(AVLTree tree) {        if (tree == null)             return -1;        return tree.height;    }    // 对照几张示意图,即可弄明白指针的指向    // 情形1    private static AVLTree singleRotateWithLeft(AVLTree oldRoot) {        AVLTree newRoot = oldRoot.lchild;;        oldRoot.lchild = newRoot.rchild;        newRoot.rchild = oldRoot;        oldRoot.height = Math.max(getHeight(oldRoot.lchild), getHeight(oldRoot.rchild)) + 1;        newRoot.height = Math.max(getHeight(newRoot.lchild), oldRoot.height) + 1;        return newRoot;    };    // 情形4    private static AVLTree singleRotateWithRight(AVLTree oldRoot) {        AVLTree newRoot = oldRoot.rchild;;        oldRoot.rchild = newRoot.lchild;        newRoot.lchild = oldRoot;        oldRoot.height = Math.max(getHeight(oldRoot.lchild), getHeight(oldRoot.rchild)) + 1;        newRoot.height = Math.max(oldRoot.height, getHeight(newRoot.rchild)) + 1;        return newRoot;    };    // 情形2    private static AVLTree doubleRotateWithLeft(AVLTree oldRoot) {        oldRoot.lchild = singleRotateWithRight(oldRoot.lchild);        return singleRotateWithLeft(oldRoot);    };      // 情形3    private static AVLTree doubleRotateWithRight(AVLTree oldRoot) {        oldRoot.rchild = singleRotateWithLeft(oldRoot.rchild);        return singleRotateWithRight(oldRoot);    };    // 先序遍历    public static void preOrder(AVLTree tree) {        if(tree != null) {                      System.out.print(tree.element + " ");                       preOrder(tree.lchild);                      preOrder(tree.rchild);        }           }       // 中序遍历    public static void inOrder(AVLTree tree) {              if(tree != null) {              inOrder(tree.lchild);            System.out.print(tree.element + " ");            inOrder(tree.rchild);        }           }    // 后序遍历    public static void postOrder(AVLTree tree) {                if(tree != null) {              postOrder(tree.lchild);                     postOrder(tree.rchild);            System.out.print(tree.element + " ");        }           }}// outputpreOrder: 4 2 1 3 6 5 8 7 9 inOrder: 1 2 3 4 5 6 7 8 9 postOrder: 1 3 2 5 7 9 8 6 4 

Summary

以前挺畏惧树的,可是仔细研究一下 – Just a pretty girl standing out there in the fog waiting to be saved…

0 0
原创粉丝点击