Day30-数据结构与算法-树


title: Day30-数据结构与算法-树
date: 2020-10-21 19:08:27
author: 子陌


常用的经典数据结构

树(Tree)

使用树形结构可以大大提高效率

树的概念
  • 节点、根节点、父节点、子节点、兄弟节点
  • 一棵树可以没有任何节点,称为空树
  • 一棵树可以只有一个节点,也就是只有根节点
  • 子树、左子树、右子树
  • 节点的:子树的个数
  • 树的:所有节点度中的最大值
  • 叶子节点:度为0的节点
  • 非叶子节点:度不为0的节点
  • 层数:根节点在第一层,根节点的子节点在第二层,以此类推
  • 节点的深度:从根节点到当前节点的唯一路径上的节点总数
  • 节点的高度:从当前节点到最远叶子节点的路径上的节点总数
  • 树的深度:所有节点深度中的最大值
  • 树的高度:所有节点高度中的最大值
  • 树的深度等于树的高度
  • 有序树
    • 树中任意节点的字节的之间有顺序关系
  • 无序树
    • 树中任意节点的子节点之间没有顺序关系
    • 也称为“自由树”
  • 森林
    • 由m(m ≥ 0)棵互不相交的树组成的集合

二叉树(Binary Tree)

特点

每个节点的度最大为2(最多拥有2棵子树)
左子树和右子树是有顺序的
即使某节点只有一棵子树,也要区分左右子树

二叉树的性质

非空二叉树的第i层,最多有2i - 1个节点(i ≥ 1)
在高度为n的二叉树上最多有2n - 1个节点(n ≥ 1)
对于任何一棵非空二叉树,如果叶子节点个数为n0,度为2的节点个数为n2,则有:n0 = n2 + 1
假设度为1的节点个数为n1,那么二叉树的节点总数n = n0 + n1 + n2
二叉树的边数T = n1 + 2 * n2 = n - 1 = n0 + n1 + n2 - 1

  • 真二叉树:所有节点的都要么为0,要么为2

  • 满二叉树:所有节点的都要么为0,要么为2。且所有的叶子节点都在最后一层

    • 在同样高度的二叉树中,满二叉树的叶子节点数量最多、总节点数量最多

    • 满二叉树一定是真二叉树,真二叉树不一定是满二叉树

    • 假设满二叉树的高度为h(h ≥ 1),那么:

      • 第i层的节点数量:2i - 1

      • 叶子节点数量:2h - 1

      • 总节点数量n

        ✔ n =2h - 1 = 20 + 21 + 22 + … + 2h - 1

        ✔ h = log2(n + 1)

  • 完全二叉树:叶子节点只会出现最后2层,且最后1层的叶子节点都靠左对齐

    • 完全二叉树从根节点倒数第二层是一棵满二叉树

    • 满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树

    • 性质:

      • 度为1的节点只有左子树

      • 度为1的节点要么是1个,要么是0个

      • 同样节点数量的二叉树,完全二叉树的高度最小

      • 假设完全二叉树的高度为h(h ≥ 1),那么

        • 至少有2h - 1个节点(20 + 21 + 22 + … + 2h - 2 + 1)

        • 最多有2h - 1个节点(20 + 21 + 22 + … + 2h - 1,满二叉树)

        • 总节点数量为n

          ✔ 2h - 1 ≤ n ≤ 2h

          ✔ h - 1 ≤ log2n < h(h = floor(log2n)向下取整 + 1)

完全二叉树

完全二叉树1

二叉树的遍历
  • 遍历是数据结构中的常见操作
    • 把所有元素都访问一遍
  • 线性数据结构的遍历比较简单
    • 正序遍历
    • 逆序遍历
  • 根据节点访问顺序的不同,二叉树的常见遍历方式有4种
    • 前序遍历:根节点、前序遍历子树、前序遍历子树
      • 树状结构展示(注意左右子树的顺序)
    • 中序遍历:中序遍历子树、根节点、中序遍历子树
      • 二叉搜索树的遍历结果是升序或者降序
    • 后序遍历:后序遍历子树、后序遍历子树、根节点
      • 适用于先子后父的操作
    • 层序遍历:从上到下、从左到右依次访问每个节点
      • 计算二叉树的高度
      • 判断一棵树是否为完全二叉树
根据遍历结果重构二叉树
  • 前序遍历 + 中序遍历
  • 后序遍历 + 中序遍历
  • 后序遍历 + 后序遍历
    • 如果它是一棵真二叉树,结果唯一
    • 不然结果不唯一
前驱节点
  • 前驱节点:中序遍历的前一个节点
    • 如果是二叉搜索树,前驱节点就是前一个比它小的节点
  • node.left != null
    • predecessor = node.left.right.right…
    • 终止条件:right == null
  • node.left == null && node.parent != null
    • predecessor = node.parent.parent…
    • 终止条件:node在parent的子树中
  • node.left == null && node.parent == null
    • 没有前驱节点
后继节点
  • 后继节点:中序遍历的后一个节点
    • 如果是二叉搜索树,前驱节点就是后一个比它大的节点
  • node.right != null
    • successor = node.right.left.left.left…
    • 终止条件:left == null
  • node.right == null && node.parent != null
    • successor = node.parent.parent.parent…
    • 终止条件:node在parent的子树中
  • node.right == null && node.parent == null
    • 没有后继节点
二叉搜索树(Binary Search Tree)
  • 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为BST
    • 又被称为:二叉查找树,二叉排序树、
    • 任意一个节点的值都大于左子树所有节点的值
    • 任意一个节点的值都小于右子树所有节点的值
    • 它的左右子树也是一棵二叉搜索树
  • 二叉搜索树可以大大提高搜索数据的效率
  • 二叉搜索树存储的元素必须具备可比较性
    • 比如int、double等
    • 如果是自定义类型,需要指定比较方式
    • 不允许为null
接口设计

int size() 元素的数量
boolean isEmpty() 是否为空
void clear() 清空所有元素
void add(E element) 添加元素
void remove(E element) 删除元素
boolean contains(E element) 是否包含某个元素

需要注意的是,对于二叉树来说,没有索引的概念

  • 删除节点:
    • 度为0:叶子节点直接删除 parent.child = null 或 root = null
    • 度为1:用删除的子节点替代 parent.child = child.child 或 root = child.child
    • 度为2:先用前驱或者后继节点的值覆盖原节点的值,然后删除相应的前驱或者后继节点
      • 如果一个节点的度为2,那么它的前驱、后继节点的度只可能是1和0
package com.zimo.;

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

/**
 * 树 - 二叉树 - 二叉搜索树实现
 *
 * @author Liu_zimo
 * @version v0.1 by 2020/10/23 15:08:30
 */

