数据结构与算法-平衡二叉搜索树AVL

平衡二叉搜索树:简称平衡二叉树。由前苏联的数学家 Adelse-Velskil 和 Landis 在 1962 年提出的高度平衡的二叉树,根据科学家的英文名也称为 AVL 树。它具有如下几个性质:
1.可以是空树。
2.假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过 1。

上篇文章优先级队列PriorityQueue源码分析分析了优先级队列PriorityQueue的实现,PriorityQueue所用的是二叉堆,是一种具备"下沉"和"上移"功能的二叉搜索树。二叉搜索树在一定程度上可以提高查找效率。但是当原本的数据趋向于有序时,如数据123456,数据结构将会退化成链表,查找时间复杂度O(n),这是平衡二叉搜索树出现的原因。

链表/右斜树


平衡因子

平衡因子(Balance Factor)是指某个节点左子树与右子树的高度差,平衡二叉树的平衡因子只可能是-1,0,1,。如果平衡因子的绝对值大于1,说明此树不是平衡二叉树。


平衡二叉树和非平衡二叉树

基础节点设计

public class BalanceTree<E extends Comparable<E>> {//实现Comparable,节点的值必须是可比较的
    private Node root;
    private int size;

    private class Node {
        private E e;
        private Node left;
        private Node right;
        private int height;//height方便计算平衡因子

        public Node(E e) {
            this.e = e;
            this.left = null;
            this.right = null;
            this.height = 1;//高度初始值是1
        }
    }

    public BalanceTree() {
        this.root = null;
        this.size = 0;
    }

    public int getSize() {
        return size;
    }

    private int getHeight(Node node) {//获取节点高度
        if (node == null) {
            return 0;
        }
        return node.height;
    }

    private int getBalanceFactor(Node node) {//获取节点平衡因子
        if (node == null) {
            return 0;
        }
        return getHeight(node.left) - getHeight(node.right);
    }

    public boolean isBalance(Node node) {//判断是否是一颗平衡二叉树,需左右子树都是平衡二叉树
        if (node == null) {
            return true;
        }
        int balanceFactor = Math.abs(getBalanceFactor(node));
        if (balanceFactor > 1) {
            return false;
        }
        return isBalance(node.left) && isBalance(node.right);
    }
}
  • 平衡二叉树也是二叉搜索树,所以节点的值必须是可比较的,需实现Comparable
  • 为了方便计算平衡因子的值,设置height变量
  • 平衡因子等于左右子树的高度差
  • 判断是否是一颗平衡二叉树,需左右子树都是平衡二叉树

添加节点

往平衡二叉树添加节点很有可能导致平衡二叉树失去平衡,所以每次添加节点后我们需要进行平衡维护,添加节点破坏平衡有以下四种情况

  • LL(需要右旋)

LL的意思是为往左节点(L)添加左子节点(L)导致失去平衡的情况,需要右旋维护平衡

右旋

新插入的节点4,比9和5都小,所以插入到5的左边,9变成了失衡点,所以将失衡点9作为参数进行右旋

    private Node rightRotate(Node imbalance) {
        Node left = imbalance.left;//获取9的左节点5
        Node leftRight = left.right;//5的右节点,这里是null
        left.right = imbalance;//5的右节点赋值为9
        imbalance.left = leftRight;//5的右节点放到9的左边
        
        //右旋影响了9和5的高度,重新计算赋值
        imbalance.height = Math.max(getHeight(imbalance.left), getHeight(imbalance.right)) + 1;
        left.height = Math.max(getHeight(left.left), getHeight(left.right)) + 1;
        //将新的头节点返回 这里是5这个节点
        return left;
    }

右旋思路:将失衡点放到失衡点左节点的右边,并重新计算影响到节点的高度。


  • RR(需要左旋)

RR的意思是为往右节点(R)添加右子节点(R)导致失去平衡的情况,需要左旋维护平衡

左旋

