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

平衡二叉搜索树

如果二叉排序树是平衡的,则n个节点的二叉排序树的高度为,其查找效率为,近似于折半查找。

如果二叉排序树完全不平衡,则其深度可达到n,查找效率为O(n),退化为顺序查找。一般的,二叉排序树的查找性能在到O(n)之间。

因此,为了获得较好的查找性能,就要构造一棵平衡的二叉排序树。

 

平衡

  • 当节点数量固定时,左右子树的高度越接近,这颗二叉树就越平衡(高度越低)

  • 最理想的平衡,就是像完全二叉树、满二叉树那样,高度是最小的 

 如何改进二叉树搜索树

  • 首先,节点的添加、删除是无法限制的,可以认为是随机的
  • 所以,改进方案是:在节点的添加、删除之后,想办法让二叉搜索树恢复平衡(减小树的高度)

  • 如果接着继续调整节点的位置,完全可以达到理想平衡,但是付出的代价可能会比较大 

       比如调整的次数会比较多,反而增加了时间复杂度

  • 总结来说,比较合理的改进方案是:用尽量少的调整次数达到适度平衡即可
  • 一棵达到适度平衡的二叉搜索树,可以称之为:平衡二叉搜索树 

平衡二叉树搜索树 

  • AVL树
  • 红黑树

AVL树

  • 平衡因子(Balance Factor):某节点的左右子树的高度差
  • AVL树的特点:每个节点的平衡因子只可能是1、0、-1
  • 每个节点的左右子树的高度差不超过1
  • 搜索、添加、删除的时间复杂度O(logn)

                        

平衡对比

  • 输入数据:35、37、34、56、25、62、57、9、74、32、94、80、75、100、16、82

 添加导致的失衡

  • 例子:往下面这棵子树中添加13                    
  • 最坏情况:可能会导致所有祖先节点都失衡
  • 父节点、非祖先节点,都不可能失衡

                          

LL-右旋转(单旋)

  • g.left = p.right

  • p.right = g

  • 让p成为这棵树的根节点 

  • 仍然是一棵二叉搜索树:T0<n<T1<P<T2<g<T3

  • 整棵树都达到平衡

  • 还需要注意维护的内容

        1、T2、P、G 的parent属性

        2、先后更新g、p的高度

       

 RR-左旋转(单旋)

 

        1、T2、P、G 的parent属性

        2、先后更新g、p的高度

  • g.right = p.left
  • p.left = g
  • 让p成为这棵子树的根节点
  • 仍然是一棵二叉搜索树:T0<G<T1<P<T2<N<T3

  • 整棵树都达到平衡

  • 还需要注意维护的内容

LR-RR左旋转,LL右旋转

RL- LL右旋转,RR左旋转

删除导致的失衡

  • 删除下面的这棵子树中的16
  • 只可能导致父节点失衡或祖先节点失衡(只有1个节点失衡)
  • 除父节点以外的节点,都不可能失衡

                              

代码 

package com.jvm.letcode;

import java.util.LinkedList;
import java.util.Queue;

public class BinaryTree<E> {
    protected int size;
    protected Node<E> root;

    // 清空所有元素
    public void clear() {
        root = null;
        size = 0;
    }

    // 元素的数量
    public int size() {
        return size;
    }

    // 是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 前序遍历
     */
    public void preorder(Visitor<E> visitor) {
        preorderTraversal(root, visitor);
    }

    public void preorderTraversal(Node<E> node, Visitor<E> visitor) {
        if (node == null) return;

        preorderTraversal(node.left, visitor);
        preorderTraversal(node.right, visitor);
    }


    /**
     * 中旬遍历
     */
    public void inorder(Visitor<E> visitor) {
        inorder(root, visitor);
    }

    public void inorder(Node<E> node, Visitor<E> visitor) {
        if (node == null) return;
        inorder(node.left, visitor);
        visitor.visit(node.element);
        inorder(node.right, visitor);

    }

    /**
     * 后续遍历
     */
    public void postorder(Visitor<E> visitor) {
        postorder(root, visitor);
    }

    public void postorder(Node<E> node, Visitor<E> visitor) {
        if (node == null) return;
        postorder(node.left, visitor);
        postorder(node.right, visitor);
        System.out.println("BinarySearchTree.inorderTraversal:" + node.element);
    }

    /**
     * 层序遍历
     */
    public void levelOrder(Visitor<E> visitor) {
        if (root == null || visitor == null) return;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();
            visitor.visit(node.element);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
    }

    /**
     * 获取前驱节点
     *
     * @param node
     * @return
     */
    protected Node<E> predecessor(Node<E> node) {
        if (node == null) return null;
        Node<E> p = node.left;
        // 前驱节点在左子树当中 left.right.right.right
        if (p != null) {
            while (p.right != null) {
                p = p.right;
            }
            return p;
        }
        // 从父节点、祖父节点中国呢寻找前驱节点
        Node<E> parent = node.parent;
        while (parent != null && node == node.parent.left) {
            node = node.parent;
        }

        return node.parent;
    }

