数据结构 - 学习笔记 - 红黑树前传——234树

news2024/9/23 21:32:04

数据结构 - 学习笔记 - 红黑树前传——234树

  • 简介
  • 结点类型
  • 与红黑树对应关系
  • 插入逻辑
    • 插入步骤演示
    • 2结点插入
    • 3结点插入(红黑树旋转)
      • 共对应6种红黑树情形
      • 有4种情形需要再平衡
    • 4结点插入(红黑树变色)
      • 234树转红黑树
      • 触发分裂
      • 有4种情形需要变色实现平衡
      • 递归调整颜色
  • 删除逻辑
    • 删除步骤演示
    • 234树删除结点
    • 2结点删除
    • 3结点删除
    • 4结点删除
  • 辅助脚本
  • 总结

简介

在学习红黑树前需要先了解234树。因为红黑树就是由234树演变出来的。
了解了234树才能明白红黑树颜色变化的底层逻辑。

  1. 明明是包含123个结点,为什么不叫123树而叫234树。因为树的特性就是分叉,结点的命名是按它的分叉能力来的。我理解为:n结点就是能分n个叉的结点。(这怎么感觉跟制动有异曲同工之妙啊。)
  2. 234树 就是 4阶B树。也就是允许结点最多有4个子结点平衡多路查找树。
  3. 234树 是倒着长的。新元素插入到叶子,然后触发分裂向上提升元素成父级。

结点类型

结点结点内容子结点 s对应红黑树结点
2结点1元素个。
如:a
2个子结点或子结点
( , a), (a, )
黑色a
3结点2元素个。
如:a,b
3个子结点或子结点
( , a) , (a, b) , (b, )
父结点必需是黑色
黑色b—L→红色a
黑色a—R→红色b
4结点3元素个。
如:a,b,c
4个子结点或子结点
( , a) , (a, b) , (b, c) , (c, )
红色a←L—黑色b—R→红色c

与红黑树对应关系

在这里插入图片描述

  1. 上图中没有画出具体的子结点 仅用虚线框标识了一下子结点的取值范围。
  2. 不难看出,只要将红黑树中的红结点向上一提,与父结点合并,就反推出了234树
  3. 在平时分析红黑树时,可以直接在脑海里映射成234树来分析。这样变化旋转操作就有据可依,而不是死记硬背了。

插入逻辑

  1. 新元素插入到叶子结点,如果触发分裂,再提取元素与上级合并。
  2. 如果上提后,父级也触发分裂,则循环此操作,直到根结点。
插入场景插入前插入值插入后结论
当前无结点1[5]直接插入就完事了。
当前2结点[5]3[3, 5]2结点升级为3结点
当前3结点[3, 5]7[3, 5, 7]3结点升级为4结点
当前4结点[3, 5, 7]8[5]
[3, 7, 8]
4结点 插入新值后,出现5结点临时情况。
触发分裂:2 上升与原本的父结点合并。
1. 原本没有父结点,直接作为父结点。
2. 原父为2结点,合并。父结点变成3结点
3. 原父为3结点,合并。父结点变成4结点
4. 原父为4结点,合并。递归触发分裂

插入步骤演示

下图演示了234树的插入步骤,以及触发分裂的效果。
在这里插入图片描述

下图对应234树插入步骤,在右侧列出对应的红黑树。因为3结点红黑树存在两种情况,所以按排列组合方式一一列出。
对照前文的与红黑树对应关系,可以看到黑红颜色背后的逻辑来源于234树
在这里插入图片描述

2结点插入

2结点插入新值,直接升级为3结点,无需任何调整。
在这里插入图片描述

3结点插入(红黑树旋转)

3结点插入新值,直接升级为4结点,无需任何调整。
但在3结点对应的红黑树中,可能出现不平衡的情况。需要旋转调整实现平衡。

共对应6种红黑树情形

在这里插入图片描述

  1. 旋转方向的逻辑可以想象天平。左边重了往右挪(旋)右边重了往左挪(旋)
  2. 从上图可以看到有3个位置能插入子结点。对应 6 种红黑树的情形。
  3. 其中有2种是平衡的,无需调整。剩下4种 需要再平衡。

有4种情形需要再平衡

虽然共有4种 情形,但其中 LR可以转为LLRL可以转为RR。总之就是有拐弯的,最终也是转为一条直线,再处理。

  1. LL 右旋1次,实现平衡。
  2. RR 左旋1次,实现平衡。
  3. LR 左旋1次,转为 LL,重复 LL 的平衡操作。
  4. RL 右旋1次,转为 LL,重复 RR 的平衡操作。
    在这里插入图片描述

4结点插入(红黑树变色)

234树转红黑树