// public class BinarySearchTree<E extends Comparable<E>> { 声明时,不强制实现比较接口,如果别人想自定义比较器则会出错
public class BinarySearchTree<E> {
    public static void main(String[] args) {
        BinarySearchTree<Integer> b1 = new BinarySearchTree<>();
        // 匿名类方式,也可以自定义类实现比较器
        BinarySearchTree<Object> b2 = new BinarySearchTree<>(new Comparator<Object>() {
            @Override
            public int compare(Object o, Object t1) {
                // 比较逻辑
                return 0;
            }
        });

        Integer[] integers = {7, 4, 9, 2, 5, 8, 11, 1, 3, 10, 12};
        for (Integer integer : integers) {
            b1.add(integer);
        }
        b1.preorderTraversal(new Visitor<Integer>() {
            @Override
            public boolean visitor(Integer element) {
                System.out.print("_" + element + "_ ");
                return element == 9 ? true : false; // 遇到9后续不打印
            }
        });
        System.out.println("\n树高为:" + b1.height() + b1.height1());
        System.out.println("是否为完全二叉树" + b1.isComplete());
        System.out.println(b1.predesessor(b1.root).element);
        System.out.println(b1.successor(b1.root).element);
        b1.remove(11);
        b1.remove(7);
        b1.preorderTraversal(new Visitor<Integer>() {
            @Override
            public boolean visitor(Integer element) {
                System.out.print("_" + element + "_ ");
                return false;
            }
        });
    }
    private int size;
    private Node<E> root;
    private Comparator<E> comparator;

    public BinarySearchTree() {
        this(null);
    }

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

    /**
     * 获取元素的数量
     * @return 元素的数量
     */
    public int size(){
        return size;
    }

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

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

    /**
     * 添加元素
     * @param element 要添加的元素
     */
    public void add(E element){
        elementNotNullCheck(element);
        if (root == null){
            // 添加第一个节点
            root = new Node<>(element, null);
            size++;
            return;
        }else {
            // 添加不是第一个节点
            Node<E> node = this.root;
            Node<E> parent = null;
            int compare = 0;

            // 1.找到父节点parent
            while (node != null){
                compare = compare(element, node.element);
                parent = node;
                if (compare > 0){
                    node = node.right;
                }else if (compare < 0){
                    node = node.left;
                }else { // 相等
                    node.element = element;
                    return;
                }
            }
            // 2.创建新节点node
            Node<E> newNode = new Node<>(element, parent);
            // 3.parent.left = node || parnet.right = node
            if (compare > 0){
                parent.right = newNode;
            }else {
                parent.left = newNode;
            }
            size++;
        }
    }

    /**
     * 删除元素(提供外界删除元素,外面没有节点概念)
     * @param element 要删除的元素
     */
    public void remove(E element){
        remove(node(element));
    }

    /**
     * 删除一个节点(删除内部节点)
     * @param node 要删除的节点
     */
    private void remove(Node<E> node){
        if (node == null) return;
        size--;
        if (node.hasTwoChildren()){
            // 删除度为2的节点 - rmNode的前驱或者后继节点覆盖rmNode,然后删除相应的前驱或者后继节点
            Node<E> successor = successor(node);
            // 用后继节点值覆盖度为2的节点值
            node.element = successor.element;
            // 删除后继节点
            node = successor;
        }
        // 删除node节点(node 度必然是1 或者 0)
        Node<E> replacement = node.left != null ? node.left : node.right;

        if (replacement != null){
            // 删除度为1的节点 - 用删除的子节点替代 parent.child = rmNode.left/right  || root = rmNode.left/right
            replacement.parent = node.parent;   // 更改parent
            // 更改parent的left/right的指向
            if (node.parent == null){   // 度为1的根节点
                root = replacement;
            }else if(node == node.parent.left){
                node.parent.left = replacement;
            }else {
                node.parent.right = replacement;
            }
        }else if (node.parent == null){
            // 删除根节点:root = null
            root = null;
        }else{
            // 删除叶子节点 - 直接删除 left/right = null
            if (node == node.parent.left){
                node.parent.left = null;
            }else {
                node.parent.right = null;
            }
        }
    }

    /**
     * 根据元素查找对应的节点
     * @param element
     * @return
     */
    private Node<E> node(E element) {
        Node<E> node = this.root;
        while (node != null){
            int cmp = compare(element, node.element);
            if (cmp == 0) return node;
            if (cmp > 0) node = node.right;
            else node = node.left;
        }
        return null;
    }

    /**
     * 是否包含某个元素
     * @param element 要查找的元素
     * @return 是否包含查找的元素
     */
   public boolean contains(E element){
        return node(element) != null;
    }

    /**
     * 比较元素大小
     * @param e1
     * @param e2
     * @return 0:e1 == e2   >0: e1 > e2   <0: e1 < e2
     */
    private int compare(E e1, E e2){
        // return e1.compareTo(e2);
        if (comparator != null) {
            return comparator.compare(e1, e2);
        }
        return ((Comparable<E>)e1).compareTo(e2);   // 如果没实现比较器,默认为强制实现比较接口
    }

    /**
     * 前序遍历
     */
    public void preorderTraversal(Visitor<E> visitor){
        if (visitor == null) return;
        preorderTraversal(root, visitor);
    }
    private void preorderTraversal(Node<E> node, Visitor<E> visitor){
        if (node == null || visitor.stop) return;
        // System.out.println(node.element);
        //if (visitor.stop) return;
        visitor.stop = visitor.visitor(node.element);
        preorderTraversal(node.left, visitor);
        preorderTraversal(node.right, visitor);
    }

    /**
     * 中序遍历
     * @param visitor
     */
    public void inorderTraversal(Visitor<E> visitor){
        if (visitor == null) return;
        inorderTraversal(root ,visitor);
    }
    private void inorderTraversal(Node<E> node, Visitor<E> visitor){
        if (node == null || visitor.stop) return;
        inorderTraversal(node.left,visitor);
        // System.out.println(node.element);
        if (visitor.stop) return;
        visitor.stop = visitor.visitor(node.element);
        inorderTraversal(node.right,visitor);
    }

    /**
     * 后序遍历
     */
    public void postorderTraversal(Visitor<E> visitor){
        if (visitor == null) return;
        postorderTraversal(root, visitor);
    }
    private void postorderTraversal(Node<E> node, Visitor<E> visitor){
        if (node == null || visitor.stop) return;
        postorderTraversal(node.left,visitor);
        postorderTraversal(node.right,visitor); // visitor.stop == true
        // System.out.println(node.element);
        if (visitor.stop) return;
        visitor.stop = visitor.visitor(node.element);
    }

