码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 数据结构: 红黑树


    目录

    1.红黑树概念

    2.红黑树性质

    3.调整

    1.如果p和u都是红色,将其都改为黑色即可,然后向上调整

    2.如果p红(u黑/u不在),这时候左子树两红,于是给右子树一个红(旋转+变色)

    2.1右单旋 + 变色- p变黑, g变红, 达到给右子树一个红节点的效果, 并保持每条路径上黑色节点的个数相同

    2.2左右双旋转 + 变色

    2.3左单旋 + 变色

    2.4右左双选 + 变色

    4.红黑树的简单实现

    4.1红黑树的定义

    4.2相关功能

    插入

    检查

    获取最左/右侧的节点

    检查树种是否存在data节点

    4.3默认成员函数

    测试用例:

    1.插入

    2.检查

    3.获取最左/右侧节点

    4.在树种查找节点


    1.红黑树概念

    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的

    2.红黑树性质

    1. 每个结点不是红色就是黑色
    2. 根节点是黑色的
    3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
    4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
    5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

    最短路径: 全黑

    最长路径: 一黑一红交替

    红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍

    红黑树优势: 旋转次数更少

    新插入的节点默认是红色

    --1.如果是黑色, 一定违反了规则4 会影响所有路径

    --2.如果是红色, 当插入到红色节点后面,违反规则3 , 当插入到黑色节点的后面,不违反规则

    3.调整

    什么时候需要修改红黑树?--当插入到红色节点后面的时候

    1.如果p和u都是红色,将其都改为黑色即可,然后向上调整

    • -然后将g改为红(g原来为黑,我们已经把p,u改为黑了,会多一个黑节点,违反规则4,需要把g改为红)
    • -当然改为红后,g的p可能也是红,继续往上调整即可(把cur = g),如果最后调到根,要将根变黑

    2.如果p红(u黑/u不在),这时候左子树两红,于是给右子树一个红(旋转+变色)

    -这种情况讨论cur的插入位置 ,来决定其需要怎么旋转(单旋,双旋)

    --p是g的左 ,且插入的节点在左子树

    2.1右单旋 + 变色
    - p变黑, g变红, 达到给右子树一个红节点的效果, 并保持每条路径上黑色节点的个数相同

    2.2左右双旋转 + 变色

    --p是g的右, 且插入的节点在右子树

    2.3左单旋 + 变色

    2.4右左双选 + 变色

    4.红黑树的简单实现

    4.1红黑树的定义

    节点

    RBTree

    4.2相关功能

    插入

    1.找到节点的位置

    2.链接节点

    3.判断此时p是不是红色, 且存在 (默认插入的节点是红色), 是的话就需要调整

      --p,u存在且都为红 ===> 直接将p,u变为黑色,g变红色, 然后向上调整,

      如果调到根(要将其变黑)

      --p红, u红/u不在    ===> 对插入节点位置进行讨论

    1.p是g的左, cur是 p的左  ===> g右单旋

    2.p是g的左, cur是p的右   ===>  p左旋, g右旋

    3.p是g的右, cur是p的右   ===>  g左单旋

    4.p是g的右, cur是p的左   ===>  p右旋,g左旋

    代码:

    1.找到节点的位置 2.链接节点

    ​​​​​​​​​​​​​​

    3.判断此时p是不是红色, 且存在 (默认插入的节点是红色), 是的话就需要调整

    效果:

    检查

    1. 判断根节点是黑色的(规则2)
    2. 判断有无连续的红色节点(规则3)
    3. 判断每条路径上的黑色节点个数是否相等(规则4)                                                             --这里随便选取一条路径的黑色节点数作为基准值, 用来和对比其它路径黑节点的个数

    代码:

    1. //红黑树的检查
    2. bool Is_RBTree()
    3. {
    4. return _Is_RBTree(_root);
    5. }
    6. //红黑树的检查
    7. bool _Is_RBTree(Node* root)
    8. {
    9. //规则2:根节点是黑色的
    10. if (root == nullptr) return true;
    11. if (root->_color != BLACK) return false;
    12. //规则3:不能有连续的红色节点
    13. //规则4:每条路径上的黑色节点个数相等
    14. Node* cur = root; int base_nums = 0;
    15. while (cur)
    16. {
    17. if (cur->_color == BLACK) base_nums++;
    18. cur = cur->_left;
    19. }
    20. Check(root,base_nums,0);
    21. }
    22. bool Check(Node* root,int base_nums,int block_nums)
    23. {
    24. if (root == nullptr)
    25. {
    26. if (base_nums != block_nums) return false;
    27. return true;
    28. }
    29. //检查有没有连续的红色节点
    30. if (root->_parent && root->_color == RED && root->_parent->_color == RED)
    31. return false;
    32. //遇到一个黑色节点就++
    33. if (root->_color == BLACK) block_nums++;
    34. return Check(root->_left,base_nums,block_nums)
    35. && Check(root->_right,base_nums,block_nums);
    36. }

    获取最左/右侧的节点

    1. //获取红黑树最左侧节点
    2. Node* LeftMost()
    3. {
    4. Node* cur = _root;
    5. //空树
    6. if (cur == nullptr) return nullptr;
    7. while (cur->_left)
    8. {
    9. cur = cur->_left;
    10. }
    11. return cur;
    12. }
    13. //获取红黑树最右侧节点
    14. Node* RightMost()
    15. {
    16. Node* cur = _root;
    17. //空树
    18. if (cur == nullptr) return nullptr;
    19. while (cur->_right)
    20. {
    21. cur = cur->_right;
    22. }
    23. return cur;
    24. }

    检查树种是否存在data节点

    1. //检测红黑树中是否存在值为data的节点
    2. Node* Find(const T& data)
    3. {
    4. Node* cur = _root;
    5. while (cur)
    6. {
    7. if (cur->_data > data)
    8. cur = cur->_left;
    9. else if (cur->_data < data)
    10. cur = cur->_right;
    11. else return cur;
    12. }
    13. return nullptr;
    14. }

    4.3默认成员函数

    --构造函数

    这里传了缺省值(可不写)

    --拷贝构造

    思路:使用前序遍历, 构造红黑树

    --赋值运算符

    思路: 交换_root

    --析构函数

    后序遍历,删除节点

    测试用例:

    1.插入

    2.检查

    正常情况:

    异常:

    屏蔽掉颜色的调整

    修改默认生成黑色节点

    3.获取最左/右侧节点

    4.在树种查找节点

    代码:RB-Tree/RB-Tree · 朱垚/数据结构练习 - 码云 - 开源中国 (gitee.com)

  • 相关阅读:
    当酷雷曼VR直播遇上视频号,会摩擦出怎样的火花?
    ant-design-vue的日期选择器默认时间的时分秒
    R计算 地理集中指数
    开发deepstram的自定义插件,使用gst-dseaxmple插件进行扩充,实现deepstream图像输出前的预处理,实现图像自定义绘制图(精四)
    正大国际期货:如何提升外盘恒指交易技巧?
    Azure AD混合部署,通过 Intune 管理设备,实现条件访问
    Jetbrains学生邮箱教育认证,操作避坑指南!!!!!!
    React 多环境运行打包配置(版本区分)
    2022年Java面试题整理归纳(持续更新)
    徕客科技分享:低代码助力徕客数字化业务落地
  • 原文地址:https://blog.csdn.net/m0_70402487/article/details/133934847
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号