首页 > 编程语言 >数据结构与算法-红黑树的java实现-构建红黑树

数据结构与算法-红黑树的java实现-构建红黑树

时间:2024-06-18 18:32:55浏览次数:24  
标签:right curr parent color 红黑树 java 数据结构 节点 left

红黑树

红黑树是一种二分查找树,与普通的二分查找树不同的一点是,红黑树的每个节点都有一个颜色(color)属性。该属性的值要么是红色,要么是黑色。

通过限制从根到叶子的任何简单路径上的节点颜色,红黑树确保没有比任何其他路径长两倍的路径,从而使树近似平衡。

节点

红黑树的节点记录父节点、左子节点、右子节点、数据和颜色(红色或黑色)

image-20240613114301748

红黑树特性

image-20240613151659210

红黑树节点关系图

红黑树中涉及: 父节点,爷节点(parent.parent), 叔父节点(parent.parent.right或 parent.parent.left), 兄弟节点(parent.right 或 parent.left)

image-20240613161453823

构建一颗二叉树(添加节点)

使用循环先构建一颗二叉搜索树(BST),

/**
 * 添加节点
 *
 * @param data
 */
public void add(int data) {

    if (root == null) {
        root = new Node(data);
        root.color = Color.BLACK;
        return;
    }

    Node curr = root; //记录根节点
    Node parent = null;  //记录父节点

    /*
      遍历到要插入新节点的位置,类似BST
     */
    while (curr != null) {
        parent = curr;  //记录父节点
        if (data < curr.data) {//走左侧位置
            curr = curr.left;
        } else {
            curr = curr.right;
        }
    }
    Node newNode = new Node(data);
    newNode.parent = parent;
    if (data < parent.data) {
        parent.left = newNode;
    } else {
        parent.right = newNode;
    }
    
     adjustTree(newNode); //调整红黑树
}

调整二叉树为红黑树

记录当前节点的父节点: Node parent = curr.parent;

在调整红黑树有以下几种可能:

  1. 要插入的节点的父节点是根节点
  2. 要插入的节点的父节点的颜色为黑色
  3. 要插入的节点的父节点颜色为红色,叔父节(父节点的兄弟节点)点为红色
  4. 要插入的节点的父节点颜色为红色,叔父节(父节点的兄弟节点)点为黑色
    • LL型: 父节点为左侧,插入节点在父节点左侧
    • LR型: 父节点为左侧,插入节点在父节点右侧
    • RR型: 父节点为右侧,插入节点在父节点右侧
    • RL型: 父节点为右侧,插入节点在父节点左侧

当前节点的父节点为根节点

当前节点的父节点为空,那么当前节点为根节点。将当前节点的颜色变成黑色。

if (parent == null) {
    curr.color = Color.BLACK;
    return;
}

当前节点的父节点为黑色

如果当前节点的父节点为黑色,不做调整,直接返回。

if(parent.color = Color.BLACK){
    return;
}

当前节点的父节点为红色,叔父节点为红色

当插入节点的父亲节点为红色,叔父节点也为红色。需要将父节点、叔父节点变成黑色,将爷节点变为红色。

Node uncleNode = uncle(parent);
    Node grandfatherNode = parent.parent;
    if (uncleNode.color == Color.RED) {
        parent.color = Color.BLACK;
        uncleNode.color = Color.BLACK;
        grandfatherNode.color = Color.RED;
        adjustTree(grandfatherNode);
        return;
    }

当前节点的父节点为红色,叔父节点为黑色

这种情况需要修改父亲的颜色为黑色爷节点颜色为红色,然后进行节点的旋转,由于父节点的位置和新插入节点位置不同,操作过程也不相同。我们把此种情况分为四类

类型父节点位置新节点位置操作方式
LL在爷节点的左侧在父节点的左侧右旋
LR在爷节点的左侧在父节点的右侧先左旋,后右旋
RR在爷节点的右侧在父节点的右侧左旋
RL在爷节点的右侧在父节点的右侧先右旋,后左旋
LL型

LL型: 当前节点的父节点在爷节点的左侧,要插入的当前节点在父节点的左侧 ,即Left Left(LL型)。

if (grandfatherNode.left == parent && curr == parent.left) {
    parent.color = Color.BLACK;
    grandfatherNode.color = Color.RED;
    //右旋
}
LR型

LR型: 当前节点父节点在爷节点的左侧,当前要添加的节点在父节点的右侧

else if (grandfatherNode.left == parent && curr == parent.right) {
    //parent在左侧,当前插入的节点在右侧(LR)

    //左旋
    curr.color = Color.BLACK;
    grandfatherNode.color = Color.RED;
    //右旋
 }
RR型

RR型: 当前节点的父节点在爷节点右侧,当前添加节点在父节点的右侧

else if (grandfatherNode.right == parent && curr == parent.right) {
    //RR
    parent.color = Color.BLACK;
    grandfatherNode.color = Color.RED;
    //左旋
}
RL型

RL型: 当前节点的父节点在爷节点右侧,当前添加节点在父节点的左侧

else {
    //RL
    //右旋
    curr.color = Color.BLACK;
    grandfatherNode.color = Color.RED;
    //左旋
}

右旋

此处的当前节点是传入的要插入节点的爷节点。

找到X节点
  1. 记录当(curr)前节点(实际上是指要插入节t3的爷节点)的左节点X。
  2. 记录t3节点,即X节点的右子节点
image-20240617110652242
Node x = curr.left;
Node t3 = x.right;
修改t3的父节点引用

如果t3节点不为空,将t3节点的父节点引用指向当前节点(curr)