    /**
     * 层序遍历:实现思路(队列)
     *  1.根节点入队
     *  2.循环执行一下操作,直到队列为空
     *      A节点访问,A的左子树入队,A的右子树入队
     */
    public void levelOrderTraversal(Visitor<E> visitor){
        if (root == null || visitor == null) return;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            Node<E> poll = queue.poll();
            // System.out.println(poll.element);
            if (visitor.visitor(poll.element)) {
                return;
            }
            if (poll.left != null){
                queue.offer(poll.left);
            }
            if (poll.right != null){
                queue.offer(poll.right);
            }
        }
    }

    /**
     * 计算二叉树的高度(递归)
     * @return 二叉树的高度
     */
    public int height(){
        return height(root);
    }
    private int height(Node<E> node){
        if (node == null) return 0;
        return 1 + Math.max(height(node.left), height(node.right));
    }

    /**
     * 计算二叉树高度(非递归:层序遍历)
     * @return
     */
    public int height1(){
        if(root == null) return 0;
        int height = 0; // 树高度
        int levelSize = 1;  // 每层的元素的数量
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            Node<E> poll = queue.poll();
            levelSize--;
            if (poll.left != null){
                queue.offer(poll.left);
            }
            if (poll.right != null){
                queue.offer(poll.right);
            }
            if (levelSize == 0){
                levelSize = queue.size();
                height++;
            }
        }
        return height;
    }

    /**
     * 是否为完全二叉树
     * @return 返回是否为完全二叉树的结果
     */
    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> poll = queue.poll();
            if (leaf && !poll.isLeaf()) return false;

            if (poll.left != null){
                queue.offer(poll.left);
            }else if (poll.right != null){
                return false;   // left == null && right != null
            }

            if (poll.right != null){
                queue.offer(poll.right);
            }else {
                // left == null && right == null 或者  left != null && right == null
                leaf = true;
            }
        }
        return true;
    }

    public boolean isComplete1(){
        if (root == null) return false;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        boolean leaf = false;
        while (!queue.isEmpty()){
            Node<E> poll = queue.poll();
            if (leaf && poll.isLeaf()) return false;
            if (poll.hasTwoChildren()){
                queue.offer(poll.left);
                queue.offer(poll.right);
            }else if (poll.left == null && poll.right != null){
                return false;
            }else {
                // 后面遍历的节点必须是叶子节点
                leaf = true;
                if (poll.left != null){
                    queue.offer(poll.left);
                }
            }
        }
        return true;
    }

    /**
     * 获取node节点的前驱节点:中序遍历的前一个
     * @param node 要找的节点
     * @return 查找结果
     */
    private Node<E> predesessor(Node<E> node){
        if (node == null) return null;
        // 前驱节点在左子树中
        Node<E> p = node.left;
        if (p != null){
            while (p.right != null) p = p.right;
            return p;
        }

        // 从父节点、祖父节点中寻找前驱
        while (node.parent != null && node == node.parent.left){
            node = node.parent;
        }
        // node.parent
        return node.parent;
    }

    /**
     * 获取node节点的后继节点:中序遍历的后一个
     * @param node
     * @return
     */
    private 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;
        }

        // 从父节点、祖父节点中寻找前驱
        while (node.parent != null && node == node.parent.right){
            node = node.parent;
        }
        // node.parent
        return node.parent;
    }

    private void elementNotNullCheck(E element){
        if(element == null)
            throw new IllegalArgumentException("element元素不能为空");
    }

    // 如果想要操作遍历元素
    public static abstract class Visitor<E>{
        boolean stop;
        /**
         * 返回true时停止遍历
         * @param element
         * @return
         */
        abstract boolean visitor(E element);
    }

    private 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;
        }

        /**
         * 判断是否为叶子节点
         * @return
         */
        public boolean isLeaf() {
            return left == null && right == null;
        }

        /**
         * 是否有两个子节点
         * @return
         */
        public boolean hasTwoChildren(){
            return left != null && right != null;
        }
    }
}
翻转二叉树
package com.zimo.;

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

/**
 * 翻转二叉树 : https://leetcode-cn.com/problems/invert-binary-tree/
 *
 * @author Liu_zimo
 * @version v0.1 by 2020/10/24 14:50:40
 */
public class InvertBinaryTree {

    // 前序遍历
    public TreeNode preInvertTree(TreeNode root){
        if (root == null) return null;

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;

        preInvertTree(root.left);
        preInvertTree(root.right);
        return root;
    }

    // 后序遍历
    public TreeNode postInvertTree(TreeNode root){
        if (root == null) return null;

        preInvertTree(root.left);
        preInvertTree(root.right);

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        return root;
    }

    // 中序遍历
    public TreeNode inInvertTree(TreeNode root){
        if (root == null) return root;

        preInvertTree(root.left);

        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;

        preInvertTree(root.left);   // 注意:中序和前后序遍历不一样,交换后还是left而不是right
        return root;
    }

    // 层序遍历
    public TreeNode levelInvertTree(TreeNode root){
        if (root == null) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()){
            TreeNode node = queue.poll();

            TreeNode tmp = node.left;
            node.left = node.right;
            node.right = tmp;

            if (node.left != null){
                queue.offer(node.left);
            }
            if (node.right != null){
                queue.offer(node.right);
            }
        }
        return root;
    }

}
class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x){
        val = x;
    }
}
重构二叉搜索树