先简单的把 4结点红黑树 对应关系,罗列出来。根据新结点插入的位置不同,对应的红黑树也有所差异:
在这里插入图片描述

对应上图的步骤序号。

  1. 原234树为 357.
  2. 插入新元素。将要触发分裂。
  3. 先分裂。然后找到目标位置,与原有的2结点 合并成为3结点
    3.1. 如果还有父结点,分裂出去的结点,与原父结点合并。
    3.2. 如果原来的父结点也是一个4结点,将递归触发分裂
  4. 234树结点转红黑树结点。
    4.1. 所有 2结点 变为黑色。
    4.2. 3结点 展开,上黑下红。

触发分裂

单独分析一下触发分裂效果。

  1. 演示了从234树的角度来染色的逻辑(左)。
  2. 演示了从红黑树的角度来染色的公式(右)。
  3. 如果当前操作的只是一颗子树。比如结点2也是红色(需要旋转,对应RR公式),则需要继续处理,直至根。

在这里插入图片描述

有4种情形需要变色实现平衡

在这里插入图片描述

  1. 【234树】 插入新元素。将要触发分裂。
  2. 【234树】 先分裂。然后找到待插入的目标位置,与原有的2结点 合并成为3结点
  3. 【红黑树】 这是一个中间状态,为了便于观察才把它画出来。(3结点展开,但未调色,暂时还保持着不平衡的状态,便于观察)
  4. 【红黑树】 结点、叔伯结点变成黑色祖父结点变成红色
    4.1. 结点与祖父结点调换颜色:满足红结点子必的定义。同时对于插入新结点的这一路径来说黑结点数未发生变化。
    4.2. 叔伯结点变成黑色祖父结点原本作为公共的黑结点,挪给左路后,右路就少了一个黑结点。因此 叔伯要站出来变维持平衡。
  5. 【红黑树】 最后祖父结点更新为当前结点。
    5.1. 判断曾祖是否为红色。如果是,则需要向上递归调整颜色,一直到根。
    5.2. 如果是根,直接染

递归调整颜色

插入新结点 1 后递归触发变色。直到根结点为止。
在这里插入图片描述

删除逻辑

  1. 先删除。(作为一颗二叉树,删除结点)
  2. 再平衡。(作为一颗红黑树,调整颜色)

删除步骤演示

下图演示了234树的删除步骤,以及触发合并的效果。
同时,右则列表出对应的红黑树
234树中删除结点,为满足特性(子结点数量),需要向父兄结点借元素。此过程可能会引发合并。下图中也用虚线框标出了借兵过程。
在这里插入图片描述

234树删除结点

234树删除结点时,根据被删除的结点所包含的子结点个数不同,共有3种场景:

结点子结点数删除操作
2结点0个子结点直接删除。
3结点1个子结点1. 删除当前结点。
2. 子结点顶上来。(还要染成黑色,维持平衡)
4结点2个子结点1. 找到前驱后继结点。
2. 替换当前结点。
3. 再删除前驱后继结点。

2结点删除

删除结点后,当前位置空出,红黑树失去平衡。需要向父兄结点借元素来补位。
在这里插入图片描述

3结点删除

删除一个元素,变成2结点。保持平衡。

  • 红结点:直接删除即可。
  • 黑结点:删除黑结点,红结点补位,并变成黑色。

在这里插入图片描述

  1. 原234树结点,蓝色 标出是要删除的目标。
  2. 转为对应的红黑树
  3. 删除目标结点。
  4. 如果删的是父结点子结点上移补位。
  5. 补上来的结点染成原父结点的颜色。如果是根结点 直接填充黑色

4结点删除

删除一个元素,变成3结点。保持平衡。
4结点 的删除,如果忽略掉它的兄弟结点。本质上还是一个3结点的删除。
对应红黑树:

  • 红结点:直接删除即可。
  • 黑结点:删除黑结点,红结点补位,并变成黑色。

在这里插入图片描述

  1. 234树结点,蓝色 标出是要删除的目标。
  2. 转为对应的红黑树
  3. 删除目标结点。
  4. 如果删的是父结点子结点上移补位。
  5. 补上来的结点染成原父结点的颜色。如果是根结点 直接填充黑色。(虽然单看234树转过来的这个局部,父结点必定是黑色。但在一个完整红黑中,父结点有可能是红色)

辅助脚本

红黑树可视化演示

