AVL树及java实现

二叉排序树查找、插入和删除操作的时间复杂度和树的深度n有关。构建树时,当先后插入的结点按关键字有序时,二叉排序树退化为链表,插入和删除的时间都会上升到O(n)。因此需要在构建二叉排序树的过程中进行“平衡化”处理,使之成为二叉平衡树。

二叉平衡树,又称AVL树。它或者是一棵空树,或者是具有下列性质的树:

1)具备二叉排序树的所有性质;

2)左子树和右子树深度差的绝对值不超过1;

3)左子树和右子树都是二叉平衡树

以上,得出AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。

对于旋转定义可以参考链接:www.cnblogs.com/skywang12345/p/3576969.html#a1以及www.cnblogs.com/Camilo/p/3917041.html

/**
 * node节点
 * @author SUJiannan
 */
class AVLNode {
    // 单node 高度为0 ; 
    // 空树 高度为 -1
    public int value; //值;为简化操作
    public AVLNode left;  //左孩子结点  
    public AVLNode right; //右孩子结点  
    public int height;    //树的高度  
    public AVLNode(int value) {
        this.value = value;
        this.height = 0;  // 树的init高度为0
    }
    public AVLNode() {
    }
}
package tree;

import java.util.ArrayList;
import java.util.List;

/**
 * 二叉平衡树 
 * @author SUJiannan
 * @see 下午8:26:31
 * 图例参考:http://www.cnblogs.com/Camilo/p/3917041.html
 */
public class AVLTree {

    private AVLNode root;    // 根结点
    /**
     * 计算树的高度  
     */
    public int height(AVLNode node){  
        return node == null ? -1 : node.height;  // 空树高度为-1
    } 
    
    /**
     * 四种旋转实现(LL,LR,RL,RR) 
     */
    // 单右旋 LL  返回值:旋转后的根节点
    // 当根结点左子树的左子树中的节点导致根结点的平衡因子为2时,采用LL型旋转进行调整。
    private AVLNode llRotate(AVLNode node){
        AVLNode x = node.left;
        node.left = x.right;
        x.right = node;
        
        node.height = Math.max(this.height(node.right),this.height(node.left)) + 1;
        x.height = Math.max(this.height(x.left), node.height) + 1;
        return x;  
    }
    
    // 单左旋 RR
    // 根结点右子树的右子树中的节点导致根结点的平衡因子为-2时,采用RR型旋转进行调整。
    private AVLNode rrRotate(AVLNode node){
        AVLNode x = node.right;
        node.right = x.left;
        x.left = node;
        
        node.height = Math.max(this.height(node.right),this.height(node.left)) + 1;
        x.height = Math.max(this.height(x.right), node.height) + 1;
        return x;  
    }
    
    //  LR型(先单次左旋,再单次右旋)
    // 当根结点左子树的右子树中的节点导致根结点的平衡因子为2时,采用LR型旋转进行调整。
    private AVLNode lrRotate(AVLNode node){
        node.left = rrRotate(node.left); // 左子树部分左旋
        return llRotate(node); // 整体右旋ll
    }
    
    // RL型(先单次右旋,再单次左旋)
    // 当根结点右子树的左子树中的节点导致根结点的平衡因子为-2时,采用RL型旋转进行调整。
    private AVLNode rlRotate(AVLNode node){
        node.right = llRotate(node.right); //  右子树部分右旋
        return rrRotate(node);
    }
    
    /**
     * 插入操作
     */
    public void insert(int val) {
        this.root = insert(root,val);
    }
    
    public AVLNode insert(AVLNode node, int val){
        if(node == null) {
            return new AVLNode(val);
        }
        int cmp = node.value - val;
        if(cmp > 0) {
            node.left = insert(node.left,val);
            if(height(node.left) - height(node.right) == 2) {
                if(node.left.value > val) {
                    // ll 
                    node = llRotate(node);
                } else {
                    // lr
                    node = lrRotate(node);
                }
            }
        } else if(cmp < 0) {
            node.right = insert( node.right,val);
            if(height(node.left) - height(node.right) == -2) {
                if(val > node.right.value) {
                    // rr
                    node = rrRotate(node);
                } else {
                    //rl
                    node = rlRotate(node);
                }
            }
        } else {
            // 相等 无操作 
            return null;
        }
        // 插入后 树的高度  
        node.height = Math.max(height(node.left), height(node.right)) + 1; 
        return node; 
    }
    