    /**
     * 获取后继节点
     *
     * @param node
     * @return
     */
    protected Node<E> successor(Node<E> node) {
        if (node == null) return null;
        Node<E> p = node.right;

        if (p != null) {
            while (p.left != null) {
                p = p.left;
            }
            return p;
        }

        Node<E> parent = node.parent;
        while (parent != null && node == node.parent.right) {
            node = node.parent;
        }

        return node.parent;
    }

    public Integer hight() {
        return hight(root);
    }

    public int hight(Node<E> node) {
        if (node == null) return 0;
        return 1 + Math.max(hight(node.left), hight(node.right));
    }

    public Integer hight2() {
        if (root == null) return 0;
        Queue<Node<E>> queue = new LinkedList<>();
        int queueSize = 1;
        int hight = 0;
        queue.offer(root);
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();
            queueSize--;
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
            if (queueSize == 0) {
                queueSize = queue.size();
                hight++;
            }
        }
        return hight;
    }

    public boolean isComplete() {
        if (root == null) return false;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        boolean leaf = false;
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();

            if (leaf && !node.isLeaf()) return false;

            if (node.hasTwoChildren()) {
                queue.offer(node.left);
                queue.offer(node.right);
            } else if (node.left == null && node.right != null) {
                return false;
            } else {
                // 判断是否都是叶子节点
                leaf = true;
                if (node.left != null) {
                    queue.offer(node);
                }
            }
        }
        return true;
    }

    public boolean isCompleteOther() {
        if (root == null) return false;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        boolean leaf = false;
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();
            if (leaf && !node.isLeaf()) return false;
            if (node.left != null) {
                queue.offer(node.left);
            } else if (node.right != null) {
                //node.left == null && node.right!=null,
                return false;
            }
            if (node.right != null) {
                queue.offer(node.right);
            } else {
                //node.left !=null && node.right==null 或者 node.left ==null && node.right == null
                leaf = true;
            }
        }
        return true;
    }


    public Object root() {
        return root;
    }

    public Object left(Object node) {
        return ((Node<E>) node).left;
    }

    public Object right(Object node) {
        return ((Node<E>) node).right;
    }

    public Object string(Object node) {
        return ((Node<E>) node).element;
    }

    protected Node<E> createNode(E element, Node<E> parent) {
        return new Node<>(element, parent);
    }

    /**
     * 遍历接口
     *
     * @param <E>
     */
    public static interface Visitor<E> {
        void visit(E element);
    }

    protected static class Node<E> {
        E element;
        Node<E> left;
        Node<E> right;
        Node<E> parent;

        public Node(E element, Node<E> parent) {
            this.element = element;
            this.parent = parent;
        }

        public boolean isLeaf() {
            return left == null && right == null;
        }

        public boolean hasTwoChildren() {
            return left != null && right != null;
        }

        public boolean isLeftChild() {
            return parent != null && this == parent.left;
        }

        public boolean isRightChild() {
            return parent != null && this == parent.right;
        }

    }
}

 

package com.jvm.letcode;

/**
 * 二叉搜索树
 *
 * @param <E>
 */
public class BinarySearchTree<E> extends BinaryTree {

    private Comparator<E> comparator;

    public BinarySearchTree(Comparator<E> comparator) {
        this.comparator = comparator;
    }

    // 添加元素
    public void add(E element) {
        elementNotNullCheck(element);
        if (root == null) {
            // 添加第一个节点
            root = createNode(element,null);
            size++;
            afterAdd(root);
            return;
        }
        // 添加不是第一个节点
        // 找到父节点
        Node<E> parent = null;
        Node<E> node = root;
        int cmp = 0;
        while (node != null) {
            cmp = compare(element, node.element);
            parent = node;
            if (cmp > 0) {
                node = node.right;
            } else if (cmp < 0) { // 新加的元素比父节点小
                node = node.left;
            } else { // 相等 将对象覆盖
                node.element = element;
                return;
            }
        }

        // 看看插入到副节点的哪个位置
        Node<E> newNode = createNode(element, parent);
        if (cmp > 0) {
            parent.right = newNode;
        } else {
            parent.left = newNode;
        }
        size++;
        afterAdd(newNode);
    }

    protected void afterAdd(Node<E> node){

    }

    private int compare(E element1, E element2) {
        return comparator.comparator(element1, element2);
    }

    // 删除元素
    public void remove(E elemet) {
        remove(node(elemet));
    }

