AVL树(自平衡的二叉搜索树)

一、谈二叉搜索树


增加的最坏时间复杂度 删除的最坏时间复杂度 查询的最坏时间复杂度
链表 O(N) + O(1) O(N) + O(1) O(N)
二叉搜索树 O(N) + O(1) O(N) + O(1) O(N)

       对于二叉搜索树,如果添加数据的时候数据随机分布的话,插入结点的时间复杂度会是O(h)、O(logN)。但是考虑下面两种极端情况,当**数据从小到大或者从大到小插入**的时候,裂开,复杂度直接变为O(N),而且**二叉搜索树变得和普通链表**一样了。

AltAlt

       不但插入结点会凉凉,删除结点可能也会变成链表,考虑下面情况:

Alt

       其实出现上述情况的根源还是二叉搜索树失衡了




二、AVL树

1、AVL树(自平衡)特点

       每个结点的平衡因子的绝对值小于等于1,一旦超过就是失衡,balanceFactor计算方法:平衡因子 = 左子树高度 - 右子树高度

       AVL树增加删除查询结点的时间复杂度都是O(h)、O(logN)。



2、设计结构图:

Alt


3、注意点

写代码要搞清楚以下两个点:

① 什么时候会出现失衡?
二叉搜索树插入结点和删除结点的时候会出现失衡情况。其实插入结点和删除结点也是不一样的,插入结点造成的失衡,只要往上找到第一个失衡的祖父结点,之后旋转同时将该结点及子结点的高度更新后,祖父结点之上失衡的结点也会变得平衡。然后删除结点恰恰相反,可能牵一发而动全身,不过最坏情况也不过是执行O(logN)次旋转操作。

② 怎么解决失衡?四种旋转情况对号入座

4、四种旋转情况(g、p、n三个结点)分析

       第一种情况:LL造成的失衡,g结点右旋转。
       第二种情况:RR造成的失衡,g结点左旋转。
       第三种情况:LR造成的失衡,先将p结点左旋转,再将g结点右旋转。
       第四种情况:RL造成的失衡,先将p结点右旋转,再将g结点左旋转。

       旋转情况比较简单,主要还是确定三个点,这三个点都是结点左右子树中比较长的结点。其中三个点用来判断是哪一种旋转情况,而 g 和 p 结点是专门用来旋转的。


       模板设计模式搭好AVL树插入结点和删除结点的算法框架,在之前BST插入代码里面写好接口,AVL树实现相应解决失衡的方法。