重构二叉搜索树

  • 抽取二叉树公共方法

    package com.zimo.;
    
    import java.util.LinkedList;
    import java.util.Queue;
    
    /**
     * 二叉树 - 基类
     *
     * @author Liu_zimo
     * @version v0.1 by 2020/10/26 10:41
     */
    public class BinaryTree<E> {
        protected int size;
        protected Node<E> root;
    
        public int size() {
            return size;
        }
    
        public boolean isEmpty() {
            return size == 0;
        }
    
        public void clear() {
            root = null;
            size = 0;
        }
    
        public void preorderTraversal(Visitor<E> visitor) {
            if (visitor == null) return;
            preorderTraversal(root, visitor);
        }
    
        private void preorderTraversal(Node<E> node, Visitor<E> visitor) {
            if (node == null || visitor.stop) return;
            visitor.stop = visitor.visitor(node.element);
            preorderTraversal(node.left, visitor);
            preorderTraversal(node.right, visitor);
        }
    
        public void inorderTraversal(Visitor<E> visitor) {
            if (visitor == null) return;
            inorderTraversal(root, visitor);
        }
    
        private void inorderTraversal(Node<E> node, Visitor<E> visitor) {
            if (node == null || visitor.stop) return;
            inorderTraversal(node.left, visitor);
            if (visitor.stop) return;
            visitor.stop = visitor.visitor(node.element);
            inorderTraversal(node.right, visitor);
        }
    
        public void postorderTraversal(Visitor<E> visitor) {
            if (visitor == null) return;
            postorderTraversal(root, visitor);
        }
    
        private void postorderTraversal(Node<E> node, Visitor<E> visitor) {
            if (node == null || visitor.stop) return;
            postorderTraversal(node.left, visitor);
            postorderTraversal(node.right, visitor);
            if (visitor.stop) return;
            visitor.stop = visitor.visitor(node.element);
        }
    
        public void levelOrderTraversal(Visitor<E> visitor) {
            if (root == null || visitor == null) return;
            Queue<Node<E>> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()) {
                Node<E> poll = queue.poll();
                if (visitor.visitor(poll.element)) {
                    return;
                }
                if (poll.left != null) {
                    queue.offer(poll.left);
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                }
            }
        }
    
        protected Node<E> predesessor(Node<E> node) {
            if (node == null) return null;
            Node<E> p = node.left;
            if (p != null) {
                while (p.right != null) p = p.right;
                return p;
            }
            while (node.parent != null && node == node.parent.left) {
                node = node.parent;
            }
            // node.parent
            return node.parent;
        }
    
        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;
            }
            while (node.parent != null && node == node.parent.right) {
                node = node.parent;
            }
            return node.parent;
        }
    
        public int height() {
            return height(root);
        }
    
        private int height(Node<E> node) {
            if (node == null) return 0;
            return 1 + Math.max(height(node.left), height(node.right));
        }
    
        public int height1() {
            if (root == null) return 0;
            int height = 0; // 树高度
            int levelSize = 1;  // 每层的元素的数量
            Queue<Node<E>> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()) {
                Node<E> poll = queue.poll();
                levelSize--;
                if (poll.left != null) {
                    queue.offer(poll.left);
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                }
                if (levelSize == 0) {
                    levelSize = queue.size();
                    height++;
                }
            }
            return height;
        }
    
        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> poll = queue.poll();
                if (leaf && !poll.isLeaf()) return false;
    
                if (poll.left != null) {
                    queue.offer(poll.left);
                } else if (poll.right != null) {
                    return false;
                }
                if (poll.right != null) {
                    queue.offer(poll.right);
                } else {
                    leaf = true;
                }
            }
            return true;
        }
    
        public boolean isComplete1() {
            if (root == null) return false;
            Queue<Node<E>> queue = new LinkedList<>();
            queue.offer(root);
            boolean leaf = false;
            while (!queue.isEmpty()) {
                Node<E> poll = queue.poll();
                if (leaf && poll.isLeaf()) return false;
                if (poll.hasTwoChildren()) {
                    queue.offer(poll.left);
                    queue.offer(poll.right);
                } else if (poll.left == null && poll.right != null) {
                    return false;
                } else {
                    leaf = true;
                    if (poll.left != null) {
                        queue.offer(poll.left);
                    }
                }
            }
            return true;
        }
    
        protected static class Node<E> {
            public E element;
            public Node<E> left;
            public Node<E> right;
            public 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 static abstract class Visitor<E> {
            boolean stop;
    
            public abstract boolean visitor(E element);
        }
    }
    
  • 二叉搜索树实现

    package com.zimo..二叉搜索树;
    
    import com.zimo..BinaryTree;
    
    import java.util.Comparator;
    
    /**
     * 树 - 二叉树 - 重构二叉搜索树
     *
     * @author Liu_zimo
     * @version v0.1 by 2020/10/26 10:34:00
     */
    
    public class ReconsitutionBinarySearchTree<E> extends BinaryTree<E> {
    
        public static void main(String[] args) {
            ReconsitutionBinarySearchTree<Integer> b1 = new ReconsitutionBinarySearchTree<>();
            Integer[] integers = {7, 4, 9, 2, 5, 8, 11, 1, 3, 10, 12};
            for (Integer integer : integers) {
                b1.add(integer);
            }
            b1.preorderTraversal(new Visitor<Integer>() {
                @Override
                public boolean visitor(Integer element) {
                    System.out.print("_" + element + "_ ");
                    return element == 9 ? true : false; // 遇到9后续不打印
                }
            });
            System.out.println("\n树高为:" + b1.height() + b1.height1());
            System.out.println("是否为完全二叉树" + b1.isComplete());
            System.out.println(b1.predesessor(b1.root).element);
            System.out.println(b1.successor(b1.root).element);
            b1.remove(11);
            b1.remove(7);
            b1.preorderTraversal(new Visitor<Integer>() {
                @Override
                public boolean visitor(Integer element) {
                    System.out.print("_" + element + "_ ");
                    return false;
                }
            });
        }
    
        private Comparator<E> comparator;
    
        public ReconsitutionBinarySearchTree() {
            this(null);
        }
    
        public ReconsitutionBinarySearchTree(Comparator<E> comparator) {
            this.comparator = comparator;
        }
    
        public void add(E element) {
            elementNotNullCheck(element);
            if (root == null) {
                root = new Node<>(element, null);
                size++;
                return;
            } else {
                Node<E> node = this.root;
                Node<E> parent = null;
                int compare = 0;
                while (node != null) {
                    compare = compare(element, node.element);
                    parent = node;
                    if (compare > 0) {
                        node = node.right;
                    } else if (compare < 0) {
                        node = node.left;
                    } else { // 相等
                        node.element = element;
                        return;
                    }
                }
                Node<E> newNode = new Node<>(element, parent);
                if (compare > 0) {
                    parent.right = newNode;
                } else {
                    parent.left = newNode;
                }
                size++;
            }
        }
    
        public void remove(E element) {
            remove(node(element));
        }
    
        private void remove(Node<E> node) {
            if (node == null) return;
            size--;
            if (node.hasTwoChildren()) {
                Node<E> successor = successor(node);
                node.element = successor.element;
                node = successor;
            }
            Node<E> replacement = node.left != null ? node.left : node.right;
            if (replacement != null) {
                replacement.parent = node.parent;   // 更改parent
                if (node.parent == null) {   // 度为1的根节点
                    root = replacement;
                } else if (node == node.parent.left) {
                    node.parent.left = replacement;
                } else {
                    node.parent.right = replacement;
                }
            } else if (node.parent == null) {
                root = null;
            } else {
                if (node == node.parent.left) {
                    node.parent.left = null;
                } else {
                    node.parent.right = null;
                }
            }
        }
    
        private Node<E> node(E element) {
            Node<E> node = this.root;
            while (node != null) {
                int cmp = compare(element, node.element);
                if (cmp == 0) return node;
                if (cmp > 0) node = node.right;
                else node = node.left;
            }
            return null;
        }
    
        public boolean contains(E element) {
            return node(element) != null;
        }
    
        private int compare(E e1, E e2) {
            // return e1.compareTo(e2);
            if (comparator != null) {
                return comparator.compare(e1, e2);
            }
            return ((Comparable<E>) e1).compareTo(e2);   // 如果没实现比较器,默认为强制实现比较接口
        }
    
        private void elementNotNullCheck(E element) {
            if (element == null)
                throw new IllegalArgumentException("element元素不能为空");
        }
    }
    

    如果从小到大添加元素,二叉搜索树退化成链表,则复杂度为n,如果是平衡二叉树,则是log2n两者性能差异较大

    • 添加、删除节点时,都可能会导致二叉搜索树退化成链表
