【简易版tinySTL】 红黑树- 定义, 插入, 构建

文章目录

    • 旋转
      • 左旋
      • 右旋
    • 左旋右旋代码实现
    • 红黑树的基本性质
    • 红黑树的插入
    • 红黑树的插入示例
    • 红黑树修复代码实现
    • 参考资料

旋转

image-20240613095136796

对于一个平衡二叉搜索树,左子树高度为4,右子树高度为2,它们的高度差为2,破坏了平衡性(高度差<2才算平衡,因此需要调整二叉树使其平衡)

二叉树最基本的调整方式包括左旋、右旋:

左旋

  • 不平衡点没有左子树

image-20240613095515121

  • 不平衡点有左子树

image-20240613095615583

当结点5左旋时,由于有左子树3,会和结点6冲突,阻碍旋转,我们需要将"冲突的左孩变右孩",即将结点6连在被旋转点5的右孩子上

右旋

  • 不平衡点没有右子树

image-20240613095954955

  • 不平衡点有右子树

image-20240613100021786

当结点14右旋时,由于有右子树17,会和结点9冲突,阻碍旋转,我们需要将"冲突的右孩变左孩",即将结点9连在被旋转点14的左孩子上

左旋右旋代码实现

Node* rightRotate(Node* node)
{
    // node为失衡节点
    Node* l_son = node->left;

    // 不管是否会发生冲突,都把冲突的右孩变左孩
    node->left = l_son->right;
    // 右孩变左孩后,更新父节点(前提它不是空节点)
    if(node->left)
    {
        node->left->parent = node;
    }

    // 更新旋转中心的父节点指向
    l_son->parent = node->parent;
    // 如果当前节点(node)是根节点,则更新根节点为 l_son
    if(l_son->parent == nullptr)
    {
        root = l_son;
    }
    // 如果node是父结点的左子节点
    else if(node->parent->left == node)
    {
        node->parent->left = l_son;
    }
    else
    {
        // 如果node是父结点的右子节点
        node->parent->right = l_son;
    }

    // 把node结点接在l_son右边
    node->parent = l_son;
    l_son->right = node;

    return l_son;
}

Node* leftRotate(Node* node)
{
    Node* r_son = node->right;
    // 提前断掉右结点
    node->right = r_son->left;
    if(r_son->left)
    {
        node->right = r_son->left;
        r_son->left->parent = node;
    }

    r_son->parent = node->parent;
    if(r_son->parent == nullptr)
    {
        root = r_son;
    }
    else if(node->parent->left == node)
    {
        node->parent->left = r_son;
    }
    else
    {
        node->parent->right = r_son;
    }

    r_son->left = node;
    node->parent = r_son;

    return r_son;
}

红黑树的基本性质

空结点也是红黑树的叶子结点,也属于黑结点

  • 根叶黑:根和叶子结点默认为黑色
  • 不红红:不存在连续2个红色结点
  • 黑路同:任一结点到叶子结点的所有路径,黑结点的数量相同(包括空结点/叶子结点)

image-20240613100233691

红黑树的插入

要求:

  1. 默认插入的都是红色
  2. 插入情况讨论:
    • 插入的结点是根结点:直接变黑
    • 插入结点的叔叔结点是红色:叔父爷变色,当前指针指向爷爷结点,修复爷爷结点的红黑树性质
    • 插入结点的叔叔结点是黑色:先旋转(LL、RR、LR、RL),后变色

image-20240620191458222

image-20240620191519731

image-20240620192947162

红黑树的插入示例

假设我们要依次插入:17、18、23、34、27、15、9、6、8、5、25

我们每次插入之后,都要检查是否满足红黑树的性质

微信图片_20240620192221

红黑树修复代码实现

