java实现AVL树

1.AVL概念

AVL树是带有平衡条件的二叉查找树,也称为平衡二叉树。
最简单的实现方法就是保证树的左右子树具有相同的高度,保证树的深度是O(log N),但是这个条件过于严格难以使用需要放宽条件。

一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树

即AVL树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。

2.图解分析

2.1 模拟器地址

AVL树:https://www.cs.usfca.edu/~galles/visualization/AVLtree.html
所有数据结构:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

2.2 普通树和AVL树

图左,节点6的左边子树高度为3,而右边子树的高度为1,左右子树的高度之差不能超过1
在这里插入图片描述

2.3 最简单的旋转

依次插入1 2 3节点,1的左子树为空高度为0,而右子树高度为2,旋转后,左右高度都为1
在这里插入图片描述

2.4单旋转

依次插入6 3 7 1 4,插入2时,树的平衡被破坏
在这里插入图片描述
在这里插入图片描述
步骤:

  • 获取k1节点=k2的左边节点
  • 设置k2的左边节点为k1的右边节点Y
  • 设置k1的右边节点为k2
  • 重新计算k2和k1的高度
 private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2) {
        AvlNode 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), k2.height) + 1;
        return k1;
    }

2.5双旋转

依次插入6 2 7 1 4,插入3时,树的平衡被破坏
在这里插入图片描述
下面的图解C节点实际上应该没有,因为插入B的时候已经影响平衡
在这里插入图片描述
步骤:

  • k3的左边子树进行一次右边的单旋转
  • k3进行一次左边的单旋转
 private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3) {
        k3.left = rotateWithRightChild(k3.left);
        return rotateWithLeftChild(k3);
    }

2.6实现

平衡二叉树实现的大部分过程和二叉查找树是一样的,区别就在于插入删除之后要判断树左右子树高度之差是否大于1,如果大于1需要进行旋转维持平衡
其它的两种插入影响平衡的情况和以上两种刚好相反

3.代码

3.1树节点

public class AvlNode<T> {
    T element;
    int height;
    AvlNode<T> left;
    AvlNode<T> right;

    public AvlNode(T element) {
        this(element, null, null);
    }

    public AvlNode(T element, AvlNode<T> left, AvlNode<T> right) {
        this.element = element;
        this.left = left;
        this.right = right;
        this.height = 0;
    }
}

3.2平衡代码

private AvlNode<T> balance(AvlNode<T> t) {
        if (t == null) {
            return t;
        }

        if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) {
            if (height(t.left.left) >= height(t.left.right)) {
                t = rotateWithLeftChild(t);
            } else {
                t = doubleWithLeftChild(t);
            }
        } else if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) {
            if (height(t.right.right) >= height(t.right.left)) {
                t = rotateWithRightChild(t);
            } else {
                t = doubleWithRightChild(t);
            }
        }
        t.height = Math.max(height(t.left), height(t.right)) + 1;
        return t;
    }

3.3完整代码

public class AvlTree<T extends Comparable<? super T>> {

    private AvlNode<T> root;

    public void insert(T x) {
        root = insert(x, root);
    }

    public void remove(T x) {
        root = remove(x, root);
    }

    public T findMin() {
        return findMin(root).element;
    }


    public void makeEmpty() {
        root = null;
    }

    public boolean isEmpty() {
        return root == null;
    }

    /**
     * 添加节点
     *
     * @param x 插入节点
     * @param t 父节点
     */
    private AvlNode<T> insert(T x, AvlNode<T> t) {

        //如果根节点为空,则当前x节点为根及诶单
        if (null == t) {
            return new AvlNode(x);
        }

        int compareResult = x.compareTo(t.element);

        //小于当前根节点 将x插入根节点的左边
        if (compareResult < 0) {
            t.left = insert(x, t.left);
        } else if (compareResult > 0) {
            //大于当前根节点 将x插入根节点的右边
            t.right = insert(x, t.right);
        } else {

        }
        return balance(t);
    }

    private static final int ALLOWED_IMBALANCE = 1;

    private AvlNode<T> balance(AvlNode<T> t) {
        if (t == null) {
            return t;
        }

        if (height(t.left) - height(t.right) > ALLOWED_IMBALANCE) {
            if (height(t.left.left) >= height(t.left.right)) {
                t = rotateWithLeftChild(t);
            } else {
                t = doubleWithLeftChild(t);
            }
        } else if (height(t.right) - height(t.left) > ALLOWED_IMBALANCE) {
            if (height(t.right.right) >= height(t.right.left)) {
                t = rotateWithRightChild(t);
            } else {
                t = doubleWithRightChild(t);
            }
        }
        t.height = Math.max(height(t.left), height(t.right)) + 1;
        return t;
    }

    private AvlNode<T> doubleWithRightChild(AvlNode<T> k3) {
        k3.right = rotateWithLeftChild(k3.right);
        return rotateWithRightChild(k3);
    }

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

