数据结构 - AVL树

手撕AVL树

在开始正式学习之前,引用一句很经典的话,介绍给大家,也给自己留一个mark:

数据结构 - 定义一种性值并且维护这种性值

1. 二叉排序树

性值:

  • 左子树 < 根节点
  • 右子树 > 根节点
    用途:解决与排序相关的搜索问题
    操作:
  • 插入:
  • 删除:
    * 删除度为0的节点:直接删除即可
    * 删除度为1的节点:删除后,将唯一子树连接到父节点
    * 删除度为2的节点:找到前驱节点(小于当前节点的最大节点),将当前删除节点值替换为前驱节点值,并在左子树中删除前驱节点(该前驱节点一定是度为0或1的节点);

代码实现:

public class Binary_search_tree {

    public TreeNode getNewNode(int key) {
        return new TreeNode(key);
    }

    public TreeNode insert(TreeNode root, int key) {
        if (root == null) {
            return getNewNode(key);
        }
        if (key == root.val) {
            return root;
        }
        if (key < root.val) {
            root.left = insert(root.left, key);
            return root;
        }
        root.right = insert(root.right, key);
        return root;
    }

    public TreeNode erase(TreeNode root, int key) {
        if (root == null) return null;
        if (key < root.val) {
            root.left = erase(root.left, key);
        } else if (key > root.val) {
            root.right = erase(root.right, key);
        } else {
            if (root.left == null || root.right == null) {
                TreeNode temp = root.left == null ? root.right : root.left;
                root = null;
                return temp;
            } else {
                TreeNode temp = preDeccessor(root);
                root.val = temp.val;
                root.left = erase(root.left, temp.val);
            }
        }
        return root;
    }

    private TreeNode preDeccessor(TreeNode root) {
        TreeNode temp = root.left;
        while (temp.right != null) {
            temp = temp.right;
        }
        return temp;
    }

    public void clear(TreeNode root) {
        if (root == null) return;
        clear(root.left);
        clear(root.right);
        root = null;
    }

    public static void main(String[] args) {
        Binary_search_tree tree = new Binary_search_tree();
        TreeNode root = null;
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter two number: ");
        while (true) {
            String line = scanner.nextLine();
            String[] strings = line.split(", ");
            int op = Integer.parseInt(strings[0]);
            int val = Integer.parseInt(strings[1]);
            switch (op) {
                case 0: {
                    root = tree.insert(root, val);
                    break;
                }
                case 1:
                    root = tree.erase(root, val);
            }
            outPut(root);
            System.out.println();
        }
    }

    private static void outPut(TreeNode root) {
        if (root == null) return;
        outPut(root.left);
        System.out.print(root.val + ",");
        outPut(root.right);
    }
}

2. AVL树

性值:| H(left) - H(right) | <= 1
优点:对每个节点左右子树的高度做了限制,所以整颗树不会退化成链表
下面才是经典~ 这一对互逆的操作非常优美的维护了AVL树的性值~

左旋

在这里插入图片描述

右旋

在这里插入图片描述
重点来了~
失衡类型
LL型: 右旋
在这里插入图片描述
RL型:右旋+左旋
在这里插入图片描述
LR型:左旋+右旋

RR型:左旋

手撕代码:

public class AVLTree {
    static Node NIL = new Node(0, 0, null, null);

    static class Node {
        int key;
        int h;
        Node left;
        Node right;

        public Node(int key, int h, Node left, Node right) {
            this.key = key;
            this.h = h;
            this.left = left;
            this.right = right;
        }

        public Node(int key, int h) {
            this.key = key;
            this.h = h;
            this.left = NIL;
            this.right = NIL;
        }
    }

    private void updateHeight(Node root) {
        root.h = Math.max(root.left.h, root.right.h) + 1;
    }

    final String[] TYPE = {"", "LL", "RR", "LR", "RL"};