平衡二叉搜索树(Balanced Binary Search Tree)

英文简称:BBST

  • 平衡:当节点数量固定时,左右子树的高度越接近,这棵二叉树就越平衡(高度越低)
  • 理想平衡:最理想的平衡,就是像完全二叉树、满二叉树那样,高度最小

二叉搜索树改进:

二叉搜索树改进
经典常见的平衡二叉搜索树有:

  • AVL树

    ✓ Windows NT 内核中广泛使用

  • 红黑树

    ✓ C++ STL(比如map、set)

    ✓ Java的TreeMap、TreeSet、HashMap、HashSet

    ✓ Linux的进程调度

    ✓ Ngix的timer管理

  • 一般也称他们为:自平衡的二叉搜索树(Self-balancing Binary Search Tree)

AVL树
  • AVL树是最早发明的自平衡二叉搜索树之一
  • AVL取名于两位发明者的名字(G.M.Adeloson-Velsky和E.M.Landis)来自苏联的科学家
  • 网络上有些人把AVL树念作“艾薇儿树”
  • 平衡因子(Balance Factor):某节点的左右子树的高度差
  • AVL树的特点
    • 每个节点的平衡因子只可能是1,0,-1(绝对值 ≤ 1,如果超过1,称之为“失衡”)
    • 每个节点的左右子树高度差不超过1
    • 搜索、添加、删除的时间复杂度是O(log2n)

AVL树
AVL继承结构

  • 添加导致失衡
    • 最坏情况:可能会导致所有祖先节点都失衡
    • 父节点、非祖先节点,都不可能失衡
    • 只要让高度最低的失衡节点恢复平衡,整棵树就恢复平衡【仅需O(1)次调整】
    • LL - 右旋转(单旋)、RR - 左旋转(单旋)、LR - RR左旋转、LL右旋转(双旋)、RL - LL右旋转、RR左旋转(双旋)

添加导致失衡
统一所有旋转操作

  • 删除导致的失衡
    • 可能会导致父节点或者祖先节点失衡(只有一个节点会失衡),其他节点,都不可能失衡
    • 除父节点外的其他节点,都不可能失衡
    • 父节点恢复平衡后,可能会导致更高层的祖先节点失衡【最多需要O(log2n)次调整】

删除导致失衡

  • BinaryTree修改
// 二叉树 - 基类 修改的地方如下
public class BinaryTree<E> {
+   protected Node<E> createNode(E element, Node<E> parent){
        return new Node<>(element, parent);
    }
    protected static class Node<E> {
        public E element;
        public Node<E> left;
        public Node<E> right;
        public 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 && parent.left == this; }
+       public boolean isRightChild() { return parent != null && parent.right == this; }
    }
}
  • ReconsitutionBinarySearchTree修改
// 树 - 二叉树 - 重构二叉搜索树 修改的地方如下
public class ReconsitutionBinarySearchTree<E> extends BinaryTree<E> {

    public void add(E element) {
        elementNotNullCheck(element);
        if (root == null) {
            root = createNode(element, null);
            size++;
+           afterAdd(root);
            return;
        } else {
            Node<E> node = this.root;
            Node<E> parent = null;
            int compare = 0;
            while (node != null) {
                compare = compare(element, node.element);
                parent = node;
                if (compare > 0) {
                    node = node.right;
                } else if (compare < 0) {
                    node = node.left;
                } else { // 相等
                    node.element = element;
                    return;
                }
            }
            Node<E> newNode = createNode(element, parent);
            if (compare > 0) {
                parent.right = newNode;
            } else {
                parent.left = newNode;
            }
            size++;
+           afterAdd(newNode);
        }
    }
    
    private void remove(Node<E> node) {
        if (node == null) return;
        size--;
        if (node.hasTwoChildren()) {
            Node<E> successor = successor(node);
            node.element = successor.element;
            node = successor;
        }
        Node<E> replacement = node.left != null ? node.left : node.right;
        if (replacement != null) {
            replacement.parent = node.parent;   // 更改parent
            if (node.parent == null) {   // 度为1的根节点
                root = replacement;
            } else if (node == node.parent.left) {
                node.parent.left = replacement;
            } else {
                node.parent.right = replacement;
            }
+           afterRemove(node);	// 为了兼容红黑树和其他数据结构,不建议提取到外面去
        } else if (node.parent == null) {
            root = null;
+           afterRemove(node);
        } else {
            if (node == node.parent.left) {
                node.parent.left = null;
            } else {
                node.parent.right = null;
            }
+           afterRemove(node);
        }
    }

    /**
     * 添加node之后的调整
     * @param node 新添加的节点
     */
+   protected void afterAdd(Node<E> node){}
    
    /**
     * 删除node之后的调整
     * @param node 被删除的节点
     */
+   protected void afterRemove(Node<E> node){}
  • 新增AVL树类
package com.zimo..二叉搜索树;

import com.zimo..BinaryTree;

import java.util.Comparator;

/**
 * 树 - 二叉树 - 二叉搜索树 - AVL树
 *
 * @author Liu_zimo
 * @version v0.1 by 2020/10/26 15:01:54
 */
public class AVLTree<E> extends ReconsitutionBinarySearchTree<E>{
    public AVLTree() {
        this(null);
    }

    public AVLTree(Comparator comparator) {
        super(comparator);
    }

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

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

    @Override
    protected void afterRemove(Node<E> node) {
        while ((node = node.parent) != null){
            if (isBalanced(node)){
                // 更新高度
                updateHeight(node);
            }else {
                // 恢复平衡
                rebalance(node);
            }
        }
    }

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

    /**
     * 恢复平衡
     * @param node 高度最底的不平衡节点
     */
    private void rebalance(Node<E> node){
        Node<E> parent = ((AVLNode<E>)node).tallerChild();
        Node<E> child = ((AVLNode<E>)parent).tallerChild();
        if (parent.isLeftChild()){ // L
            if (child.isLeftChild()){   // LL
                rotateRight(node);
                // unifyRebalance(node,child.left,child,child.right,parent,parent.right,node,node.right);
            }else { //LR
                rotateLeft(parent);
                rotateRight(node);
                // unifyRebalance(node, parent.left, parent, child.left, child, child.right, node, node.right);
            }
        }else { // R
            if (child.isLeftChild()){ // RL
                rotateRight(parent);
                rotateLeft(node);
                // unifyRebalance(node, node.left, node, child.left, child, child.right, parent, parent.right);
            }else { // RR
                rotateLeft(node);
                // unifyRebalance(node, node.left, node, parent.left, parent, child.left, child, child.right);
            }
        }
    }

