红黑树

红黑树是一种非严格平衡的二叉搜索树,它的每个节点都有红色或黑色,并遵循特定规则保持平衡。在插入和删除操作中,通过旋转和调整节点颜色保持黑节点平衡。本文介绍了红黑树的基本概念、插入节点的处理策略及其优势。

一.简介

红黑树作为一种二叉搜索树的一种实现,红黑树的左右子树高度差可能大于 1。所以红黑树不是严格意义上的平衡二叉树(AVL),但红黑树是黑色节点完美平衡, 其平均统计性能要强于 AVL 。

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。
1.节点是红色或黑色。

2.根节点是黑色。

3.每个红色节点的两个子节点都是黑色。(红色节点的子节点必须是黑色节点)

4.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

故红黑树是黑色平衡的树,左子树与右子树高度差不会超过2倍。红节点的父节点、子节点只能是黑节点

如果插入节点是黑色则所在路径将多出一个黑色节点,故新插入节点是红色节点(插入/删除红色节点不会改变所在路径黑色节点数量),通过旋转和调整节点颜色保证树的平衡

二.实现

红黑树增加/删除节点时需要保证子树黑节点平衡,有如下情况:

1.插入节点为树的根节点时,把根节点颜色修改为黑色

2.插入节点父节点是黑色节点,由于插入节点是红色节点,不会影响该子树黑色节点数量,故不用任何处理

3.插入节点父节点为红色且父节点的兄弟节点也为红色,父节点、父节点的兄弟节点修改为黑色,父节点的父节点修改为红色,再以父节点的父节点为插入节点递归处理

4.父节点为红色且父节点的兄弟节点为null或为黑节点
由于父节点是红色节点,故父节点的父节点为黑色节点

1)LL型
插入数据父节点的兄弟节点只会为null,如果不为null则父节点的兄弟节点子树与父节点将不是平衡的。

修改父节点为黑色节点,祖父节点修改为红色节点
对祖父节点右旋转,让父节点为子树根节点,由于子树黑节点数量没有发生变化,故旋转后黑节点数量和旋转前一样

2)LR型
父节点左旋转将变为LL型,按LL型处理

3)RR型
修改父节点为黑色,祖父节点修改为红色,对祖父节点左旋转,让父节点为子树根节点,旋转后和旋转前黑色节点数量没有改变,故事黑色节点平衡

4)RL型
父节点右旋转变为RR型,按RR型处理

示例说明:

插入数据:4,3,6,5,7,8,9,10,11

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


package com.vincent;


import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        RBTree<Integer> tree = new RBTree<>();
        for(Integer data : Arrays.asList(4,3,6,5,7,8,9,10,11)){
            tree.add(data);
            System.out.println(tree.getRoot());
        }
        System.out.println();
        List<Integer> list = tree.infixList();
        System.out.println(list);

        tree.delete(list.get(0));

        list = tree.infixList();
        System.out.println(list);

        tree.delete(list.get(list.size()-1));

        list = tree.infixList();
        System.out.println(list);

        tree.delete(list.get(list.size()/2));

        list = tree.infixList();
        System.out.println(list);
    }
}

//红黑树
class RBTree<T extends Comparable<T>>{
    private static final int RED = 0;
    private static final int BLACK = 1;

    static class Node<T extends Comparable<T>> {
        private T item;
        private int color = RED;
        private Node<T> left;
        private Node<T> right;
        private Node<T> parent;

        public Node(T item) {
            this.item = item;
        }

        public T getItem(){
            return item;
        }

        /**
         * 添加节点到当前节点树
         * @param node      添加的节点
         */
        public void add(Node<T> node){
            if(node.item.compareTo(this.item) <= 0){
                if(this.left == null){
                    this.left = node;
                    node.parent = this;
                }
                else{
                    this.left.add(node);
                }
            }
            else{
                if(this.right == null){
                    this.right = node;
                    node.parent = this;
                }
                else{
                    this.right.add(node);
                }
            }
        }


        /**
         * 通过item查找所在树的结点
         * @param item
         * @return
         */
        public Node<T> searchNode(T item){
            int cmp = item.compareTo(this.item);
            if(cmp == 0){
                return this;
            }
            Node<T> node = null;
            if(cmp < 0 && this.left != null && (node=this.left.searchNode(item)) != null){
                return node;
            }
            else if(cmp > 0 && this.right != null && (node=this.right.searchNode(item)) != null){
                return node;
            }
            return null;
        }

        /**
         * 删除节点,如果删除的节点为根节点将有NullPointerException
         */
        public void del(){
            Node<T> parent = this.parent;
            if(this.left==null && this.right==null){//删除节点为叶子节点
                if(parent.left == this){
                    parent.left = null;
                }
                else{
                    parent.right = null;
                }
            }
            else if(this.left == null){//删除节点只有右子树
                if(parent.left == this){
                    parent.left = this.right;
                }
                else{
                    parent.right = this.right;
                }
            }
            else if(this.right == null){//删除节点只有左子树
                if(parent.left == this){
                    parent.left = this.left;
                }
                else{
                    parent.right = this.left;
                }
            }
            else{//删除节点有左右节点,从删除节点左子树中寻找最大值
                Node<T> maxNode = this.left;
                while(maxNode.right != null){
                    maxNode = maxNode.right;
                }
                if(maxNode == this.left){//删除节点左子树的最大值就是删除节点的左节点
                    this.item = maxNode.item;
                    this.left = maxNode.left;
                }
                else{
                    maxNode.parent.right = null;
                    this.item = maxNode.item;
                }
            }
        }