    private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3) {
        k3.left = rotateWithRightChild(k3.left);
        return rotateWithLeftChild(k3);
    }

    private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2) {
        AvlNode 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), k2.height) + 1;
        return k1;
    }

    private int height(AvlNode<T> t) {
        return t == null ? -1 : t.height;
    }

    /**
     * 删除节点
     *
     * @param x    节点
     * @param t    父节点
     */
    private AvlNode<T> remove(T x, AvlNode<T> t) {

        if (null == t) {
            return t;
        }

        int compareResult = x.compareTo(t.element);

        //小于当前根节点
        if (compareResult < 0) {
            t.left = remove(x, t.left);
        } else if (compareResult > 0) {
            //大于当前根节点
            t.right = remove(x, t.right);
        } else if (t.left != null && t.right != null) {
            //找到右边最小的节点
            t.element = findMin(t.right).element;
            //当前节点的右边等于原节点右边删除已经被选为的替代节点
            t.right = remove(t.element, t.right);
        } else {
            t = (t.left != null) ? t.left : t.right;
        }
        return balance(t);
    }

    /**
     * 找最小节点
     *
     * @param root 根节点
     */
    private AvlNode<T> findMin(AvlNode<T> root) {
        if (root == null) {
            return null;
        } else if (root.left == null) {
            return root;
        }
        return findMin(root.left);
    }

    /**
     * 找最大节点
     *
     * @param root 根节点
     */
    private AvlNode<T> findMax(AvlNode<T> root) {
        if (root == null) {
            return null;
        } else if (root.right == null) {
            return root;
        } else {
            return findMax(root.right);
        }
    }

    public void printTree() {
        if (isEmpty()) {
            System.out.println("节点为空");
        } else {
            printTree(root);
        }
    }


    public void printTree(AvlNode<T> root) {
        if (root != null) {
            System.out.print(root.element);
            if (null != root.left) {
                System.out.print("左边节点" + root.left.element);
            }
            if (null != root.right) {
                System.out.print("右边节点" + root.right.element);
            }
            System.out.println();
            printTree(root.left);
            printTree(root.right);
        }
    }

}

4.测试

代码:

 @Test
    public void test1(){
        AvlTree testTree = new AvlTree();
        testTree.insert(1);
        testTree.insert(2);
        testTree.insert(3);
        testTree.printTree();
    }

测试截图:
在这里插入图片描述
代码:

    @Test
    public void test4(){
        AvlTree testTree = new AvlTree();
        testTree.insert(6);
        testTree.insert(2);
        testTree.insert(7);
        testTree.insert(1);
        testTree.insert(4);
        testTree.insert(3);

        testTree.printTree();
    }

测试截图:
在这里插入图片描述

5.参考书籍

6.系列链接

上一篇:java实现二叉查找树

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树是一种自平衡的二叉搜索,它的升序遍历可以通过中序遍历来实现。下面是Java实现AVL树升序遍历的示例代码: ```java // AVL树节点定义 class Node { int key; int height; Node left; Node right; Node(int key) { this.key = key; this.height = 1; } } // AVL树类定义 class AVLTree { Node root; // 获取节点的高度 int getHeight(Node node) { if (node == null) { return 0; } return node.height; } // 更新节点的高度 void updateHeight(Node node) { node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1; } // 获取节点的平衡因子 int getBalanceFactor(Node node) { if (node == null) { return 0; } return getHeight(node.left) - getHeight(node.right); } // 右旋操作 Node rotateRight(Node y) { Node x = y.left; Node T2 = x.right; x.right = y; y.left = T2; updateHeight(y); updateHeight(x); return x; } // 左旋操作 Node rotateLeft(Node x) { Node y = x.right; Node T2 = y.left; y.left = x; x.right = T2; updateHeight(x); updateHeight(y); return y; } // 插入节点 Node insertNode(Node node, int key) { if (node == null) { return new Node(key); } if (key < node.key) { node.left = insertNode(node.left, key); } else if (key > node.key) { node.right = insertNode(node.right, key); } else { return node; // 不允许插入重复的节点 } updateHeight(node); int balanceFactor = getBalanceFactor(node); // 左旋操作 if (balanceFactor > 1 && key < node.left.key) { return rotateRight(node); } // 右旋操作 if (balanceFactor < -1 && key > node.right.key) { return rotateLeft(node); } // 左右旋操作 if (balanceFactor > 1 && key > node.left.key) { node.left = rotateLeft(node.left); return rotateRight(node); } // 右左旋操作 if (balanceFactor < -1 && key < node.right.key) { node.right = rotateRight(node.right); return rotateLeft(node); } return node; } // 中序遍历 void inorderTraversal(Node node) { if (node != null) { inorderTraversal(node.left); System.out.print(node.key + " "); inorderTraversal(node.right); } } } // 测试代码 public class Main { public static void main(String[] args) { AVLTree tree = new AVLTree(); tree.root = tree.insertNode(tree.root, 10); tree.root = tree.insertNode(tree.root, 20); tree.root = tree.insertNode(tree.root, 30); tree.root = tree.insertNode(tree.root, 40); tree.root = tree.insertNode(tree.root, 50); tree.root = tree.insertNode(tree.root, 25); System.out.println("AVL树的升序遍历结果:"); tree.inorderTraversal(tree.root); } } ``` 运行以上代码,输出结果为:10 20 25 30 40 50,即AVL树的升序遍历结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值