    // 左旋
    private void rotateLeft(Node<E> node){
        Node<E> parent = node.right;
        Node<E> child = parent.left;
        node.right = child;
        parent.left = node;

        afterRotate(node, parent, child);
    }

    // 右旋
    private void rotateRight(Node<E> node){
        Node<E> parent = node.left;
        Node<E> child = parent.right;
        node.left = child;
        parent.right = node;

        afterRotate(node, parent, child);
    }

    /**
     * 统一处理恢复平衡(不分情况左右旋转)
     * @param node
     */
    private void unifyRebalance(Node<E> oldRoot,
                                Node<E> nodeA, Node<E> nodeB, Node<E> nodeC,
                                Node<E> nodeD,
                                Node<E> nodeE, Node<E> nodeF, Node<E> nodeG,){
        // d成为子树的根节点
        nodeD.parent = oldRoot.parent;
        if (oldRoot.isLeftChild()){
            oldRoot.parent.left = nodeD;
        }else if (oldRoot.isRightChild()){
            oldRoot.parent.right = nodeD;
        }else {
            root = nodeD;
        }

        // a - b - c
        nodeB.left = nodeA;
        if (nodeA != null) nodeA.parent = nodeB;
        nodeB.right = nodeC;
        if (nodeC != null) nodeC.parent = nodeB;
        updateHeight(nodeB);

        // e - f - g
        nodeF.left = nodeE;
        if (nodeE != null) nodeE.parent = nodeF;
        nodeF.right = nodeG;
        if (nodeG != null) nodeG.parent = nodeF;
        updateHeight(nodeF);

        // b - d - f
        nodeD.left = nodeB;
        nodeD.right= nodeF;
        nodeB.parent = nodeD;
        nodeF.parent = nodeD;
        updateHeight(nodeD);
    }

    private void rotate

    private void afterRotate(Node<E> node, Node<E> parent, Node<E> child) {
        parent.parent = node.parent;
        if (node.isLeftChild()) {
            node.parent.left = parent;
        } else if (node.isRightChild()) {
            node.parent.right = parent;
        } else {
            root = parent;
        }
        if (child != null) child.parent = node;
        node.parent = parent;
        updateHeight(node);
        updateHeight(parent);
    }

    private void updateHeight(Node<E> node){
        ((AVLNode<E>)node).updateHeight();
    }

    private static 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 updateHeight(){
            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;
        }
    }
}
  • 平均时间
    • 搜索:O(log2n)
    • 添加:O(log2n),仅需O(1)次的旋转操作
    • 删除:O(log2n),最多需要O(log2n)次的旋转操作
B树(B-tree、B-树)

B树是一种平衡的多路搜索树,多用于文件系统、数据库的实现

  • 特点:

    • 1个节点可以存储超过2个元素、可以拥有超过2个子节点
    • 拥有二叉搜索树的一些性质
    • 平衡,每个节点的所有子树的高度一致
    • 比较矮
  • m阶B树的性质(m ≥ 2)

    假设一个节点存储的元素个数为x

    • 根节点:1 ≤ x ≤ m - 1

    • 根节点:ceil(m/2) - 1 ≤ x ≤ m - 1

    • 如果有子节点,子节点个数 y = x + 1

      • 根节点:2 ≤ y ≤ m

      • 非根节点:ceil(m/2) ≤ y ≤ m

        比如m = 3, 2 ≤ y ≤ 3,因此可以称为(2,3)树、2 - 3树

        比如m = 4, 2 ≤ y ≤ 4,因此可以称为(2,4)树、2 - 3 - 4树

        比如m = 5, 3 ≤ y ≤ 5,因此可以称为(3,5)树、3 - 4 - 5树

        比如m = 6, 3 ≤ y ≤ 6,因此可以称为(3,6)树

        若m = 2,那么b树就是二叉搜索树,数据库中实现一般用200 ~ 300阶B树

B树 VS 二叉搜索树
  • B树和二叉搜索树,在逻辑上是等价的
  • 多代节点合并,可以获得一个超级节点
    • 2代合并的超级节点,最多拥有4个子节点(至少是4阶B树)
    • 3代合并的超级节点,最多拥有8个子节点(至少是8阶B树)
    • n代合并的超级节点,最多拥有2n个子节点(至少是2n阶B树)
  • m阶B树,最多需要log2m代合并
搜索

B树搜索

添加

B树添加
添加上溢问题解决
B树添加上溢问题

删除

B树中,最后真正被删除的元素都在叶子节点中

B树删除

删除下溢问题解决

B树删除下溢

4阶B树

学习4阶B树(2-3-4树),将能更好理解红黑树

  • 性质:
    • 所有节点能存储的元素个数x:1 ≤ x ≤ 3
    • 所有非叶子节点的子节点个数y:2 ≤ y ≤ 4
红黑树(Red Black Tree)
  • 红黑树也是一种自平衡的二叉搜索树,以前也叫做平衡二叉B树(Symmetric Binary B-tree)
  • 红黑树必须满足以下5条性质
    1. 节点是RED或者BLACK
    2. 根节点是BLACK
    3. 叶子节点(外部节点,空节点)都是BLACK,空节点是假象出来,为了保证以前的节点度为2
    4. RED节点的子节点都是BLACK
      • RED节点的父节点都是BLACK
      • 从根节点到叶子节点的所有路径上不能有2个连续的RED节点
    5. 从任一节点到叶子节点的所有路径都包含相同数目的BLACK节点
红黑树的等价变换

红黑树等价变换

添加

红黑树添加

  • 添加操作的所有情况

红黑树添加所有情况

  • 添加:修复性质4 不能有连续红色节点
    红黑树添加-修复性质4
删除

红黑树删除情况分析

红黑树实现

继承结构修改:BinaryTree <- ReconsitutionBinarySearchTree <- BalanceBinarySearchTree <-(AVL/红黑树)

  • BinaryTree修改
protected static class Node<E> {
    public E element;
    public Node<E> left;
    public Node<E> right;
    public 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 && parent.left == this; }
    public boolean isRightChild() { return parent != null && parent.right == this; }

+   public Node<E> sibling(){
+       if (isLeftChild()) return parent.right;
+       if (isRightChild()) return parent.left;
+       return null;
+   }
}
  • ReconsitutionBinarySearchTree 修改