        /**
         * 节点的中序遍历
         * @param dst   遍历节点的存放容器
         */
        public void infixList(List<T> dst){
            if(this.left != null){
                this.left.infixList(dst);
            }
            dst.add(this.item);
            if(this.right != null){
                this.right.infixList(dst);
            }
        }

        /**
         * 该节点树的最大高度
         * @return
         */
        public int height(){
            return Math.max(left==null?0:left.height(),right==null?0:right.height())+1;
        }

        /**
         * 对当前节点左旋转操作
         * @return  返回左旋转操作后子树根节点(即当前节点的右节点)
         */
        public Node<T> leftRotate(){
            if(this.right==null){
                return null;
            }
            Node<T> right = this.right;
            this.right = right.left;
            if(right.left != null) {
                right.left.parent = this;
            }

            right.left = this;
            right.parent = this.parent;
            if(this.parent != null) {
                if (this.parent.left == this) {
                    this.parent.left = right;
                } else {
                    this.parent.right = right;
                }
            }
            this.parent = right;
            return right;
        }

        /**
         * 对当前节点右旋转操作
         * @return  返回右旋转操作后子树根节点(即当前节点的左节点)
         */
        public Node<T> rightRotate(){
            if(this.left==null){
                return null;
            }
            Node<T> left = this.left;
            this.left = left.right;
            if(left.right != null) {
                left.right.parent = this;
            }

            left.right = this;
            left.parent = this.parent;
            if(this.parent != null) {
                if (this.parent.left == this) {
                    this.parent.left = left;
                } else {
                    this.parent.right = left;
                }
            }
            this.parent = left;
            return left;
        }

        @Override
        public String toString() {
            return "Node{" +
                    "item=" + item +
                    '}';
        }
    }

    private Node<T> root;

    Node<T> getRoot(){
        return root;
    }

    public void add(T item){
        Node<T> node = new Node<>(item);
        if(this.root == null){
            this.root = node;
        }
        else{
            Node<T> old = this.root.searchNode(item);
            if(old != null){
                old.item = item;
            }
            else{
                this.root.add(node);
            }
        }
        rebalance(node);
    }

    /**
     * 调整树的平衡性,会依次回溯到父节点
     * @param node      当前插入的节点
     */
    private void rebalance(Node<T> node){
        Node<T> parent = node.parent;
        if(parent == null){//树的根节点
            node.color = BLACK;
            return;
        }
        else if(parent.color == RED) {//红节点一定有父节点
            Node<T> pparent = parent.parent;
            //父节点的兄弟节点
            Node<T> psibling = pparent.left == parent ? pparent.right : pparent.left;
            if (psibling != null && psibling.color == RED) {
                parent.color = psibling.color = BLACK;
                pparent.color = RED;

                rebalance(pparent);
            }
            else if (psibling == null || psibling.color == BLACK) {
                Node<T> subRoot = null;
                if (pparent.left == parent && parent.left == node) {//LL型
                    parent.color = BLACK;
                    pparent.color = RED;
                    subRoot = pparent.rightRotate();

                } else if (pparent.left == parent && parent.right == node) {//LR型
                    parent.leftRotate();
                    node.color = BLACK;
                    pparent.color = RED;
                    subRoot = pparent.rightRotate();
                } else if (pparent.right == parent && parent.left == node) {//RL型
                    parent.rightRotate();
                    node.color = BLACK;
                    pparent.color = RED;
                    subRoot = pparent.leftRotate();
                } else {//RR型
                    parent.color = BLACK;
                    pparent.color = RED;
                    subRoot = pparent.leftRotate();
                }

                //设置树的根节点
                if (subRoot.parent == null) {
                    this.root = subRoot;
                }
            }
        }
    }

    public void delete(T item){
        Node<T> delNode = null;
        if(root.item.compareTo(item)==0){//删除根节点
            delNode = root;

            if(root.left==null && root.right==null){
                this.root = null;
            }
            else if(root.left==null){
                this.root = root.right;
            }
            else if(root.right==null){
                this.root = root.left;
            }
            else{//根节点有左右节点,扫描右子树最小节点
                Node<T> node = this.root.right;
                while(node.left!=null){
                    node = node.left;
                }
                if(node == this.root.right){
                    this.root.item = node.item;
                    this.root.right = node.right;
                }
                else {
                    node.parent.left = null;
                    this.root.item = node.item;
                }
            }
        }
        else {
            Node<T> node = this.root.searchNode(item);
            delNode = node;
            if (node != null) {
                node.del();
            }
        }
        if(delNode != null){
            this.rebalance(delNode);
        }
    }

    public List<T> infixList(){
        List<T> rst = new ArrayList<>();
        this.root.infixList(rst);
        return rst;
    }

    public int height(){
        return this.root.height();
    }

}

三.总结

红黑树的平衡处理相对AVL较为宽松,数据插入/删除时效率相对较高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值