    private Node maintain(Node root) {
        if (Math.abs(root.left.h - root.right.h) < 2) return root;
        int type = -1;
        System.out.println("maintain: " + root.key);
        if (root.left.h > root.right.h) {
            if (root.left.right.h > root.left.left.h) {
                System.out.println(root.left.key + " left rotate");
                root.left = leftRotate(root.left);
                type = 3;
            }
            System.out.println(root.key + " right rotate");
            root = rightRotate(root);
            if (type == -1) {
                type = 1;
            }
        } else {
            if (root.right.left.h > root.right.right.h) {
                System.out.println(root.right.key + " right rotate");
                root.right = rightRotate(root.right);
                type = 4;
            }
            System.out.println(root.key + " left rotate");
            root = leftRotate(root);
            if (type == -1) {
                type = 2;
            }
        }
        System.out.println("maintain type = " + TYPE[type]);
        return root;
    }

    private Node leftRotate(Node root) {
        Node newRoot = root.right;
        root.right = newRoot.left;
        newRoot.left = root;
        updateHeight(root);
        updateHeight(newRoot);
        return newRoot;
    }

    private Node rightRotate(Node root) {
        Node newRoot = root.left;
        root.left = newRoot.right;
        newRoot.right = root;
        updateHeight(root);
        updateHeight(newRoot);
        return newRoot;
    }

    public Node erase(Node root, int key) {
        if (root == NIL) return root;
        if (key < root.key) {
            root.left = erase(root.left, key);
        } else if (key > root.key) {
            root.right = erase(root.right, key);
        } else {
            if (root.left == NIL || root.right == NIL) {
                Node temp = root.left == null ? root.right : root.left;
                root = null;
                return temp;
            } else {
                Node temp = precursor(root);
                root.key = temp.key;
                root.left = erase(root.left, temp.key);
            }
        }
        updateHeight(root);
        return maintain(root);
    }

    private Node precursor(Node root) {
        Node temp = root.left;
        while (temp.right != NIL) {
            temp = temp.right;
        }
        return temp;
    }

    public static void outPut(Node root) {
        if (root == NIL) return;
        System.out.print(root.key + ", ");
        outPut(root.left);
        outPut(root.right);
    }

    public Node getNewNode(int key) {
        return new Node(key, 1);
    }

    public Node insert(Node root, int key) {
        if (root == NIL) {
            return getNewNode(key);
        }
        if (key == root.key) {
            return root;
        }
        if (key < root.key) {
            root.left = insert(root.left, key);
        } else {
            root.right = insert(root.right, key);
        }
        updateHeight(root);
        return maintain(root);
    }

    public static void main(String[] args) {
        AVLTree tree = new AVLTree();
        Node root = NIL;
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter two number: ");
        while (true) {
            String line = scanner.nextLine();
            String[] strings = line.split(", ");
            int op = Integer.parseInt(strings[0]);
            int val = Integer.parseInt(strings[1]);
            switch (op) {
                case 0: {
                    root = tree.insert(root, val);
                    break;
                }
                case 1:
                    root = tree.erase(root, val);
            }
            outPut(root);
            System.out.println();
        }
    }

}

运行结果:

Enter two number:
0, 5
--------AVL tree print-------
5,
--------AVL tree print done -------
0, 9
--------AVL tree print-------
5, 9,
--------AVL tree print done -------
0, 8
--------AVL tree print-------
maintain: 5
9 right rotate
5 left rotate
maintain type = RL
8, 5, 9,
--------AVL tree print done -------
0, 3
--------AVL tree print-------
8, 5, 3, 9,
--------AVL tree print done -------
0, 2
--------AVL tree print-------
maintain: 5
5 right rotate
maintain type = LL
8, 3, 2, 5, 9,
--------AVL tree print done -------
0, 4
--------AVL tree print-------
maintain: 8
3 left rotate
8 right rotate
maintain type = LR
5, 3, 2, 4, 8, 9,
--------AVL tree print done -------
0, 1
--------AVL tree print-------
5, 3, 2, 1, 4, 8, 9,
--------AVL tree print done -------
0, 7
--------AVL tree print-------
5, 3, 2, 1, 4, 8, 7, 9,
--------AVL tree print done -------

这篇文章是基础,也是重中之重。掌握了精髓,解决相关的算法题目会觉得轻松很多~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值