var sleep = (delaytime = 1000) => {
  return new Promise(resolve => setTimeout(resolve, delaytime))
}
async function delayDo(arr, callback = data=>console.log(`数据:${data}`), delaytime) {
    var len = arr.length;
    for (let i = 0; i <len  ; i++) {        
        await sleep(delaytime);
        callback(arr[i]);
    }
};
// 获取文本框
var [insertTxt, deleteTxt, findTxt] = [...document.querySelectorAll("#AlgorithmSpecificControls [type=Text]")];
// 获取按钮
var [insertBtn, deleteBtn, findBtn] = [...document.querySelectorAll("#AlgorithmSpecificControls [type=Button]")];
var process = {
	insert: function insert(v){	insertTxt.value = v; insertBtn.click();	},
	del: function del(v){ deleteTxt.value = v; deleteBtn.click(); },
	find: function find(v){ findTxt.value = v; findBtn.click(); }
}
// 遍历数组,间隔 n 秒处理一个元素。
function main(arr = [...Array(10).keys()], cb = v=>console.log(v), delaytime=200){
	delaytime = delaytime<200 ? 200 : delaytime
    delayDo(arr, v => cb(v), delaytime);
}
// 插入元素,间隔 200 毫秒
main([...Array(20).keys()].map(v=>v+1), process.insert, 200);

总结

  1. 可以将红黑树看作是234树的一个具体实现。
  2. 一颗234树可以对应多个234树。(因为 3结点 对应 红黑树 时可以左倾,也可以右倾)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

234. 回文链表

1、题目描述 额外要求&#xff1a;你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题&#xff1f; 2、题解 2.1 解题思路1 使用额外的栈空间&#xff0c;先将链表中所有的元素依次压入栈中&#xff0c;得到链表的逆序&#xff0c;然后将栈中的元素依次弹出和链表中的元素从…

C++关于初始化列表的细节(必须/不能使用初始化列表的情况、初始化列表的效率分析)

必须使用初始化列表初始化的变量 const修饰的成员变量。 class A { public:A() { a 1; }int a; };构造函数内使用a 1初始化变量a&#xff0c;但这本质上是一种赋值&#xff0c;而我们都知道&#xff0c;const类型的变量是不允许赋值的。 没有默认构造函数的成员变量 所有变量…

百度安全在线查询提示风险原因分析与解决思路

很多站长看到自己的网站被百度提示&#xff1a;“百度网址安全中心提醒您&#xff1a;该页面可能存在违法信息”&#xff0c;这样的提示&#xff0c;都会惊讶自己网站昨天还好好的&#xff0c;怎么今天就提示这样的信息呢&#xff1f;在弄清楚这个问题之前&#xff0c;我们要知…

实时频谱仪的外部I、Q输出端口的同步扫描介绍

实时频谱分析仪与外部GPIO&#xff0c;I、Q输出端口等集成在一起。外部GPIO由外部触发功能组成&#xff0c;通过使用外部硬件和/或多个RTSA设备&#xff0c;可以实现同步扫描设置&#xff0c;以自动进行频谱扫描和捕获。同时&#xff0c;I、Q输出端口有助于与外部高速数字化仪集…

联合证券|日元疯狂跳水30000点!神秘无人机现身韩国萨德基地!

刚刚&#xff0c;又有大事发生&#xff01; 日本央行意外宣告保持收益率曲线忍受区间不变。日元忽然大暴跌&#xff0c;日元兑美元狂泻超三万点。韩国也有大音讯&#xff0c;据韩联社报导&#xff0c;1月17日&#xff0c;一架无人机挨近韩国“萨德”基地时被美军用搅扰枪击落&a…

2023跳槽最新面试题整理——JVM系列

今天是农历2022年腊月二十七了&#xff0c;和往常的春节假期、五一假期和十一假期一样都是团队中坚持到最后的一个。没几天也要快过年了&#xff0c;我先提前向大家拜个早年——祝大家兔年大吉&#xff0c;新春快乐&#xff0c;财源滚滚&#xff0c;万事如意。 今年从十一…

如何使用 Selenium 实现自动化操作?

目录 前言 一、关于Selenium 1.1、为什么选择它作为web自动化的测试工具&#xff1f; 1.2、Selenium操作浏览器的原理 二、实现一个简单的自动化 2.1、使用自动化操作浏览器 2.2、Selenium常用的API 2.2.1、查找页面元素 小结 前言 本篇咱们来谈谈Selenium自动化脚本是…

pfx证书转pem、crt、key

今天测试端的服务器突然不能下载苹果APP了&#xff0c;经查看&#xff0c;发现原来是测试环境的https证书过期了&#xff0c;需要更换证书&#xff0c;于是赶紧从阿里云更新我们的最新证书 我们程序部署在tomcat上&#xff0c;于是下载tomcat版本&#xff0c;下载完成后如下 我…

【微信小程序-原生开发】实用教程05-首页(含自定义调试模式、插入图片、图文排版、底部留白、添加本地图片)

开始前&#xff0c;请先完成启动/欢迎/首屏广告页的开发&#xff0c;详见 【微信小程序-原生开发】实用教程04-启动/欢迎/首屏广告页&#xff08;含倒计时、添加文字、rpx、定义变量和函数、读取变量、修改变量、wx.reLaunch 页面跳转、生命周期 onReady等) https://blog.csdn…

