【数据结构与算法分析】0基础带你学数据结构与算法分析12--红黑树

红黑树 (red-black tree) 是一种自平衡二叉树,于 1972 年由 Rudolf Bayer 发明,发明时被称为 对称二叉 B 树,现代名称红黑树来自 Knuth 的博士生 Robert Sedgewick 于 1978 年发表的论文。红黑树的结构复杂,但操作有着良好的最坏情况运行时间:它可以在 \mathcal{O}(\log_{}{N}) 时间内完成查找、插入和删除操作。

红黑树是具有下列着色性质的 BST:

  1. 每个结点要么是黑色要么是红色
  2. 根是黑色的
  3. 如果一个结点是红色的,那么它的子结点必须是黑色的
  4. 从一个结点到一个 NULL 指针的每一条路径都必须包含相同数目的黑色结点

根据着色规则,red-black tree 高度最多是 2\log_{}(N+1),因此查找保证是一种对数的操作。当然还有一条约定,空结点 nullptr 我们假设其为黑色,这样我们可以在不违反约定的情况下,方便操作。

通常困难在于将一个插入一个新结点后,如果将结点涂为黑色将违反性质 4,因为这会让路径上的黑色结点数量加一,但其他路径上黑色结点数量不变。

因此在插入结点时,默认结点为红色,父结点为黑色时,直接插入。在以下的情况中不再讨论这种情况。父结点是红色则会违反规则 3,在这种情况下必须修改树以满足所有性质。

红黑树的自底向上插入

如果新插入的结点 X 是红色的,它有父结点 P,兄弟结点 S,叔父结点 U,以及祖父结点 G。那么需要考虑几种情况:

  1. 如果 P、U 都是红色的,意味着 G 是黑色的,可以将 P、U 重绘为黑色将 G 重绘为红色,这样既不会违反规则 3 也不会违反规则 4。但是 G 之上的情况我们不知道,G 也可能是根,因此需要对 G 进行递归地向上进行重绘操作
  2. 如果 P 与 U 只有一个是红色的,意味着 G 是黑色的,而插入的 X 虽然不违反规则 4 但是违反了规则 3,迫使 X 或 P 变为黑色,而这样又会违反规则 4。为了让树再次符合要求,我们对其需要进行旋转操作并重绘结点颜色,其实这里的旋转操作与 AVL 树中是一致的,只是将结点的平衡因子转换为了颜色信息。 a. 当 X、P、G 形成 zig-zig 时,我们采用 single rotation b. 当 X、P、G 形成 zig-zag 时,我们采用 double rotation
// 该函数仅处理父结点是红色的情况,黑色情况则直接插入即可
// 使用头结点方便处理,头结点的 parent 指向 root,root 的 parent 指向 head
void insert_help(Node* node, Node* head) {
  // 当结点不是树的根或父结点是红色时,进行循环
  while (node != head->parent && node->parent->tag == RED) {
    Node* uncle = get_uncle(node);
    Node* grandparent = get_grandparent(node);
    Node* parent = node->parent;
    // 如果叔父结点不为空且为红色,符合情况 1
    if (uncle != nullptr && uncle->tag == RED) {
      parent->tag = uncle->tag = BLACK;
      grandparent->tag = RED;
      node = grandparent;
      continue;
    }
    // 判断 zig-zig 或 zig-zag 类型,进行相应的旋转
    if (parent == grandparent->left) {
      if (node == parent->right) { // l-r 的 zig-zag
	node = parent;
	parent = rotate_left(parent);
      }
      rotate_right(grandparent); // l-l 的 zig-zig
    } else {
      if (node == node->parent->left) { // r-l 的 zig-zag
	node = parent;
	parent = rotate_right(parent);
      }
      ratate_left(grandparent); // r-r 的 zig-zig
    }
    grandparent->tag = RED;
    parent->tag = BLACK;
  }
  head->parent->tag = BLACK;
}

红黑树的自顶向下插入

自底向上的操作需要父指针或栈保存路径,而自顶向下时实际是对红黑树应用自顶向下保证 S 不会时红色的过程。

在向下的过程中,如果结点 N 有两个红色的孩子时,将孩子重绘为黑色,结点 N 重绘为红色。结点 N 与其父结点 P 都为红色时,将违反红黑树的着色性质,此时对其进行 zig-zig 或 zig-zag 旋转即可。至于叔父结点 U 在自顶向下的过程中排除了红色的可能。

