红黑树

原理

  1. 每个节点要么是红色要么是黑色
  2. 根节点是黑色
  3. 每个叶子节点(NIL)是黑色
  4. 每个红色节点的两个子节点一定都是黑色,不能红红相连
  5. 任意一个节点到每个叶子节点的路径都包含数量相同的黑节点(黑高)

自平衡操作

  1. 变色,节点的颜色由红色变黑或者由黑变红

  2. 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。
    在这里插入图片描述

  3. 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变
    在这里插入图片描述

插入操作

  • 插入节点,必须为红色,理由很简单,红色在父节点(如果存在)为黑色节点时,红黑树的黑色平衡没被破坏,不需要做自平衡操作。
    但如果插入结点是黑色,那么插入位置所在的子树黑色结点总是多1,必须做自平衡。

1. 情景1:红黑树为空树,直接把插入结点作为根结点就行

注意:根据红黑树性质2:根节点是黑色。还需要把插入结点设为黑色。

2. 情景2:插入结点的Key已存在处理:更新当前节点的值,为插入节点的值

3. 情景3:插入结点的父结点为黑结点由于插入的结点是红色的,当插入结点是红色时,并不会影响红黑树的平衡,直接插入即可,无需做自平衡。

4. 情景4 :插入节点的父节点为红色,根据性质2插入节点的父节点为红色,那么肯定存在爷爷节点

4.1 . 叔叔节点存在并且为红色,由性质4可知,红色节点不能相连,那么爷爷节点肯定为黑色节点。因为不可以同时存在两个相连的红节点,那么此时插入子树的红黑层数的情况是:黑红红。那么将其改为红黑红即可。

  1. 将P和U节点改为黑色
  2. 将PP改为红色
  3. 将PP设置为当前节点,进行后续处理
    在这里插入图片描述

4.2. 叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的左子结点

注意:单纯从插入前来看,叔叔节点非红即空(NIL节点),否则的话破坏了红黑树性质5,此路径会比其它路径多一个黑色节点

4.2.1. 新插入节点,为其父节点的左子节点(LL红色情况)
  • 处理:
  1. 变颜色:将P设置为黑色,将PP设置为红色
  2. 对PP节点进行右旋
    在这里插入图片描述
4.2.2. 新插入节点,为其父节点的右子节点(LR红色情况)

处理:
1.对P进行左旋
2. 将P设置为当前节点,得到LL红色情况
3. 按照LL红色情况处理(1.变颜色 2.右旋PP)

4.3. 叔叔结点不存在或为黑结点,并且插入结点的父亲结点是祖父结点的右子结点

4.3.1 新插入节点,为其父节点的右子节点(RR红色情况)
  • 处理:
  1. 变颜色:将P设置为黑色,将PP设置为红色
  2. 对PP节点进行左旋
    在这里插入图片描述
4.3.2 新插入节点,为其父节点的左子节点(RL红色情况)
  • 处理:
  1. 对P进行右旋
  2. 将P设置为当前节点,得到RR红色情况
  3. 按照RR红色情况处理(1.变颜色 2.左旋PP)
    在这里插入图片描述

代码

package cn.wy.datastruct.tree;

import java.util.Scanner;

public class RBTree <K extends Comparable<K>, V> {
   
    //定义颜色常量
    private static final boolean RED = true;
    private static final boolean BLACK = false;

    //红黑树的树根
    private static RBNode root;

    public RBNode getRoot() {
   
        return root;
    }

    /**
     * 公开的插入接口
     * @param key 键
     * @param value 值
     */
    public void insert(K key, V value) {
   
        RBNode node = new RBNode();
        node.setKey(key);
        node.setValue(value);
        node.setColor(RED);
        insert(node);
    }

    /**
     * 内部插入接口定义
     */
    private void insert(RBNode node) {
   
        //1.找到插入的位置
        RBNode parent = null;
        RBNode x = this.root;
        while(x != null) {
   
            parent = x;

            //a > b 则返回 1,否则返回 -1 ,相等返回0
            int cmp = node.key.compareTo(parent.key);

            if(cmp < 0) {
   
                x = x.left;
            } else if(cmp == 0) {
   
                parent.setValue(node.value);
                return;
            } else {
   
                x = x.right;
            }
        }

        node.parent = parent;

        if(parent != null) {
   
            if(node.key.compareTo(parent.key) < 0) {
   
                parent.left = node;
            } else {
   
                parent.right = node;
            }
        } else {
   
            this.root = node;
        }

        //插入之后需要进行修复红黑树,让红黑树再次平衡。
        insertFixUp(node);
    }


    /**
     * 插入后修复红黑树平衡的方法
     *     |---情景1:红黑树为空树
     *     |---情景2:插入节点的key已经存在
     *     |---情景3:插入节点的父节点为黑色
     *
     *     情景4 需要咱们去处理
     *     |---情景4:插入节点的父节点为红色
     *          |---情景4.1:叔叔节点存在,并且为红色(父-叔 双红)
     *          |---情景4.2:叔叔节点不存在,或者为黑色,父节点为爷爷节点的左子树
     *               |---情景4.2.1:插入节点为其父节点的左子节点(LL情况)
     *               |---情景4.2.2:插入节点为其父节点的右子节点(LR情况)
     *          |---情景4.3:叔叔节点不存在,或者为黑色,父节点为爷爷节点的右子树
     *               |---情景4.3.1:插入节点为其父节点的右子节点(RR情况)
     *               |---情景4.3.2:插入节点为其父节点的左子节点(RL情况)
     */
    private void insertFixUp(RBNode node) {
   
        RBNode parent = parentOf(node);
        RBNode gparent = parentOf(parent);
        //存在父节点且父节点为红色
        if(parent != null && isRed(parent
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值