新插入的节点10,比7和9都大,所以插入到9的右边,7变成了失衡点,将7作为参数左旋

    private Node leftRotate(Node imbalance) {
        Node right = imbalance.right;//获取失衡点7的右节点,这里是9
        Node rightLeft = right.left;//获取9的左节点,这里是null
        right.left = imbalance;//将9的左节点指向7
        imbalance.right = rightLeft;//7的右节点指向9的原来的左节点
         
        //影响了7和9,重新计算高度赋值
        right.height = Math.max(getHeight(right.left), getHeight(right.right)) + 1;
        imbalance.height = Math.max(getHeight(imbalance.left), getHeight(imbalance.right)) + 1;
        //返回新的根节点9
        return right;
    }

左旋思路:将失衡点放到失衡点右节点的左边,并重新计算影响到节点的高度。


  • LR(需要先左旋再右旋)
先左旋再右旋

新插入的节点8,比9小,比7大,所以插在7的右边,形成LR的情况,先将左节点7左旋,再将根节点9右旋

        if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {//LR
            //先左旋 再右旋
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }

先左旋再右旋思路:先将根节点的左节点左旋,再把根节点右旋


RL(需要先右旋再左旋)

新插入的节点9,比7大,比7的右节点10小,所以放在了10的左节点上。需要先对10右旋


右旋

然后根节点7左旋


左旋
        if (balanceFactor < -1 && getBalanceFactor(node.right) > 0) {//RL
            //先右旋 再左旋
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }

先右旋再左旋思路:先将根节点的右节点右旋,再把根节点左旋