// 自顶向下插入,value 是待插入的值
void insert(Node* node, Node* head, T& value, Node** pos = nullptr) {
  bool inserted = false;
  if (node == nullptr) { // 插入结点,默认为红色
    node = new Node(value);
    *pos = node;
    inserted = true;
  }
  if (node->left != nullptr && node->left->tag == RED &&
      node->right != nullptr && node->right->tag == RED) {
    node->left->tag = node->right->tag = BLACK;
    node->tag = RED;
  }
  head->parent->tag = BLACK;
  Node* gp = get_grandparent(node);
  Node* parent = node->parent;
  if (node->tag == RED && parent->tag == RED) {
    // 判断 zig-zig 或 zig-zag 类型,进行相应的旋转
    if (parent == gp->left) {
      if (node == parent->right) { // l-r 的 zig-zag
	parent = rotate_left(parent);
      }
      rotate_right(gp); // l-l 的 zig-zig
    } else {
      if (node == parent->left) { // r-l 的 zig-zag
	parent = rotate_right(parent);
      }
      ratate_left(gp); // r-r 的 zig-zig
    }
    gp->tag = RED;
    parent->tag = BLACK;
  }
  if (inserted) {
    return;
  }
  if (node->val < value) {
    insert(node->left, head, &node->left, value);
  } else {
    insert(node->right, head, &node->right, value);
  }
}

红黑树的自顶向下删除

删除结点时,所有情况都可以归结于删除一个叶结点,因为删除带有两个孩子的结点,都可以与其左子树最大结点或右子树最小结点的值进行交换,这只改变了值没有改变颜色,并不影响红黑树的性质。之后删除交换后的叶结点即可。对于红色叶结点,我们可以将其直接删除,这不影响红黑树的结构,如果有孩子我们只需要用其孩子代替它即可。如此我们需要保证在自顶向下过程中保证叶结点是红色的。

假设当前结点是 N,其兄弟结点 S、父结点 P、叔父结点 U 和祖父结点 G。开始时需要将树根重涂为红色,沿树向下遍历,当到达一个结点时,确保 P 是红色、N 和 S 是黑色。在此过程中会遇到一些情况:

  1. N 有两个黑色的孩子,此时 a. S 也有两个黑色的孩子,那么重涂反转 N、S、P 的颜色,树结构不变 b. S 有红色的孩子,根据红色的孩子进行 signal rotate 或 double rotate。如果两个孩子都是红色,任选一个进行旋转即可
  2. N 有红色的孩子,此时向下递归 a. 新的 N 是红色,继续递归 b. 新的 N 是黑色,对 S 和 P 进行旋转,S 成为 P 的父结点,重绘 P 与 S 的颜色,即可得到红色的父结点 P。对于 P 来说,回到情况 1

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

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

相关文章

新的勒索软件是迄今为止最快的加密器

在一家美国公司遭到网络攻击后&#xff0c;恶意软件研究人员发现了一种似乎具有“技术独特功能”的新型勒索软件&#xff0c;他们将其命名为 Rorschach。 观察到的功能之一是加密速度&#xff0c;根据研究人员的测试&#xff0c;这将使 Rorschach 成为当今最快的勒索软件威胁。…

对Mysql的了解-索引

什么是索引? 索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树&#xff0c; B树和 Hash。 索引的作用就相当于目录的作用。打个比方: 我们在查字典的时候&#xff0c;如果没有目录&#xff0c;那我们就只能一页一页的去找我们需要查的那个字&#xff0c…

结合基于规则和机器学习的方法构建强大的混合系统

经过这些年的发展&#xff0c;我们都确信ML即使不能表现得更好&#xff0c;至少也可以在几乎所有地方与前ML时代的解决方案相匹配。比如说一些规则约束&#xff0c;我们都会想到能否把它们替换为基于树的ml模型。但是世界并不总是黑白分明的&#xff0c;虽然机器学习在解决问题…

nacos本地启动单节点

1.官网下载 Releases alibaba/nacos GitHub 解压文件 unzip nacos-server-2.2.1.zip cd /Users/xiaosa/dev_tools/nacos/bin sh startup.sh -m standalone 启动不成功&#xff0c;报错入如下 原因是下面的配置为空。位置在nacos/config目录下的application.properties文件…

【英语】大学英语CET考试,导学规划与听力题答题技巧笔记(1-2)

文章目录1、课程规划和导学1.1 试卷结构和备考目标1.2 单词&#xff0c;听力&#xff0c;阅读&#xff0c;真题学习方法2、听力技巧课1&#xff08;导学与发音&#xff09;3、听力技巧课2&#xff08;答题技巧&#xff01;重要&#xff01;&#xff09;1、课程规划和导学 主讲…

C语言中宏和函数的9个区别,你都了解吗?

C语言中的宏和函数是非常相似的&#xff0c;它们都可以完成类似的功能。比如&#xff0c;想要求2个数的较大值&#xff0c;使用宏的写法是&#xff1a; // 宏的定义 #define MAX(x, y) ((x)>(y)?(x):(y))// 使用 int m MAX(10, 20);使用函数的写法是&#xff1a; // 函数…

[Golang从零到壹] 1.环境搭建和第三方包管理

文章目录安装go环境go.mod第一种情况&#xff0c;选择GOPATH第二种情况&#xff0c;不选择GOPATH(推荐)GO111MODULEgo module可执行文件位置安装go环境 go在安装时选择好安装目录完成安装之后&#xff0c;还需要设置两个环境变量&#xff1a;GOROOT、GOPATH GOROOT即go的安装…

