平衡二叉树(AVL)的插入、删除、查找的java实现

本文介绍了一种平衡二叉树——AVL树的Java实现,包括插入、删除操作及旋转调整算法。AVL树是一种自平衡的二叉查找树,通过对每个节点的高度维护,确保任意节点的两个子树的高度差不超过1。
  • 平衡二叉树(AVL)操作实现java代码
package ccnu.offer.tree;

// 平衡二叉树(AVL树)的avl实现
// AVL树只是实现平衡二叉树的一种方法,它还有很多的其他实现方法如红黑树、替罪羊树、Treap、伸展
// 树等。接着来了解一下AVL树的特性:一棵AVL树是其每个结点的左子树和右子树的高度差的绝对值不超
// 过1的二叉查找树(空树的高度为-1),这个差值也称为平衡因子(其取值可以是1,0,-1,平衡因子是
// 某个结点左右子树高度的差值,有的书上定义是左边减去右边,有的书上定义是右边减去左边,这样可能会
// 有正负的区别,但是这个并不影响我们对平衡二叉树的讨论)

// 为了满足平衡二叉树的特性,需要在原来的二叉搜索树(BST)的结点中添加一个height的字段表示它的高
// 度,这里强调一下,高度和深度一组相反的概念,高度是指当前结点到叶子结点的最长路径,如所有叶子结
// 点的高度都为0,而深度则是指从根结点到当前结点的最大路径,如根结点的深度为0。这里约定空结点(空
// 子树)的高度为-1,叶子结点的高度为0,非叶子节点的高度则根据其子树的高度而计算获取
public class Demo05{

    public static void main(String[] args) {
        AVLNode root = null;
        for(int i = 1; i <= 10; i++){
            root = insert(root, i);
        }
        insert(root, 2);
        inOrder(root);
        System.out.println();
//      System.out.println("height: " + (root.height + 1) + " " + (int)Math.ceil(Math.log(10)/ Math.log(2))); // 树的高度为叶子节点的最大深度加上1(根节点为第一层)
        remove(root, 4);
        inOrder(root);
    }

    public static AVLNode insert(AVLNode root, int data) {
        if (root == null) {
            root = new AVLNode(data);
            return root;
        }
        if (data <= root.data) { // 插入到其左子树上
            root.lchild = insert(root.lchild, data);
            if (getHeight(root.lchild) - getHeight(root.rchild) > 1) { // 由于是向当前root树的左边插入,所以左子树高度必定不小于右子树高度(条件>1实质上等价于==2)
                if (data <= root.lchild.data) { // 最后插入的叶子结点在该root树的左孩子的左边
                    root = LLRotate(root); // 将调整后的root返回给其父节点的左子树域
                }else{ // 最后插入的叶子结点在该root树的左孩子的右边
                    root = LRRotate(root);
                }
            }
        }else{ // 插入到其右子树上
            root.rchild = insert(root.rchild, data);
            if(getHeight(root.rchild) - getHeight(root.lchild) > 1){
                if(data <= root.rchild.data){
                    root = RLRotate(root);
                }else{
                    root = RRRotate(root);
                }
            }
        }
        // 当插入新的节点后,从这个节点到根节点的最短路径上的节点的高度值一定会发生改变,另外当出现失衡点时,这个失衡点的所有祖先节点的高度值也可能会发生改变
        root.height = Math.max(getHeight(root.lchild), getHeight(root.rchild)) + 1; // 重新调整root节点的高度值
        return root;
    }

