C++ 学习日志 · 红黑树

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: C++ 学习日志 · 红黑树

红黑树:

红黑树 就和他的名字一样,树中只存在两种颜色的节点,他的本质也是一种二叉搜索树,它相对于使用平衡因子控制的二叉树,它会稍微宽松一些,控制平衡因子绝对值不超过1会比较严格也就意味着会有更多的旋转


红黑树的性质:

       ① 根节点是黑色

        ② 没有连续的红节点,红节点下一个节点必是黑节点

        ③ 每个节点的每条路径的都有相同数量的黑色节点

    ④ 每个叶子节点(空节点)都是黑色节点

综合以上的性质,可以得出新的性质:

       最长路径的节点个数不会超过最短路径的节点个数二倍

  最短路径:全是黑色节点

       最长路径:一黑一红交叉


模拟红黑树(三叉链):

insert:

红黑树和平衡二叉树相比,没有平衡二叉树那么严格,旋转的更少,但是既然要插入一个值,它的位置是可以根据子节点 左小右大 来确定,那它的颜色该如何选择呢?

       颜色的选择就要回归到红黑的性质(规则)上面

       如果插入的是红色节点,那么有可能破坏第②个规则

       如果插入的是黑色节点,那么就一定会破坏第③个规则,这样涉及新增节点的路径上的黑色

节点数量就会比其他的路径的黑色节点数量多一个

综上得出结论:插入的节点得是一个红色节点。 (毕竟这样我们还能"补救")

c6bfe2b5d76441cd9664932244e9921b.jpg

那大家看现在这种情况应该怎么调整颜色呢?

       调整颜色的同时也需要不破坏红黑树的规则:

       首先保证没有连续的红色节点,那么那么新节点的父亲节点就需要变成黑色,此时路径上的黑色节点的数量不统一,那么叔叔节点也应该变成黑色,

此时,最上面的爷爷节点,就要判断是否是根节点,如果是根节点则为黑色(规则第一条),不是则变为红色继续向上遍历   (如果此时爷爷不是根节点还保持黑色不变的话,那么图片中这一小的分支路径上面就会多出来一个节点)

e1065e4dfb6e4d1ea2c4c567e265abe0.jpg

bool insert(const pair<K, V>& data)
  {
    if (_root == nullptr)
    {
      _root = new node(data);
      _root->col = BLACK;
      return;
    }
    node* parent = nullptr;
    node* cur = _root;
    while (cur)
    {
      if (cur->_key > data)
      {
        parent = cur;
        cur = cur->_left;
      }
      else if (cur->_key < data)
      {
        parent = cur;
        cur = cur->_right;
      }
      else
      {
        return false;
      }
    }
    //插入新节点
    node* NewNode = new node(data);
    if (parent->_key > data)
    {
      parent->_left = NewNode;
    }
    else
    {
      parent->_right = NewNode;
    }
    cur = NewNode;
    while (parent && parent->col == RED)
    {
      node* groundnode = parent->_parent;
      if (groundnode->_left == parent)
      {
        node* unclenode = groundnode->_right;
        if (unclenode && unclenode == RED)
        {
          parent->col = unclenode->col = BLACK;
          groundnode->col = RED;
          cur = groundnode;
          parent = cur->_parent;
        }
      }
      else
      {
        node* unclenode = groundnode->_left;
      }
    }
  }

注意:颜色变化根子节点是父节点的左右没有关系

之前讨论的是叔叔节点存在且为黑的情况,那如果现在叔叔节点不存在呢

b5bbe071c5d54f32aeb440fa08dabbc5.jpg

这个时候就需要进行旋转了

2f8a4d21792c468486248b39417c831e.gif

注意:这个菱形代表的子节点的多种情况


现在如果叔叔节点,存在并且是黑色的呢?

4fb2d2c4a5124d98b606d7c0f306216a.jpg大家看这张图,就能明白有的时候一种情况,多数是由其他情况在调整的时候演变出来的上图就是叔叔节点存在且为黑的情况,那么此时应该怎么做呢?

c34d4cc799a64b90931d0df344ec90c9.gif

a462542fe31a46349eaeb1d80023f8ec.jpg

当然这个是右单旋(儿子节点、父亲节点它俩都是各自父亲节点的左节点),左单选的原理和这个是一样的.

bool insert(const pair<K, V>& data)
  {
    if (_root == nullptr)
    {
      _root = new node(data);
      _root->col = BLACK;
      return;
    }
    node* parent = nullptr;
    node* cur = _root;
    while (cur)
    {
      if (cur->_key > data)
      {
        parent = cur;
        cur = cur->_left;
      }
      else if (cur->_key < data)
      {
        parent = cur;
        cur = cur->_right;
      }
      else
      {
        return false;
      }
    }
    //插入新节点
    node* NewNode = new node(data);
    if (parent->_key > data)
    {
      parent->_left = NewNode;
    }
    else
    {
      parent->_right = NewNode;
    }
    cur = NewNode;
    while (parent && parent->col == RED)
    {
      node* groundnode = parent->_parent;
      if (groundnode->_left == parent)
      {
        node* unclenode = groundnode->_right;
        if (unclenode && unclenode == RED)
        {
          parent->col = unclenode->col = BLACK;
          groundnode->col = RED;
          cur = groundnode;
          parent = cur->_parent;
        }
        else
        {
          if (parent->_left == cur)
          {
            RotateR(groundnode);
            parent->col = BLACK;
            groundnode->col = RED;
          }
          else
          {
            RtotateL(parent);
            RtotateR(groundnode);
            cur->col = BLACK;
            groundnode->col = RED;
          }
          break;
        }
      }
      else
      {
        node* unclenode = groundnode->_left;
        if (unclenode && unclenode == RED)
        {
          parent->col = unclenode->col = BLACK;
          groundnode->col = RED;
          cur = groundnode;
          parent = cur->_parent;
        }
        else
        {
          if (parent->_right == cur)
          {
            RotateL(groundnode);
            parent->col = BLACK;
            groundnode->col = RED;
          }
          else
          {
            RtotateR(parent);
            RtotateL(groundnode);
            cur->col = BLACK;
            groundnode->col = RED;
          }
          break;
        }
      }
    }
  }


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
5天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
24 4
2023/11/10学习记录-C/C++对称分组加密DES
|
27天前
|
存储 C++
【C++】红黑树
红黑树是一种自平衡二叉搜索树,通过节点颜色(红或黑)及特定规则维持平衡,确保操作效率。其性质包括:每个节点非红即黑,根节点必黑,红节点的子节点必黑,从任一节点到其每个叶子的所有路径含相同数量的黑节点。实现上,通过节点结构定义、基本操作(插入、删除、旋转等)、维护平衡性质等步骤完成。代码示例展示了节点定义、插入操作及旋转调整方法。
25 2
【C++】红黑树
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
68 3
|
2月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
34 3
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
27 1
|
2月前
|
数据采集 监控 Java
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
本文是关于SpringBoot日志的详细教程,涵盖日志的定义、用途、SLF4J框架的使用、日志级别、持久化、文件分割及格式配置等内容。
202 0
SpringBoot日志全方位超详细手把手教程,零基础可学习 日志如何配置及SLF4J的使用......
|
2月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
42 0
|
2月前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
68 0
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
286 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
下一篇
DataWorks