UnQLite入门

本文介绍UnQLite的基本使用&#xff0c;包括增删改查&#xff0c;事务ACID 文章目录UnQLite介绍UnQLite常用接口函数返回码DemoKey/Value存储数据库游标UnQLite介绍 UnQLite简介 UnQLite是&#xff0c;由 Symisc Systems公司出品的一个嵌入式C语言软件库&#xff0c;它实现了一…

Scrapy-核心架构

在之前的文章中&#xff0c;我们已经学习了如何使用Scrapy框架来编写爬虫项目&#xff0c;那么具体Scrapy框架中底层是如何架构的呢&#xff1f;Scrapy主要拥有哪些组件&#xff0c;爬虫具体的实现过程又是怎么样的呢&#xff1f; 为了更深入的了解Scrapy的相关只是&#xff0…

Chatgpt 指令收集

在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#xff0c;如果没给予指定情境与对象&#xff0c;它会不知道该如何回答的更加准确。 一、写报告 1、我现在正在 [报告的情境与目的]。…

低代码平台应该具备哪些能力?

什么样的低代码无代码平台才算好的平台呢&#xff0c;Gartner 共列出了低代码平台的11个关键能力维度&#xff1a; 1、易用性。易用性是标识低代码平台生产力的关键指标&#xff0c;是指在不写代码的情况下能够完成的功能的多少。 2、用户体验。一般来说&#xff0c;独立软件开…

2023Q2押题,华为OD机试用Python实现 -【机智的外卖员】

最近更新的博客 华为 od 2023 | 什么是华为 od,od 薪资待遇,od 机试题清单华为 OD 机试真题大全,用 Python 解华为机试题 | 机试宝典【华为 OD 机试】全流程解析+经验分享,题型分享,防作弊指南华为 od 机试,独家整理 已参加机试人员的实战技巧本篇题解:机智的外卖员 题目…

Java中的死锁

1.什么是死锁 死锁&#xff1a;多个线程同时被阻塞&#xff0c;它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期的阻塞&#xff0c;线程不可能正常终止。 【举个栗子】滑稽老铁和女生去吃饺子。吃饺子需要醋和饺子。 滑稽老哥抄起了酱油瓶&#xff0c;女生抄起…

【技术教程】在EasyCVR平台中打开第三方桌面端应用的实现过程

EasyCVR视频融合平台基于云边端协同架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;平台支持海量视频汇聚管理&#xff0c;可支持多协议接入&#xff0c;包括市场主流标准协议与厂家私有协议及SDK&#xff0c;如&#xff1a;国标GB28181、RTMP、RTSP/Onvif、海…

vue 引入高德地图当前定位失败 Get ipLocation failed.Geolocation permission denied.

getCurrentPosition 返回的 message 原因解析 &#xff1a; Get ipLocation failed&#xff1a;IP 精确定位失败&#xff0c;精确IP定位服务目前无法完全覆盖所有用户 IP&#xff0c;失败率在5%左右。sdk 定位失败&#xff1a;检查 sdk的 key 是否设置好&#xff0c;以及 webv…

如何远程连接SQLServer数据库

如何远程连接SQLServer数据库 准备工作 1.打开 选中如下的连接方式 连接成功后就会出出现 2.连接成功后&#xff1a;右键设置属性 安全性设置&#xff1a;如下图所示 设置连接属性&#xff1a; 设置完成之后点击完成&#xff01;&#xff01;&#xff01; 3.打开 启动sqlSe…

华为OD机试用JS实现 -【查找树中的元素 or 查找二叉树节点】(2023-Q2 押题)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:查找树中的元素 or 查找二叉树…

2023年南京晓庄学院五年一贯制专转本食品科学与工程专业考试大纲

2023年南京晓庄学院五年一贯制专转本食品科学与工程专业考试大纲 专业科目一 &#xff1a;微生物学基础 【参考书目】《食品微生物学》&#xff0c;杨玉红主编&#xff0c; 中国质检 出版社/中国标准出版社&#xff0c;2017(十三五高职高专院校规划教材) 【考试大纲】 ( 一) 考…

jsp054ssm高校学生成绩管理系统hsg421010A5程序

系统主要包含了学生信息管理、成绩信息管理等多个功能模块。下面分别简单阐述一下这几个功能模块需求。不同的权限对应相应的功能模块的需求&#xff0c;管理员权限的级别是最高的&#xff0c;所以所对应的需求是最多的&#xff0c;下面根据不同的权限分别简单阐述一下各个权限…

神奇智能搜索引擎:perplexity智能搜索引擎(ChatGPT与Edge合体——联网版chatGPT)

目录前言一、Perplexity AI网站介绍二、优点介绍2-0、界面介绍2-1、纯净、时效性、来源说明2-2、基于AI对话形式的搜索引擎三、使用方法介绍总结前言 ChatGPT背后的语言大模型OpenAI GPT 3.5&#xff0c;和微软的必应检索系统整合在一起&#xff1b;同时吸取这二者的长处&#…