    // 删除元素
    public void remove(Node<E> node) {

        if (node == null) return;
        size--;

        // 度为2的节点
        if (node.hasTwoChildren()) {
            // 找到后继节点
            Node<E> s = successor(node);
            // 用后继节点的值 覆盖度为2的节点的值
            node.element = s.element;
            // 删除后继节点
            node = s;
        }

        // 删除node节点(node的度必然是1 或者 0)
        Node<E> repalcement = node.left != null ? node.left : node.right;

        if (repalcement != null) { // node的度是1
            // 更改
            repalcement.parent = node.parent;
            if (node.parent == null) {// node的度是1 并且是根节点
                root = repalcement;
            } else if (node == node.parent.left) {
                node.parent.left = repalcement;
            } else if (node == node.parent.right) {
                node.parent.right = repalcement;
            }
        } else if (node.parent == null) {  // node的度是0 叶子节点 并且是根节点
            root = null;
        } else { // node的度是0 叶子节点 但不是根结点
            if (node == node.parent.right) {
                node.parent.right = null;
            } else {
                node.parent.left = null;
            }
        }
    }

    private Node<E> node(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;
    }


    // 是否包含某元素
    public boolean contains(E element) {
        return node(element) != null;
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        toString(root, sb, "");
        return sb.toString();
    }

    public void toString(Node<E> node, StringBuilder sb, String prefix) {
        if (node == null) return;
        toString(node.left, sb, prefix + "L---");
        sb.append(prefix).append(node.element).append("\n");
        toString(node.right, sb, prefix + "R---");
    }


    private void elementNotNullCheck(E element) {
        if (element == null) {
            throw new IllegalArgumentException("element must not be null");
        }
    }


    public static void main(String[] args) {
        Integer[] a = new Integer[]{7, 4, 9, 2, 1, 3, 5, 9, 8, 11, 10, 12};
        BinarySearchTree<Integer> bst = new BinarySearchTree<Integer>(new Comparator<Integer>() {
            @Override
            public int comparator(Integer e1, Integer e2) {
                return e1 - e2;
            }
        });

        for (Integer i : a) {
            bst.add(i);
        }

        System.out.println("BinarySearchTree.main:" + bst.hight2());
        System.out.println("BinarySearchTree.main:" + bst.hight());


        bst.levelOrder(new Visitor<Integer>() {
            @Override
            public void visit(Integer element) {
                System.out.println("_" + element + "_");
            }
        });
    }
}

 

package com.jvm.letcode;

public class AVLTree<E> extends BinarySearchTree<E> {

    public AVLTree() {
        this(null);
    }

    public AVLTree(Comparator<E> comparator) {
        super(comparator);
    }

    @Override
    protected void afterAdd(Node<E> node) {
        while ((node = node.parent) != null) {
            if (isBalanced(node)) {
                // 更新高度
                ((AVLNode<E>) node).updateHight();
            } else {
                // 恢复平衡
                AVLNode<E> grand = ((AVLNode<E>) node);
                Node<E> parent = grand.tallerChild();
                Node<E> no = ((AVLNode<E>) parent).tallerChild();

                if (parent.isLeftChild()) { // L
                    if (no.isLeftChild()) { // LL
                        rotateRight(grand);
                    } else { // LR
                        rotateLeft(parent);
                        rotateLeft(grand);
                    }
                } else { // R
                    if (no.isLeftChild()) { // RL
                        rotateRight(parent);
                        rotateRight(grand);
                    } else {// RR
                        rotateLeft(grand);
                    }

                }
                break;
            }
        }
    }

    private void rotateLeft(Node<E> grand) {
        Node<E> parent = grand.right;
        Node<E> child = grand.left;
        grand.right = child;
        parent.left = grand;

        parent.parent = grand.parent;
        if (grand.isLeftChild()) {
            grand.parent.left = parent;
        } else if (grand.isRightChild()) {
            grand.parent.right = parent;
        } else {
            root = parent;
        }

        if (child != null) {
            child.parent = grand;
        }

        grand.parent = parent;

        // 更新高度
        ((AVLNode<E>) grand).updateHight();
        ((AVLNode<E>) parent).updateHight();
    }

    private void rotateRight(Node<E> grand) {
        Node<E> parent = grand.left;
        Node<E> child = grand.right;
        grand.left = child;
        parent.right = grand;

        parent.parent = grand.parent;
        if (grand.isLeftChild()) {
            grand.parent.left = parent;
        } else if (grand.isRightChild()) {
            grand.parent.right = parent;
        } else {
            root = parent;
        }

        if (child != null) {
            child.parent = grand;
        }

        grand.parent = parent;

        // 更新高度
        ((AVLNode<E>) grand).updateHight();
        ((AVLNode<E>) parent).updateHight();
    }

    private boolean isBalanced(Node<E> node) {
        return Math.abs(((AVLNode<E>) node).balanceFactor()) <= 1;
    }

    private class AVLNode<E> extends Node<E> {
        int height = 1;

        public AVLNode(E element, Node<E> parent) {
            super(element, parent);
        }

        public int balanceFactor() {
            int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            return leftHeight - rightHeight;
        }

        public void updateHight() {
            int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            height = 1 + Math.max(leftHeight, rightHeight);
        }

        public Node<E> tallerChild() {
            int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            if (leftHeight > rightHeight) return left;
            if (leftHeight < rightHeight) return right;
            return isLeftChild() ? left : right;
        }
    }

    @Override
    protected Node createNode(Object element, Node parent) {
        return new AVLNode(element, parent);
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值