*	protected void afterRemove(Node<E> node, Node<E> replacement){}

	private void remove(Node<E> node) {
        if (node == null) return;
        size--;
        if (node.hasTwoChildren()) {
            Node<E> successor = successor(node);
            node.element = successor.element;
            node = successor;
        }
        Node<E> replacement = node.left != null ? node.left : node.right;
        if (replacement != null) {
            replacement.parent = node.parent;   // 更改parent
            if (node.parent == null) {   // 度为1的根节点
                root = replacement;
            } else if (node == node.parent.left) {
                node.parent.left = replacement;
            } else {
                node.parent.right = replacement;
            }
*           afterRemove(node, replacement);
        } else if (node.parent == null) {
            root = null;
*           afterRemove(node, null);
        } else {
            if (node == node.parent.left) {
                node.parent.left = null;
            } else {
                node.parent.right = null;
            }
*           afterRemove(node, null);
        }
    }
  • 新增BalanceBinarySearchTree
package com.zimo..二叉搜索树;

import java.util.Comparator;

/**
 * 平衡二叉搜索树
 *
 * @author Liu_zimo
 * @version v0.1 by 2020/10/29 17:02:40
 */
public class BalanceBinarySearchTree<E> extends ReconsitutionBinarySearchTree<E> {

    public BalanceBinarySearchTree() {
        this(null);
    }

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

    // 左旋
    protected void rotateLeft(Node<E> node){
        Node<E> parent = node.right;
        Node<E> child = parent.left;
        node.right = child;
        parent.left = node;

        afterRotate(node, parent, child);
    }

    // 右旋
    protected void rotateRight(Node<E> node){
        Node<E> parent = node.left;
        Node<E> child = parent.right;
        node.left = child;
        parent.right = node;

        afterRotate(node, parent, child);
    }

    protected void afterRotate(Node<E> node, Node<E> parent, Node<E> child) {
        parent.parent = node.parent;
        if (node.isLeftChild()) {
            node.parent.left = parent;
        } else if (node.isRightChild()) {
            node.parent.right = parent;
        } else {
            root = parent;
        }
        if (child != null) child.parent = node;
        node.parent = parent;
    }

    /**
     * 统一处理恢复平衡(不分情况左右旋转)
     * @param node
     */
    protected void unifyRebalance(Node<E> oldRoot,
                                Node<E> nodeA, Node<E> nodeB, Node<E> nodeC,
                                Node<E> nodeD,
                                Node<E> nodeE, Node<E> nodeF, Node<E> nodeG){
        // d成为子树的根节点
        nodeD.parent = oldRoot.parent;
        if (oldRoot.isLeftChild()){
            oldRoot.parent.left = nodeD;
        }else if (oldRoot.isRightChild()){
            oldRoot.parent.right = nodeD;
        }else {
            root = nodeD;
        }

        // a - b - c
        nodeB.left = nodeA;
        if (nodeA != null) nodeA.parent = nodeB;
        nodeB.right = nodeC;
        if (nodeC != null) nodeC.parent = nodeB;

        // e - f - g
        nodeF.left = nodeE;
        if (nodeE != null) nodeE.parent = nodeF;
        nodeF.right = nodeG;
        if (nodeG != null) nodeG.parent = nodeF;

        // b - d - f
        nodeD.left = nodeB;
        nodeD.right= nodeF;
        nodeB.parent = nodeD;
        nodeF.parent = nodeD;
    }
}
  • AVL树优化
*   public class AVLTree<E> extends BalanceBinarySearchTree<E>{    
        @Override
*   	protected void afterRemove(Node<E> node,  Node<E> replacement) {
            while ((node = node.parent) != null){
                if (isBalanced(node)){
                    // 更新高度
                    updateHeight(node);
                }else {
                    // 恢复平衡
                    rebalance(node);
                }
            }
        }
    }
  • 红黑树实现
package com.zimo..二叉搜索树;

import java.util.Comparator;

/**
 * 树 - 红黑树
 *
 * @author Liu_zimo
 * @version v0.1 by 2020/10/29 14:00:00
 */
public class RedBlackTree<E> extends BalanceBinarySearchTree<E> {
    private static final boolean RED = false;
    private static final boolean BLACK = true;

    public RedBlackTree() {
        this(null);
    }

    public RedBlackTree(Comparator comparator) {
        super(comparator);
    }

    @Override
    protected void afterAdd(Node<E> node) {
        Node<E> parent = node.parent;
        // 如果是根节点或者上溢到达根节点,直接染成黑色(一定要在isBlack之前处理根节点,否则null节点默认也是黑色)
        if (parent == null){
            black(node);
            return;
        }
        // 如果父节点是黑色,直接返回
        if (isBlack(parent)){ return; }
        // 父节点黑色处理完毕 
        // 祖父节点     // 优化1:无论啥情况,祖父节点都染成红色
        Node<E> grand = red(parent.parent);
        // uncle节点
        Node<E> uncle = parent.sibling();
        if (isRed(uncle)){  // 叔父节点是红色[B树节点上溢]
            // 父亲、叔父染黑色
            black(parent);
            black(uncle);
            // 祖父节点染红色,当作新添加元素重新插入
            // afterAdd(red(grand)); 优化1
            afterAdd(grand);
            return;
        }
        // 叔父节点不是红色
        if (parent.isLeftChild()){  // L
            // red(grand); 优化1
            if (node.isLeftChild()){    // LL
                black(parent);
            }else { // LR
                black(node);
                rotateLeft(parent);
            }
            rotateRight(grand);
        }else {     // R
            // red(grand); 优化1
            if (node.isLeftChild()){    // RL
                black(node);
                rotateRight(parent);
            }else { // RR
                black(parent);
            }
            rotateLeft(grand);
        }

    }