image-20240617111218074
if(t3!=null) t3.parent =  curr;
当前节点左节点连接t3

当前节点断开与X的连接,左侧连接t3。

image-20240617112522840
curr.left = t3;
curr成为X的右子节点
  1. X节点的右节点连接curr;
  2. X的父节点为原curr的节点的父节点;
  3. curr节点的父节点为X
image-20240617112737450
x.right = curr;
x.parent = parent;
curr.parent = x;
parent节点连接X
  1. 如果parent为空,X节点为根节点
  2. 如果parent.left == curr , parent左侧连接X
  3. 如果parent.right = curr, parent右侧连接 X
image-20240617113546322
if(parent == null){
    this.root= x;
}else if(parent.left == curr){
    parent.left = x;
}else{
    parent.right = x;
}

左旋

/**
 * 左旋
 *
 * @param curr 当前节点
 */
private void leftRotate(Node curr) {
    Node parent = curr.parent;
    Node x = curr.right;

    Node t2 = x.left;
    if (t2 != null) {
        t2.parent = curr;
    }
    curr.right = t2;
    x.left = curr;
    x.parent = parent;
    curr.parent = x;

    if (parent == null) {
        this.root = x;
    } else if (parent.left == curr) {
        parent.left = x;
    } else {
        parent.right = x;
    }
}

parent = curr;
}
curr.right = t2;
x.left = curr;
x.parent = parent;
curr.parent = x;

if (parent == null) {
    this.root = x;
} else if (parent.left == curr) {
    parent.left = x;
} else {
    parent.right = x;
}

}


标签:right,curr,parent,color,红黑树,java,数据结构,节点,left
From: https://blog.csdn.net/qq_36115196/article/details/139760150

相关文章

  • 计算机Java项目|房屋租赁管理系统的设计与实现
    作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师主要内容:Java项目、Python项目、前端项目、人工智能与大数据、简历模板、学习资料、面试题库、技术互助收藏点赞不迷路 ......
  • 揭秘ThreadPoolExecutor:深度解析Java线程池的艺术与源码之美
    1.线程池概述在Java中,线程池(ThreadPool)是一种管理线程的技术,通过预先创建并管理一组线程,来减少频繁创建和销毁线程所带来的开销,从而提高系统的响应速度和吞吐量。ThreadPoolExecutor是Java并发包java.util.concurrent中的一个核心类,它提供了丰富的线程池功能。2.Thread......
  • JavaScript 的Blob 对象详解
    JavaScript的Blob对象详解:https://blog.csdn.net/qq_41152573/article/details/136225387?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171870454816800227415776%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=17187045481680......
  • 详谈JavaScript 二进制家族:Blob、File、FileReader、ArrayBuffer、Base64
    详谈JavaScript二进制家族:Blob、File、FileReader、ArrayBuffer、Base64:https://blog.csdn.net/weixin_43025151/article/details/129743443?ops_request_misc=&request_id=&biz_id=102&utm_term=JavaScript%E4%B8%AD%E7%9A%84Blob%E4%BD%A0%E7%9F%A5%E9%81%93%E5%A4%9A%E......
  • 列举几种常见的数据结构,以及线性数据结构
    数据结构是计算机科学中用来组织、存储和管理数据的方式。它定义了数据元素之间的逻辑关系,以及如何对数据进行操作。数据结构的选择对于算法的效率至关重要,因为它直接影响到数据在计算机中的存储和访问方式。以下是几种常见的数据结构:数组(Array):数组是一种线性数据结构,用......
  • 毕业设计:人事管理系统,基于java+springboot+mysql
     一、前言介绍          困扰管理层的许多问题当中,人事管理是一定不敢忽视的一块。但是管理好人事又面临很多麻烦需要解决,例如有几个方面:第一,公司往往员工人数都比较多,如何保证能够管理到每一员工;第二,如何在工作琐碎,记录繁多的情况下将人事变动的情况反应......
  • 【面试八股总结】Redis数据结构及底层实现
    一、五种基本数据结构        Redis提供了丰富的数据类型,常见的有五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)结构类型结构可存储值结构读写能力使用命令底层数据结构String字符串、整数或浮点数对字符串或字符串的一部分进行操作,对整数或浮点......
  • Flink1.17.0-报错: java.lang.NoSuchMethodError: org.apache.kafka.clients.admin.De
    背景:启动Flink的sql-client.sh,创建Kafka的source端表,然后查询Kafka的数据时报错。报错信息:2024-06-1816:10:12org.apache.flink.util.FlinkException:GlobalfailuretriggeredbyOperatorCoordinatorfor'Source:kafka_rmc_cust_analog_u[1]'(operatorbc764cd8ddf7a0c......
  • java freemarker实现单元格动态合并
    在Java项目中,使用FreeMarker模板引擎来动态生成Excel文件,并实现单元格的动态合并(特别是行合并)。可以通过以下步骤来完成:1.准备数据模型        需要准备一个合适的数据模型,该模型应能表示出哪些单元格需要合并。        例如,如果想要根据某一列的值来决定......
  • 采用java语言+Redis+RabbitMQ开发的 门诊his系统源码 一站式的门诊his系统 门诊业务流
    采用java语言+Redis+RabbitMQ开发的门诊his系统源码一站式的门诊his系统门诊业务流程医院信息系统(HIS系统)门诊业务是医院信息化建设的重要组成部分之一,它涵盖了医院门诊部门涉及的各项业务。HIS系统门诊业务的实施,可以实现医院门诊业务的信息化管理和数据化处理,提高医疗服......