添加节点

    private Node add(Node node, E e) {
        if (node == null) {
            size++;
            return new Node(e);
        }
        if (e.compareTo(node.e) < 0) {
            node.left = add(node.left, e);
        } else if (e.compareTo(node.e) > 0) {
            node.right = add(node.right, e);
        }
        node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;

        int balanceFactor = getBalanceFactor(node);
        if (balanceFactor > 1 && getBalanceFactor(node.left) > 0) {//LL  
            //右旋
            return rightRotate(node);
        }
        if (balanceFactor < -1 && getBalanceFactor(node.right) < 0) {//RR
            //左旋
            return leftRotate(node);
        }
        if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {//LR
            //先左旋 再右旋
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
        if (balanceFactor < -1 && getBalanceFactor(node.right) > 0) {//RL
            //先右旋 再左旋
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
        return node;
    }

删除节点

    public E remove(E e) {
        Node node = getNode(root, e);
        if (node != null) {
            root = remove(root, e);
            return node.e;
        }
        return null;
    }

    private Node remove(Node node, E e) {
        if (node == null) {
            return null;
        }
        Node retNode;
        if (e.compareTo(node.e) < 0) {
            node.left = remove(node.left, e);
            retNode = node;
        } else if (e.compareTo(node.e) > 0) {
            node.right = remove(node.right, e);
            retNode = node;
        } else {
            if (node.left == null) {
                Node rightNode = node.right;
                node.right = null;
                size--;
                retNode = rightNode;
            } else if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                retNode = leftNode;
            } else {
                Node successor = minimum(node.right);
                successor.right = remove(node.right, successor.e);
                successor.left = node.left;

                node.left = node.right = null;
                retNode = successor;
            }
        }
        if (retNode == null) {
            return null;
        }
        retNode.height = Math.max(getHeight(retNode.left), getHeight(retNode.right)) + 1;
        int balanceFactor = getBalanceFactor(retNode);
        if (balanceFactor > 1 && getBalanceFactor(retNode.left) > 0) {
            return rightRotate(retNode);
        }
        if (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) {
            return leftRotate(retNode);
        }
        if (balanceFactor > 1 && getBalanceFactor(retNode.left) < 0) {
            node.left = leftRotate(retNode.left);
            return rightRotate(retNode);
        }
        if (balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) {
            node.right = rightRotate(retNode.right);
            return leftRotate(retNode);
        }
        return node;
    }

整体代码

public class BalanceTree<E extends Comparable<E>> {
    private Node root;
    private int size;

    private class Node {
        private E e;
        private Node left;
        private Node right;
        private int height;

        public Node(E e) {
            this.e = e;
            this.left = null;
            this.right = null;
            this.height = 1;
        }
    }

    public BalanceTree() {
        this.root = null;
        this.size = 0;
    }

    public int getSize() {
        return size;
    }

    private int getHeight(Node node) {
        if (node == null) {
            return 0;
        }
        return node.height;
    }

    private int getBalanceFactor(Node node) {
        if (node == null) {
            return 0;
        }
        return getHeight(node.left) - getHeight(node.right);
    }

    public boolean isBalance(Node node) {
        if (node == null) {
            return true;
        }
        int balanceFactor = Math.abs(getBalanceFactor(node));
        if (balanceFactor > 1) {
            return false;
        }
        return isBalance(node.left) && isBalance(node.right);
    }

    private Node rightRotate(Node imbalance) {
        Node left = imbalance.left;
        Node leftRight = left.right;
        left.right = imbalance;
        imbalance.left = leftRight;

        imbalance.height = Math.max(getHeight(imbalance.left), getHeight(imbalance.right)) + 1;
        left.height = Math.max(getHeight(left.left), getHeight(left.right)) + 1;
        return left;
    }

    private Node leftRotate(Node imbalance) {
        Node right = imbalance.right;
        Node rightLeft = right.left;
        right.left = imbalance;
        imbalance.right = rightLeft;

        right.height = Math.max(getHeight(right.left), getHeight(right.right)) + 1;
        imbalance.height = Math.max(getHeight(imbalance.left), getHeight(imbalance.right)) + 1;
        return right;
    }

    public void add(E e) {
        root = add(root, e);
    }

    private Node add(Node node, E e) {
        if (node == null) {
            size++;
            return new Node(e);
        }
        if (e.compareTo(node.e) < 0) {
            node.left = add(node.left, e);
        } else if (e.compareTo(node.e) > 0) {
            node.right = add(node.right, e);
        }
        node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;

        int balanceFactor = getBalanceFactor(node);
        if (balanceFactor > 1 && getBalanceFactor(node.left) > 0) {//LL  
            //右旋
            return rightRotate(node);
        }
        if (balanceFactor < -1 && getBalanceFactor(node.right) < 0) {//RR
            //左旋
            return leftRotate(node);
        }
        if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {//LR
            //先左旋 再右旋
            node.left = leftRotate(node.left);
            return rightRotate(node);
        }
        if (balanceFactor < -1 && getBalanceFactor(node.right) > 0) {//RL
            //先右旋 再左旋
            node.right = rightRotate(node.right);
            return leftRotate(node);
        }
        return node;
    }

    private Node getNode(Node node, E e) {
        if (node == null) {
            return null;
        }
        if (e.equals(node.e)) {
            return node;
        } else if (e.compareTo(node.e) < 0) {
            return getNode(node.left, e);
        } else {
            return getNode(node.right, e);
        }
    }

    private Node minimum(Node node) {
        if (node.left == null) {
            return node;
        }
        return minimum(node.left);
    }

    public E remove(E e) {
        Node node = getNode(root, e);
        if (node != null) {
            root = remove(root, e);
            return node.e;
        }
        return null;
    }

    private Node remove(Node node, E e) {
        if (node == null) {
            return null;
        }
        Node retNode;
        if (e.compareTo(node.e) < 0) {
            node.left = remove(node.left, e);
            retNode = node;
        } else if (e.compareTo(node.e) > 0) {
            node.right = remove(node.right, e);
            retNode = node;
        } else {
            if (node.left == null) {
                Node rightNode = node.right;
                node.right = null;
                size--;
                retNode = rightNode;
            } else if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                retNode = leftNode;
            } else {
                Node successor = minimum(node.right);
                successor.right = remove(node.right, successor.e);
                successor.left = node.left;

                node.left = node.right = null;
                retNode = successor;
            }
        }
        if (retNode == null) {
            return null;
        }
        retNode.height = Math.max(getHeight(retNode.left), getHeight(retNode.right)) + 1;
        int balanceFactor = getBalanceFactor(retNode);
        if (balanceFactor > 1 && getBalanceFactor(retNode.left) > 0) {
            return rightRotate(retNode);
        }
        if (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) {
            return leftRotate(retNode);
        }
        if (balanceFactor > 1 && getBalanceFactor(retNode.left) < 0) {
            node.left = leftRotate(retNode.left);
            return rightRotate(retNode);
        }
        if (balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) {
            node.right = rightRotate(retNode.right);
            return leftRotate(retNode);
        }
        return node;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345