C++ 学习日志 · 红黑树

简介: 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日志并进行多维度分析。
目录
相关文章
|
4天前
|
存储 编译器 C++
C++:map&set 对红黑树的封装
C++:map&set 对红黑树的封装
11 1
|
4天前
|
存储 算法 Java
数据结构/C++:红黑树
数据结构/C++:红黑树
15 3
|
4天前
|
编译器 C++
【C++】继续学习 string类 吧
首先不得不说的是由于历史原因,string的接口多达130多个,简直冗杂… 所以学习过程中,我们只需要选取常用的,好用的来进行使用即可(有种垃圾堆里翻美食的感觉)
9 1
|
4天前
|
算法 安全 程序员
【C++】STL学习之旅——初识STL,认识string类
现在我正式开始学习STL,这让我期待好久了,一想到不用手撕链表,手搓堆栈,心里非常爽
16 0
|
4天前
|
存储 安全 测试技术
【C++】string学习 — 手搓string类项目
C++ 的 string 类是 C++ 标准库中提供的一个用于处理字符串的类。它在 C++ 的历史中扮演了重要的角色,为字符串处理提供了更加方便、高效的方法。
18 0
【C++】string学习 — 手搓string类项目
|
4天前
|
存储 算法 编译器
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
【C++入门到精通】C++入门 —— 红黑树(自平衡二叉搜索树)
14 1
|
4天前
|
编译器 C语言 C++
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
23 0
|
4天前
|
SQL 监控 关系型数据库
【MySQL学习】MySQL的慢查询日志和错误日志
【MySQL学习】MySQL的慢查询日志和错误日志
|
4天前
|
C++
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
C++从入门到精通:2.1.2函数和类——深入学习面向对象的编程基础
|
4天前
|
关系型数据库 C++
【C++高阶(四)】红黑树深度剖析--手撕红黑树!
【C++高阶(四)】红黑树深度剖析--手撕红黑树!