5、代码实现

	public class BinarySearchTree<E> extends BinaryTree<E> {
	
	    private Comparator<E> comparator;
	
	
	    public BinarySearchTree(Comparator<E> comparator) {
	        this.comparator = comparator;
	    }
	
	    public BinarySearchTree() {
	        this(null);     //调用有参构造
	    }
	
	    private int compare(E e1, E e2) {
	        if (comparator != null)
	            return comparator.compare(e1, e2);
	        else
	            return ((Comparable) e1).compareTo(e2);
	    }
	
	    public boolean contains(E element) {
	        return getNode(element) != null;
	    }
	
	    public Node<E> getNode(E element) {
	        Node<E> node = root;
	        while (node != null) {
	            int cmp = compare(element, node.element);
	            if (cmp > 0) {
	                node = node.right;
	            } else if (cmp < 0) {
	                node = node.left;
	            } else {
	                return node;
	            }
	        }
	        return null;
	    }
	
	    protected Node<E> createNode(Node<E> parent, E element) {
	        return new Node(parent, element);
	    }
	
	    /**
	     * BST插入一个结点
	     *
	     * @param element
	     */
	    public void add(E element) {
	        Node<E> node = root;
	        if (root == null) {    //插入第一个结点
	            root = createNode(null, element);
	            size++;
	
	            afterAdd(root);     //判断祖父结点们是否失衡在子类里进行处理
	
	            return;
	        }
	        int cmp = 0;
	        Node<E> t = null;
	        while (node != null) {
	            t = node;
	            cmp = compare(element, node.element);
	            if (cmp > 0) {          //待插入的元素比根结点元素大
	                node = node.right;
	            } else if (cmp < 0) {   //待插入的元素比根结点元素小
	                node = node.left;
	            } else {
	                return;
	            }
	        }
	        if (cmp > 0) {
	            t.right = createNode(t, element);
	            afterAdd(t.right);  //判断祖父结点们是否失衡在子类里进行处理
	        } else {
	            t.left = createNode(t, element);
	            afterAdd(t.left);   //判断祖父结点们是否失衡在子类里进行处理
	        }
	        size++;
	
	
	    }
	
	    /**
	     * 模板设计模式  交给子类来实现
	     *
	     * @param node
	     */
	    protected void afterAdd(Node<E> node) {}
	
	    /**
	     * BST删除节点要分情况, 度为0、1、2
	     *
	     * @param element
	     */
	    public void remove(E element) {
	        Node<E> node = getNode(element);
	        if (node == null)
	            return;
	
	        if (getDegree(node) == 0) {    //度为0, 直接删除即可
	            if (node.parent == null)   //只有一个根结点
	                root = null;
	            if (node == node.parent.left)
	                node.parent.left = null;
	            else
	                node.parent.right = null;
	
	            afterRemove(node);  //判断祖父结点们是否失衡在子类里进行处理
	
	        } else if (getDegree(node) == 1) { //度为1, 找自己的左儿子或右儿子替代
	            if (node.left != null) {    //找左儿子代替
	                if (node.parent == null)   //只有一个根结点
	                    root = node.left;
	                if (node.parent.left == node) {
	                    node.parent.left = node.left;
	                    node.left.parent = node.parent;   //改变父结点
	                } else {
	                    node.parent.right = node.left;
	                    node.left.parent = node.parent;   //改变父结点
	                }
	
	                afterRemove(node);   //判断祖父结点们是否失衡在子类里进行处理
	            } else {    //找右儿子代替
	                if (node.parent == null)   //只有一个根结点
	                    root = node.right;
	                if (node.parent.left == node) {
	                    node.parent.left = node.right;
	                    node.right.parent = node.parent;   //改变父结点
	                } else {
	                    node.parent.right = node.right;
	                    node.right.parent = node.parent;   //改变父结点
	                }
	
	                afterRemove(node);   //判断祖父结点们是否失衡在子类里进行处理
	            }
	        } else {    //度为2, 找前驱或者后继, 拷贝数据然后删除找的结点
	            Node<E> t = getSuccessor(node);
	            node.element = t.element;
	
	            int s = getDegree(t);     //前驱结点和后继结点只可能是度为1或者度为0
	            if (s == 1) {  //度为1
	                if (t.left != null) {
	                    if (t.parent.left == t) {
	                        t.parent.left = t.left;
	                        t.left.parent = t.parent;
	                    } else {
	                        t.parent.right = t.left;
	                        t.left.parent = t.parent;
	                    }
	
	                    afterRemove(t);  //判断祖父结点们是否失衡在子类里进行处理
	                } else {
	                    if (t.parent.left == t) {
	                        t.parent.left = t.right;
	                        t.right.parent = t.parent;
	                    } else {
	                        t.parent.right = t.right;
	                        t.right.parent = t.parent;
	                    }
	
	                    afterRemove(t);  //判断祖父结点们是否失衡在子类里进行处理
	                }
	            } else {    //度为0
	                if (t.parent.left == t)
	                    t.parent.left = null;
	                else
	                    t.parent.right = null;
	
	                afterRemove(t);  //判断祖父结点们是否失衡在子类里进行处理
	            }
	        }
	    }
	
	    /**
	     * 模板设计模式  交给子类来实现
	     *
	     * @param node
	     */
	    protected void afterRemove(Node<E> node) {}
	    
    }
	public class AVLTree<E> extends BinarySearchTree<E> {
	
	    public AVLTree(Comparator<E> comparator) {
	        super(comparator);
	    }
	
	    public AVLTree() {
	        super();
	    }
	
	    private class AVLNode<E> extends Node<E> {
	        private int height = 1;
	
	        public int getHeight() {
	            return height;
	        }
	
	        public void setHeight(int height) {
	            this.height = height;
	        }
	
	        public AVLNode(Node parent, E element) {
	            super(parent, element);
	        }
	
	        /**
	         * 计算平衡因子
	         *
	         * @return
	         */
	        public int balanceFactor() {
	            int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
	            int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
	            return leftHeight - rightHeight;
	        }
	
	        /**
	         * 更新高度
	         */
	        public void updateHeight() {
	            int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
	            int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
	            height = 1 + Math.max(leftHeight, rightHeight);
	        }
	
	        /**
	         * 找到自己的左右子树中长的那个
	         *
	         * @return
	         */
	        public Node getTallerChild() {
	            int leftHeight = this.left == null ? 0 : ((AVLNode<E>) this.left).height;
	            int rightHeight = this.right == null ? 0 : ((AVLNode<E>) this.right).height;
	            if (leftHeight > rightHeight)
	                return left;
	            else
	                return right;
	            // TODO 相等情况
	        }
	    }
	
	    private boolean isBalance(Node<E> node) {
	        return Math.abs(((AVLNode<E>) node).balanceFactor()) <= 1;
	    }
	
	    private void updateHeight(Node<E> node) {
	        ((AVLNode<E>) node).updateHeight();
	    }
	
	    @Override
	    protected Node<E> createNode(Node<E> parent, E element) {
	        return new AVLNode(parent, element);
	    }
	
	    /**
	     * 左旋转
	     *
	     * @param g
	     */
	    private void rotateLeft(Node<E> g) {    //只需要动g 和 p
	        Node<E> p = g.right;
	
	        g.right = p.left;
	        p.left = g;
	
	        //p变为根结点
	        p.parent = g.parent;
	        if (g.parent == null) {    //旋转的是根结点
	            root = p;
	        } else if (g.parent.left == g)
	            g.parent.left = p;
	        else if (g.parent.right == g)
	            g.parent.right = p;
	
	        //改变其他结点的parent
	        if (g.right != null)
	            g.right.parent = g;
	        g.parent = p;
	
	        //更新高度
	        updateHeight(g);
	        updateHeight(p);
	    }
	
	    /**
	     * 右旋转
	     *
	     * @param g
	     */
	    private void rotateRight(Node<E> g) {   //只需要动g 和 p
	        Node<E> p = g.left;
	
	        g.left = p.right;
	        p.right = g;
	
	        //p变为根结点
	        p.parent = g.parent;
	        if (g.parent == null) {    //旋转的是根结点
	            root = p;
	        } else if (g.parent.left == g)
	            g.parent.left = p;
	        else if (g.parent.right == g)
	            g.parent.right = p;
	
	        //改变其他结点的parent
	        if (g.left != null)
	            g.left.parent = g;
	        g.parent = p;
	
	        //更新高度
	        updateHeight(g);
	        updateHeight(p);
	    }
	
	    @Override
	    protected void afterAdd(Node<E> n) {
	        Node<E> grandparent = n;
	
	        while ((grandparent = grandparent.parent) != null) {
	            if (isBalance(grandparent)) {      //结点平衡直接更新高度
	                updateHeight(grandparent);
	            } else {        //结点不平衡需要旋转操作
	                //先找到g p n 三个结点(g是第一个不平衡结点中比较长的孩子结点)
	                Node<E> parent = ((AVLNode<E>) grandparent).getTallerChild();
	                Node<E> node = ((AVLNode<E>) parent).getTallerChild();
	
	                if (grandparent.left == parent) {
	                    if (parent.left == node) {              //LL
	                        rotateRight(grandparent);
	                    } else if (parent.right == node) {      //LR
	                        rotateLeft(parent);
	                        rotateRight(grandparent);
	                    }
	                } else if (grandparent.right == parent) {
	                    if (parent.left == node) {              //RL
	                        rotateRight(parent);
	                        rotateLeft(grandparent);
	                    } else if (parent.right == node) {      //RR
	                        rotateLeft(grandparent);
	                    }
	                }
	                break;  //添加结点引起的失衡只需旋转一次
	            }
	        }
	    }
	
	    @Override
	    protected void afterRemove(Node<E> n) {
	        Node<E> grandparent = n;
	
	        while ((grandparent = grandparent.parent) != null) {
	            if (isBalance(grandparent)) {      //结点平衡直接更新高度
	                updateHeight(grandparent);
	            } else {        //结点不平衡需要旋转操作
	                //先找到g p n 三个结点(g是第一个不平衡结点中比较长的孩子结点)
	                Node<E> parent = ((AVLNode<E>) grandparent).getTallerChild();
	                Node<E> node = ((AVLNode<E>) parent).getTallerChild();
	
	                if (grandparent.left == parent) {
	                    if (parent.left == node) {              //LL
	                        rotateRight(grandparent);
	                    } else if (parent.right == node) {      //LR
	                        rotateLeft(parent);
	                        rotateRight(grandparent);
	                    }
	                } else if (grandparent.right == parent) {
	                    if (parent.left == node) {              //RL
	                        rotateRight(parent);
	                        rotateLeft(grandparent);
	                    } else if (parent.right == node) {      //RR
	                        rotateLeft(grandparent);
	                    }
	                }
	                //删除结点引起的失衡可能不止一次不要直接break
	            }
	        }
	    }
    }
发布了54 篇原创文章 · 获赞 5 · 访问量 4610

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/104521938