    public static AVLNode remove(AVLNode root, int data){
        if(root == null){ // 没有找到删除的节点
            return null;
        }
        if(data < root.data){ // 在左子树上删除
            root.lchild = remove(root.lchild, data);
            if(getHeight(root.rchild) - getHeight(root.lchild) > 1){ // 在左子树上删除,右子树高度一定不小于左子树高度
                if(getHeight(root.rchild.lchild) > getHeight(root.rchild.rchild)){
                    root = RLRotate(root);
                }else{
                    root = RRRotate(root);
                }
            }
        }else if(data == root.data){ // 找到删除的节点
            if(root.lchild != null && root.rchild != null){ // 删除的节点既有左子树又有右子树
                root.data = findNextNode(root).data; // 将失衡点的data域更改为其直接后继节点的data域
                root.rchild = remove(root.rchild, root.data); // 将问题转换为删除其直接后继节点
            }else{ // 只有左子树或者只有右子树或者为叶子结点的情况
                root = (root.lchild == null) ? root.rchild : root.lchild;
            }
        }else{ // 在root的右子树上查找删除节点
            root.rchild = remove(root.rchild, data);
            if(getHeight(root.lchild) - getHeight(root.rchild) > 1){
                if(getHeight(root.lchild.lchild) > getHeight(root.lchild.rchild)){
                    root = LLRotate(root);
                }else{
                    root = LRRotate(root);
                }
            }
        }
        if(root != null){ // 更新root的高度值
            root.height = Math.max(getHeight(root.lchild), getHeight(root.rchild)) + 1;
        }
        return root;
    }

    // LL平衡旋转(右单旋转)
    public static AVLNode LLRotate(AVLNode p){ // p为失衡点
        AVLNode lsubtree = p.lchild;
        p.lchild = lsubtree.rchild; // 将失衡点p的左孩子lsubtree的右子树成为失衡点p的左子树
        lsubtree.rchild = p; // 将失衡点作为lsubtree的右子树
        // 重新调整失衡点及其左孩子节点的高度值(只有这两个节点的高度值可能发生改变)
        p.height = Math.max(getHeight(p.lchild), getHeight(p.rchild)) + 1;
        lsubtree.height = Math.max(getHeight(lsubtree.lchild), p.height) + 1;
        return lsubtree; // 失衡点p的左孩子成为新的根节点(取代原失衡点的位置)
    }

    // RR平衡旋转(左单旋转)
    public static AVLNode RRRotate(AVLNode p){
        AVLNode rsubtree = p.rchild;
        p.rchild = rsubtree.lchild; // 将失衡点p的右孩子rsubtree的左子树成为失衡点p的右子树
        rsubtree.lchild = p; // 将失衡点p作为rsubtree左子树
        // 重新调整失衡点及其右孩子节点的高度值
        p.height = Math.max(getHeight(p.lchild), getHeight(p.rchild)) + 1;
        rsubtree.height = Math.max(getHeight(rsubtree.lchild), getHeight(rsubtree.rchild)) + 1;
        return rsubtree; //  失衡点p的右孩子成为新的根节点(取代原失衡点的位置)
    }

    // LR平衡旋转(先左后右双旋转)
    public static AVLNode LRRotate(AVLNode p){
        p.lchild = RRRotate(p.lchild); // 先将失衡点p的左子树进行RR平衡旋转
        return LLRotate(p); // 再将失衡点p进行LL平衡旋转并返回新节点代替原失衡点p

    }

    // RL平衡旋转(先右后左双旋转)
    public static AVLNode RLRotate(AVLNode p){
        p.rchild = LLRotate(p.rchild); // 先将失衡点p的右子树进行LL平衡旋转 
        return RRRotate(p); // 再将失衡点p进行RR平衡旋转并返回新节点代替原失衡点p
    }

    private static class AVLNode{
        private AVLNode lchild = null;
        private AVLNode rchild = null;
        private int data;
        private int height; // 记录该节点所在的高度

        public AVLNode(int data){
            this.data = data;
        }
    }

    public static int getHeight(AVLNode p){
        return p == null ? -1 : p.height; // 空树的高度为-1
    }

    public static void inOrder(AVLNode root){
        if(root != null){
            inOrder(root.lchild);
            System.out.print(root.data + " ");
            inOrder(root.rchild);
        }
    }

    // 得到p节点的后继节点(中序遍历),实际上也是p节点的右子树上的关键字值最小的节点
    public static AVLNode findNextNode(AVLNode p){
        if(p == null){
            return null;
        }
        AVLNode r = p.rchild;
        while(r != null && r.lchild != null){
            r = r.lchild;
        }
        return r;
    }

    // 得到p节点的直接前驱节点(中序遍历),实际上也是p节点的左子树上的关键字值最大的节点
    public static AVLNode findPreviousNode(AVLNode p){
        if(p == null){
            return null;
        }
        AVLNode l = p.lchild;
        while(l != null && l.rchild != null){
            l = l.rchild;
        }
        return l;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值