    @Override
    protected void afterRemove(Node<E> node, Node<E> replacement) {
        // 如果删除红色节点,不做任何处理
        if (isRed(node)) return;

        // 用于取代node的节点是红色
        if (isRed(replacement)){
            black(replacement);     // 将替代的子节点直接染成黑色
            return;
        }

        Node<E> parent = node.parent;
        // 删除的是根节点
        if (parent == null) return;

        // 删除的是黑色的叶子节点【下溢】
        boolean isleft = parent.left == null || node.isLeftChild(); //  node.isLeftChild()为了包含下面父节点删除情况
        Node<E> sibling = isleft ? parent.right : parent.left;
        // 1.兄弟是黑是红 无法使用node.sibling(),因为再执行afterRemove,node跟父节点切断了
        if (isleft){    // 被删除的节点在左边,兄弟在右边
            if (isRed(sibling)) {
                // 如果是红色转成黑色
                black(sibling);
                red(parent);
                rotateLeft(parent);
                // 更换兄弟
                sibling = parent.right;
            }
            // 2.兄弟节点是黑色,看左右是否有红色子节点借给我
            if (isBlack(sibling.left) && isBlack(sibling.right)){
                // 兄弟没有红色子节点,父节点向下跟兄弟节点合并
                boolean pIsBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (pIsBlack) {
                    afterRemove(parent,null);
                }
            }else{
                // 兄弟节点至少有一个红色子节点,向兄弟节点借元素
                if (isBlack(sibling.right)){   // 兄弟节点的左边是黑色,兄弟要先右旋转
                    rotateRight(sibling);
                    sibling = parent.right;
                }
                color(sibling, colorOf(parent));
                black(sibling.right);
                black(parent);
                rotateLeft(parent);
            }
        }else {     // 被删除的节点在右边,兄弟在左边
            if (isRed(sibling)) {
                // 如果是红色转成黑色
                black(sibling);
                red(parent);
                rotateRight(parent);
                // 更换兄弟
                sibling = parent.left;
            }
            // 2.兄弟节点是黑色,看左右是否有红色子节点借给我
            if (isBlack(sibling.left) && isBlack(sibling.right)){
                // 兄弟没有红色子节点,父节点向下跟兄弟节点合并
                boolean pIsBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (pIsBlack) {
                    afterRemove(parent,null);
                }
            }else{
                // 兄弟节点至少有一个红色子节点,向兄弟节点借元素
                if (isBlack(sibling.left)){   // 兄弟节点的左边是黑色,兄弟要先左旋转
                    rotateLeft(sibling);
                    sibling = parent.left;
                }
                color(sibling, colorOf(parent));
                black(sibling.left);
                black(parent);
                rotateRight(parent);
            }
        }
    }

    /**
     * 对节点进行染色
     * @param node 要染色的节点
     * @param color 要染的颜色
     * @return 返回染色的节点
     */
    private Node<E> color(Node<E> node, boolean color){
        if (node == null) return node;
        ((RBNode<E>) node).color = color;
        return node;
    }
    private Node<E> red(Node<E> node){ return color(node, RED); }
    private Node<E> black(Node<E> node){ return color(node, BLACK); }

    private boolean colorOf(Node<E> node){ return node == null ? BLACK : ((RBNode<E>) node).color; }

    private boolean isRed(Node<E> node){ return colorOf(node) == RED; }
    private boolean isBlack(Node<E> node){ return colorOf(node) == BLACK; }

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

    private static class RBNode<E> extends Node<E>{
        boolean color = RED;    // 默认染成红色,这样能够让红黑树的性质尽快满足

        public RBNode(E element, Node<E> parent) {
            super(element, parent);
        }
    }
}
红黑树优化
  • ReconsitutionBinarySearchTree 修改
*	protected void afterRemove(Node<E> node){}

	private void remove(Node<E> node) {
        if (node == null) return;
        size--;
        if (node.hasTwoChildren()) {
            Node<E> successor = successor(node);
            node.element = successor.element;
            node = successor;
        }
        Node<E> replacement = node.left != null ? node.left : node.right;
        if (replacement != null) {
            replacement.parent = node.parent;   // 更改parent
            if (node.parent == null) {   // 度为1的根节点
                root = replacement;
            } else if (node == node.parent.left) {
                node.parent.left = replacement;
            } else {
                node.parent.right = replacement;
            }
*           afterRemove(replacement);	// 对于AVL树毫无影响
        } else if (node.parent == null) {
            root = null;
*           afterRemove(node);
        } else {
            if (node == node.parent.left) {
                node.parent.left = null;
            } else {
                node.parent.right = null;
            }
*           afterRemove(node);
        }
    }
  • 红黑树修改优化
public class RedBlackTree<E> extends BalanceBinarySearchTree<E> {
    @Override
    protected void afterRemove(Node<E> node) {	// node可能是 被删除node或者被替换的replacementNode(度为1)
-       // 如果删除红色节点,不做任何处理
-       // if (isRed(node)) return;
        // 用于取代node的节点是红色
*       if (isRed(node)){
*           black(node);     // 将替代的子节点直接染成黑色
            return;
        }

        Node<E> parent = node.parent;
        if (parent == null) return;
        boolean isleft = parent.left == null || node.isLeftChild(); 
        Node<E> sibling = isleft ? parent.right : parent.left;
        if (isleft){    
            if (isRed(sibling)) {
                black(sibling);
                red(parent);
                rotateLeft(parent);
                sibling = parent.right;
            }
            if (isBlack(sibling.left) && isBlack(sibling.right)){
                boolean pIsBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (pIsBlack) {
*                   afterRemove(parent);
                }
            }else{
                if (isBlack(sibling.right)){  
                    rotateRight(sibling);
                    sibling = parent.right;
                }
                color(sibling, colorOf(parent));
                black(sibling.right);
                black(parent);
                rotateLeft(parent);
            }
        }else {    
            if (isRed(sibling)) {
                black(sibling);
                red(parent);
                rotateRight(parent);
                sibling = parent.left;
            }
            if (isBlack(sibling.left) && isBlack(sibling.right)){
                boolean pIsBlack = isBlack(parent);
                black(parent);
                red(sibling);
                if (pIsBlack) {
*                   afterRemove(parent);
                }
            }else{
                if (isBlack(sibling.left)){
                    rotateLeft(sibling);
                    sibling = parent.left;
                }
                color(sibling, colorOf(parent));
                black(sibling.left);
                black(parent);
                rotateRight(parent);
            }
        }
    } 
}
红黑树的平衡
  • 五条性质,可以保证 红黑树 等价于 4阶B树
  • 相比于AVL树,红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
  • 是一种弱平衡、黑高度平衡
  • 红黑树的最大高度是2 * log2(n + 1),依然是O(logn)级别
  • 平均时间复杂度:
    • 搜索:O(logn)
    • 添加:O(logn),O(1)次旋转操作
    • 删除:O(logn),O(1)次旋转操作
AVL树VS红黑树
  • AVL树

平衡标准比较严格:每个左右子树的高度差不超过1
最大高度是1.44 * log2(n + 2) - 1.328(100w个节点,AVL树最大树高28)
搜索、添加、删除都是O(logn)复杂度,其中添加仅需O(1)次旋转调整、删除最多需要O(logn)次旋转调整

  • 红黑树

红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
红黑树的最大高度是2 * log2(n + 1)(100w个节点,红黑树最大树高40)
搜索、添加、删除都是O(logn)复杂度,其中添加、删除仅需O(1)次旋转调整

  • 搜索的次数远远大于插入和删除,选择AVL树;搜索、插入、删除次数几乎差不多,选择红黑树
  • 相对于AVL树来说,红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树
  • 红黑树的平均统计性能优于AVL树,实际应用中更多选择使用红黑树
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳子陌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值