/*
		    O
		   /
		  O 
		 /
		O	<= target
*/
void insertFixup(Node* target) // target是当前插入的结点
{
    // 父结点存在,且出现红红
    while(target->parent && target->parent->color == Color::RED)
    {
        Node* father = target->parent;
        Node* g_father;
        if(father)
            g_father = father->parent;

        // 父是爷的左孩子
        if(g_father && g_father->left == father)
        {
            Node* uncle = g_father->right;
            // 如果叔结点存在,且颜色为红色
            if(uncle && uncle->color == Color::RED)
            {
                // 叔父爷变色
                uncle->color = Color::BLACK;
                father->color = Color::BLACK;
                g_father->color = Color::RED;
                // 将当前指针指向爷结点
                target = g_father;
            }
            // 叔结点不存在或者颜色为黑色(LL/LR)
            else
            {
                // LR
                if(target == g_father->left->right)
                {
                    // 先左旋,旋转函数的输入结点是失衡点
                    leftRotate(father);
                }
                // RR和LR后面的步骤都是一样的
                Node* t = rightRotate(g_father);
                // 变色
                t->color = Color::BLACK;
                t->right->color = Color::RED;
                t->left->color = Color::RED;
                return;
            }
        }

        if(g_father && g_father->right == father)
        {
            Node* uncle = g_father->left;
            if(uncle && uncle->color == Color::RED)
            {
                g_father->color = Color::RED;
                father->color = Color::BLACK;
                uncle->color = Color::BLACK;
                target = g_father;
            }
            else
            {
                // RL
                if(target == g_father->right->left)
                {
                    // !不是旋转父结点
                    rightRotate(father);
                }
                // LL和RL后续都一样
                Node* t = leftRotate(g_father);
                t->color = Color::BLACK;
                t->left->color = Color::RED;
                t->right->color = Color::RED;
                return;
            }
        }
        root->color = Color::BLACK;
    }
}

void insert(Key k, Value v)
{
    Node* node = new Node(k, v);
    Node* p = nullptr;
    Node* cur = root;
    if(this->size == 0)
    {
        root = node;
        size++;
        return;
    }
	// 找到插入点
    while(cur)
    {
        p = cur;
        if(k > cur->key)
        {
            cur = cur->right;
        }
        else if(k < cur->key)
        {
            cur = cur->left;
        }
        else
        {
            std::cout << "the key was in the tree" << std::endl;
            delete node;
            return;
        }
    }
    // 插入新结点
    size++;
    if(k > p->key)
    {
        p->right = node;
    }
    else
    {
        p->left = node;
    }

    node->parent = p;
    if(!p)
    {
        root = node;
    }
    // 修复红黑树
    insertFixup(node);
}

参考资料

红黑树 - 定义, 插入, 构建

红黑树 - 删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/760213.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IT之家最新科技热点

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

前端:Nuxt2 + Vuetify2

想要开发一个网站&#xff0c;并且支持SEO搜索&#xff0c;当然离不开我们的 Nuxt &#xff0c;那通过本篇文章让我们一起了解一下。如果构建一个Nuxt项目 安装 Nuxt&#xff0c;创建项目 安装nuxt2&#xff0c; 需要node v16&#xff0c;大家记得查看自己的node版本。构建脚…

初阶数据结构之堆讲解

本篇文章带大家学习的是堆&#xff0c;还请各位观众老爷给个三连 正片开始 堆的概念 如果有一个关键码的集合 K { &#xff0c; &#xff0c; &#xff0c; … &#xff0c; } &#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中&#xff0c;并满…

J021_QQ号格式校验

一、需求描述 校验QQ号码是否正确。要求全部是数字&#xff0c;数字长度&#xff08;6-20位之间&#xff09;&#xff0c;不能以0开头。 二、代码实现 package com.itheima.sort;public class Test {public static void main(String[] args) {System.out.println("----…

MySQL4(事务、函数、慢查询和索引)

目录 一、MySQL事务 1. 概念 2. 事务的ACID原则 3. MySQL实现事务的方法 4. MySQL实现事务的步骤 5. 事务的原子性、一致性、持久性 6. 事务的隔离性 7. MySql中的锁 1. 共享锁 2. 排他锁 3. 行级锁 4. 表级锁 5. 间隙锁 6. 临键锁 7. 记录锁 8. 意向共享锁…

1.spring入门案例

Spring 介绍 Spring是轻量级的开源的JavaEE框架。 Spring有两个核心部分&#xff1a;IOC和AOP IOC 控制反转&#xff0c;把创建对象过程交给Spring进行管理。 AOP 面向切面&#xff0c;不修改源代码进行功能增强。 Spring特点 1.方便解耦&#xff0c;简化开发。 2.AOP编…

docker安装sqlserver2019

1、背景 由于要学习flink cdc&#xff0c;并且数据源是sqlserver&#xff0c;所以这里采用docker安装sqlserver。 2、安装步骤 &#xff08;1&#xff09;建目录 // 创建指定的目录 mkdir sqlserver// 进入该目录 cd sqlserver// 创建/data/mssql目录 mkdir -p /data/mssql…

SpringBoot + mkcert ,解决本地及局域网(内网)HTTPS访问

本文主要解决访问SpringBoot开发的Web程序,本地及内网系统,需要HTTPS证书的问题。 我测试的版本是,其他版本不确定是否也正常,测试过没问题的小伙伴,可以在评论区将测试过的版本号留下,方便他人参考: <spring-boot.version>2.3.12.RELEASE</spring-boot.vers…

Ubuntu20.04安装vimplus插件