    /**
        * 删除结点(z),返回根节点
        * 参数说明:
        *   val:待删除的结点
        * return:
        *     根节点
     */
    public AVLNode remove(int val) {
        AVLNode root = remove(this.root , val);
        return root;
    }

    private AVLNode remove(AVLNode node, int val) {
        if(node == null) {
//          System.out.println("not find");
            return null;
        } 
        // find value
        int cmp = node.value - val;
        if(cmp > 0) {
            node.left = remove(node.left,val);
            if(this.height(node.left) - height(node.right) == -2)  {
                AVLNode tmpNode = node.right;
                if(height(tmpNode.left) > height(tmpNode.right)) {
                    //rl
                    node = this.rlRotate(node);
                } else {
                    //rr
                    node = this.rrRotate(node);
                }
            }
        } else if (cmp < 0) {
            node.right = remove(node.right,val);
            if ( height(node.left ) - height(node.right) == 2) {
                AVLNode tmpNode = node.left;
                if(height(tmpNode.left) < height(tmpNode.right)) {
                    // lr
                    node = lrRotate(node);
                } else {
                    // ll
                    node = llRotate(node);
                }
            }
        } else {
            // find it and delete it
            if(node.left == null && node.right == null) {
                node = null;
            } else if(node.left != null && node.right == null ) {
                node = node.left;
                
                // delete后 树的高度  
                node.height = Math.max(height(node.left), height(node.right)) + 1; 
                
            } else if(node.left == null && node.right != null) {
                node = node.right;
                
                // delete后 树的高度  
                node.height = Math.max(height(node.left), height(node.right)) + 1; 
                
            } else {
                // 获取左子树最大的node
                AVLNode x = node.left;
                while(x.right != null) {
                    x = x.right;
                }
                // 将该最大节点的值赋值给tree
                node.value = x.value;
                // 删除该最大节点 
                node.left = remove(node.left , x.value);
                
                // delete后 树的高度  
                node.height = Math.max(height(node.left), height(node.right)) + 1; 
            }
        }
        return node;
    }

    /**
     * 查找当前value对应的node
     */
    public AVLNode get(int value) {
        AVLNode avlNode = get(value,this.root);
        // 利用int最小值代表未找到
        return avlNode == null ? new AVLNode(Integer.MIN_VALUE) : avlNode;
    }
    private AVLNode get(int value,AVLNode node) {
        if(node == null) {
            return null; // not find
        }
        int cmp = value - node.value;
        if(cmp > 0) {
            return get(value , node.right);
        } else if(cmp < 0) {
            return get(value , node.left);
        } else {
            // find it
            return node;
        }
    }
    
    
    
    /**
     *  中序遍历
     */
    public void printZhong(){
        List list = new ArrayList();
        printZ(this.root , list);
        System.out.println("中序遍历:" + list);
    }
    private void printZ(AVLNode node, List list) {
        if(node != null) {
            printZ(node.left ,list) ;
            list.add(node.value);
            printZ(node.right ,list) ;
        }
    }
    
    /**
     *  先序遍历
     */
    public void printXian(){
        List list = new ArrayList();
        printX(this.root , list);
        System.out.println("先序遍历:" + list);
    }
    private void printX(AVLNode node, List list) {
        if(node != null) {
            list.add(node.value);
            printX(node.left ,list) ;
            printX(node.right ,list) ;
        }
    }
}

测试代码:

public static void main(String[] args) {
        int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
        AVLTree a = new AVLTree();
        for (int i : arr) {
            a.insert(i);
        }
        a.remove(5);
        a.remove(6);
        a.printXian();
        a.printZhong();
        
        AVLNode avlNode = a.get(900);
        System.out.println("寻找9的node节点:" + avlNode.value);
}

运行结果:
先序遍历:[7, 2, 1, 4, 3, 13, 11, 9, 8, 10, 12, 15, 14, 16]
中序遍历:[1, 2, 3, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

你可能感兴趣的:(AVL树及java实现)