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日志并进行多维度分析。
目录
相关文章
|
1月前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
54 16
|
2月前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
63 4
2023/11/10学习记录-C/C++对称分组加密DES
|
2月前
|
存储 算法 安全
基于红黑树的局域网上网行为控制C++ 算法解析
在当今网络环境中,局域网上网行为控制对企业和学校至关重要。本文探讨了一种基于红黑树数据结构的高效算法,用于管理用户的上网行为,如IP地址、上网时长、访问网站类别和流量使用情况。通过红黑树的自平衡特性,确保了高效的查找、插入和删除操作。文中提供了C++代码示例,展示了如何实现该算法,并强调其在网络管理中的应用价值。
|
3月前
|
存储 C++
【C++】红黑树
红黑树是一种自平衡二叉搜索树,通过节点颜色(红或黑)及特定规则维持平衡,确保操作效率。其性质包括:每个节点非红即黑,根节点必黑,红节点的子节点必黑,从任一节点到其每个叶子的所有路径含相同数量的黑节点。实现上,通过节点结构定义、基本操作(插入、删除、旋转等)、维护平衡性质等步骤完成。代码示例展示了节点定义、插入操作及旋转调整方法。
39 2
【C++】红黑树
|
4月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
4月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
155 3
|
4月前
|
存储 Prometheus NoSQL
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
大数据-44 Redis 慢查询日志 监视器 慢查询测试学习
49 3
|
4月前
|
Python
log日志学习
【10月更文挑战第9天】 python处理log打印模块log的使用和介绍
72 0
|
4月前
|
缓存 Linux 编译器
【C++】CentOS环境搭建-安装log4cplus日志组件包及报错解决方案
通过上述步骤,您应该能够在CentOS环境中成功安装并使用log4cplus日志组件。面对任何安装或使用过程中出现的问题,仔细检查错误信息,对照提供的解决方案进行调整,通常都能找到合适的解决之道。log4cplus的强大功能将为您的项目提供灵活、高效的日志管理方案,助力软件开发与维护。
125 0
|
30天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
67 19