输入设备应用

1.输入设备其实就是能够产生输入事件的设备就称为输入设备&#xff0c; 常见的输入设备包括鼠标、键盘、触摸屏、按钮等等&#xff0c;它们都能够产生输入事件&#xff0c;产生输入数据给计算机系统。2.对于输入设备的应用编程其主要是获取输入设备上报的数据、 输入设备当前状…

驱动程序那点事儿

是什么 驱动程序是一个软件组件&#xff0c;&#xff08;添加到操作系统中的一小块代码&#xff09;&#xff0c;是操作系统和设备通信的桥梁。应用程序需要从设备中读取某些数据&#xff0c;操作系统会调用由驱动程序实现的函数。驱动程序了解如何与设备硬件通信以获取数据。当…

菜鸟程序员如何快速进阶成为编程老司机?

菜鸟程序员如何摆脱稚嫩&#xff0c;快速成长为一名资深码农&#xff1f; 以下这些事情&#xff0c;帮你快速打好基础。 如果你想成为更好的开发者&#xff0c;你应该尤其注意第10点和第14点。 1.积极大胆地谷歌。你得知道如何有效地组织搜索关键字&#xff0c;查阅别人写的…

高并发系统设计 --热点key问题解决

热点Key问题&#xff0c;这是一个老生常谈的问题了&#xff0c;今天我们来仔细的去剖析这个问题。 热点key带来的问题 流量集中。达到服务器处理上限&#xff08;CPU&#xff0c;网络IO等&#xff09;会影响在同一个Redis实例上其他key的读写请求操作热key请求落到同一个Redi…

【魅力开源】第7集:开源ERP系统Odoo发展史(Odoo中文社区野史2019版)

文章目录前言历程后记前言 开源 ERP 系统 Odoo 的发展史。 历程 2002 年比利时13 岁开 始学习编程序的 Fabien Pinckaers 所创建创办了Tiny Sprl 公司。Tiny Sprl 公司的第一个产品就是开发 Tiny ERP&#xff0c;即后来的 OpenERP&#xff0c;现在改名为Odoo。 2007 年 Ope…

Sklearn标准化和归一化方法汇总(3):范数归一化

Sklearn中与特征缩放有关的五个函数和类&#xff0c;全部位于sklearn.preprocessing包内。作为一个系列文章&#xff0c;我们将逐一讲解Sklearn中提供的标准化和归一化方法&#xff0c;以下是本系列已发布的文章列表&#xff1a; Sklearn标准化和归一化方法汇总(1)&#xff1a…

博云荣获证券基金信创联盟年度优秀成员

1月12日&#xff0c;证券基金行业信息技术应用创新联盟&#xff08;以下简称“联盟”&#xff09;2022年度峰会在上海顺利举行。会上&#xff0c;联盟为2022年积极参与联盟工作的成员单位进行了颁奖&#xff0c;博云获评信创联盟年度优秀成员奖。 联盟是在中国证券监督管理委员…

Spring | SM整合(Spring+MyBatis)

0️⃣使用工具编辑器&#xff1a;IDEA企业版构建系统&#xff1a;Maven数据库&#xff1a;MySQL1️⃣创建项目&#x1f38f;创建maven项目选择新建项目&#xff0c;在E盘下创建名为SMDemo的项目&#xff0c;构建系统选择Maven.&#x1f38f;项目结构src/main/java - java 逻辑代…

企业宣传新闻稿撰写方法和技巧分享,纯干货

企业宣传新闻稿重点在于“宣传”&#xff0c;目的性强&#xff0c;具有极强的商业价值&#xff0c;怎么撰写是一大难关。 企业新闻稿堪比公关小组&#xff0c;表面上看起来只是简简单单一篇新闻稿&#xff0c;但是实际上企业新闻稿也能起到大作用&#xff0c;企业新闻稿的价值…

Python Kafka客户端性能测试比较

前言 由于工作原因使用到了 Kafka&#xff0c;而现有的代码并不能满足性能需求&#xff0c;所以需要开发高效读写 Kafka 的工具&#xff0c;本文是一个 Python Kafka Client 的性能测试记录&#xff0c;通过本次测试&#xff0c;可以知道选用什么第三方库的性能最高&#xff0c…

umi4+antd5兼容360安全浏览器

项目场景&#xff1a; umi4创建的大屏项目&#xff0c;部分模块使用了antd5进行开发 问题描述 开发完成后&#xff0c;得知客户是360安全浏览器&#xff0c;内核为86&#xff0c;测试过程中出现了样式混乱。 混乱样式有下拉内容的组件&#xff08;如select、dataPicker&#…