参考文章&#xff1a; Ubuntu Linux下vimplus的安装及使用安装vimplus之后乱码问题解决 1、安装步骤&#xff1a; $ git clone https://github.com/chxuan/vimplus.git ~/.vimplus$ cd ~/.vimplus$ ./install.sh2、./install.sh 过程 出现选择是否备份 /home/yin-roc/.vim…

注意力机制之ECA-Net:Efficient Channel Attention for Deep Convolutional Neural Network

论文link&#xff1a;link code&#xff1a;code 1.摘要 近年来&#xff0c;通道注意机制被证明在改善深层卷积神经网络&#xff08;CNN&#xff09;的性能方面提供了巨大的潜力。然而现有的大多数方法都致力于开发更复杂的注意模块以获得更好的性能&#xff0c;这不可避免地增…

博客都在使用的打字机效果,居然这么简单?

效果展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><style>body …

历年各省废水污染、治理数据

1996-2019年各省废水污染、治理数据https://download.csdn.net/download/a519573917/89485042 目录 摘要&#xff1a; 一、引言 二、文献综述 三、实证模型 &#xff08;一&#xff09;变量选择 &#xff08;二&#xff09;数据来源 &#xff08;三&#xff09;模型设定…

timm中模型更换huggingface模型链接

现在timm默认使用huggingface的链接了&#xff0c;错误链接如下&#xff1a; (MaxRetryError("HTTPSConnectionPool(hosthuggingface.co, port443): Max retries exceeded with url: /timm/swinv2_tiny_window8_256.ms_in1k/resolve/main/model.safetensors (Caused by C…

适用于智慧城市、智慧文旅等在线场景的轻量级3D数字人引擎MyAvatar简介

本人研发的国内首个纯面向web应用和小程序的轻量级3D虚拟人引擎MyAvatar。 功能简述 支持3D模型定制&#xff08;写实或卡通风格均可&#xff0c;人物模型需实现绑定和变形&#xff09;动画可以内置于模型中&#xff0c;也可以单独以glb或fbx格式导出并动态加载支持readyplay…

音频接口电路的PCB设计

Audio接口是音频插孔&#xff0c;即音频接口&#xff0c;可分为Audio in接口和Audio out接口。音频接口是连接麦克风和其他声源与计算机的设备&#xff0c;其在模拟和数字信号之间起到了桥梁连接的作用。对于平台的数字音频接RK3588口&#xff0c;需遵循《Rockchip RK3588 High…

时序分析之Clock rise/fall edge边沿对选取解析

目录 一、前言 二、Clock edge的选取逻辑 2.1 设计工程 2.2 同频同相 2.3 同频不同相1 2.4 同频不同相2 2.5 倍频关系(Fclk1>Fclk2) 2.6 倍频关系(Fclk1)<> 2.7 倍频关系存在相移(Fclk1)<> 2.8 非倍频关系无相移(Fclk1)<> 2.9 非倍频关系有相移…

在数字化转型中,中小企业如何打造数字化产品和服务?

引言&#xff1a;随着社会的发展和消费者行为的变化&#xff0c;市场对数字化产品和服务的需求日益增长。中小企业需要紧跟这一趋势&#xff0c;通过开发数字化产品和服务来满足消费者的新需求。云计算、大数据、人工智能等先进技术的出现&#xff0c;为中小企业提供了更多的机…

第5章_Modbus通讯协议

文章目录 5.1 学习Modbus的快速方法5.1.1 寄存器速记5.1.2 协议速记 5.2 初识Modbus5.2.1 背景5.2.2 什么是Modbus&#xff1f;1. Modbus简介2. Modbus特点3. Modbus常用术语4. Modbus事务处理 5.3 Modbus软件与使用5.3.1 Modbus软件简介5.3.2 Modbus Poll&#xff08;主站设备…

Pikachu靶场--Sql Inject

参考借鉴 pikachu靶场练习&#xff08;详细&#xff0c;完整&#xff0c;适合新手阅读&#xff09;-CSDN博客 数字型注入(post) 这种类型的SQL注入利用在用户输入处插入数值&#xff0c;而不是字符串。攻击者试图通过输入数字来修改SQL查询的逻辑&#xff0c;以执行恶意操作。…

C# OpenCvSharp 入门

摘要 C# OpenCvSharp 是一个基于OpenCV&#xff08;开源计算机视觉库&#xff09;的C#封装库&#xff0c;它提供了一组功能强大的工具和函数&#xff0c;用于图像处理、计算机视觉和计算机图形学等领域。通过使用OpenCvSharp库&#xff0c;您可以在C#应用程序中轻松地实现各种图…