目录

一.红黑树介绍与优势

二.红黑树的特性

①所有节点不是黑色就是红色

②根节点为黑色

③红色节点的左右孩子节点必须为黑色

④每一条路径均含有相同的黑色节点数

⑤叶子节点为黑色

三.红黑树实现原理

(一).插入节点颜色选择

(二).插入后,父节点是黑色

(三).插入后,父节点是红色

(四).叔叔节点为红色

①父节点、叔叔节点变黑,祖父节点变红

②以祖父节点为“新插入节点”继续向上判断

(五).叔叔节点为黑色、没有叔叔节点

①当前节点为父节点左子树,且在根节点左侧

②当前节点为父节点右子树,且在根节点右侧

③当前节点为父节点右子树,且在根节点左侧

④当前节点为父节点左子树,且在根节点右侧

四.思维导图

五.实现代码


一.红黑树介绍与优势

有兴趣的小伙伴可以先看看这篇文章:手把手教你实现AVL树、平衡二叉树

红黑树是在1972年由Rudolf Bayer发明的。

其特点是从根到叶子节点的所有路径中,最长路径不大于最短路径的2倍。

可以说红黑树是AVL树的plus版,因此,红黑树查找时间与AVL树相同,都为O(log N)。

同时,红黑树没有做到AVL树那种绝对平衡,因此其旋转次数少于AVL树。当数据量大时,其效率要优于AVL树。

正因如此,在实际应用中往往采取红黑树而非AVL树。

二.红黑树的特性

可以说,红黑树的特性正是它的精华与结构依据。因此,想要学懂红黑树,熟练掌握特性是必不可少的一环。

红黑树特性:

①所有节点不是黑色就是红色

②根节点为黑色

③红色节点的左右孩子节点必须为黑色

意思就是不能出现两个红色节点相连的情况。

④每一条路径均含有相同的黑色节点数

从根节点到叶子节点的每一条路径中,黑色节点数量均相同。

⑤叶子节点为黑色

三.红黑树实现原理

实现红黑树,我们需要时刻谨记它的特性,尤其是特性3和4。

(一).插入节点颜色选择

当插入节点时,如果是插入根节点,那么节点颜色为黑色即可,然后插入完成。

如果是孩子节点,那么先将颜色变为红色,为什么?

如果插入节点颜色是黑色,那么势必打破特性4:所有路径黑色节点数相同。

而如果插入红色,可能会打破特性3:不能有相连的红色节点。

相比于特性4,打破特性3的代价更小:插入黑色势必打破特性4,插入红色则有可能打破特性3。

(二).插入后,父节点是黑色

当插入孩子节点后,如果父节点是黑色,那么此时没有打破任何一条特性,任务完成。

(三).插入后,父节点是红色

如果父节点是红色,那么问题就出来了,此时打破了特性3:不能有相连的红色节点

此时需要分类讨论,而依据就是叔叔节点

需要考虑的重点是达成每条路径下均含有相同数目的黑色节点(特性4)且没有相连的红色节点(特性3)。

由此,分成(四)、(五)两种情况

(四).叔叔节点为红色

 将父节点与叔叔节点变为黑色,祖父节点变为红色,然后以祖父节点为“新插入节点”继续向上判断。

①父节点、叔叔节点变黑,祖父节点变红

此时,以祖父为根的树已经满足红黑树的特性要求,因此需要以祖父为出发点继续向上判断,此时祖父的颜色是否依旧符合红黑树,相当于将祖父节点作为“新插入节点”,重新判断。

②以祖父节点为“新插入节点”继续向上判断

(五).叔叔节点为黑色、没有叔叔节点

需要注意,此时节点并不是真正新插入的节点,因为新插入的节点父节点为红色,说明祖父节点为黑,如果此时叔叔节点为黑色,那么到父节点的这条路径的黑色节点数量就比到叔叔节点的黑色数量少一,说明插入前就已经不是红黑树,这是不成立的。因此,该情况只能出现在祖父节点向上判断时。

这种情况时,单纯的变色已经不能解决问题了,只能靠旋转+变色来解决。

这里不再具体讲解旋转的过程,与AVL树一致,可以参考这篇博客:手把手教你实现AVL树、平衡二叉树

同时,经过旋转+变色后,此时整颗树已经满足红黑树全部特性,即插入完成。

这时情况可以分成四类,分别对应不同的旋转策略,

前两种均为单旋转,后两种均为双旋转:

①当前节点为父节点左子树,且在根节点左侧

父节点右旋转,父节点变黑,祖父变红。

        步骤一、父节点右旋转

         步骤二、变色

②当前节点为父节点右子树,且在根节点右侧

父节点左旋转,父节点变黑,祖父节点变红

此处类比情况① ,将父节点右旋即可,不再具体演示

③当前节点为父节点右子树,且在根节点左侧

cur节点左旋转后右旋转,插入节点变黑,祖父节点变红

        步骤一、cur节点左旋转

        步骤二、cur节点右旋转

         步骤三、变色

④当前节点为父节点左子树,且在根节点右侧

cur节点右旋转后左旋转,插入节点变黑,祖父节点变红

此处类比情况③,cur节点右旋后左旋即可,不再具体演示

四.思维导图

五.实现代码

#pragma once
using namespace std;
#include<iostream>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#define BLACK false//用bool定义红黑颜色
#define RED true
template<class V>
class rb_tree_node//红黑树节点
{
public:rb_tree_node(V val):_val(val){}bool _col = RED;rb_tree_node* right = nullptr;rb_tree_node* left = nullptr;rb_tree_node* parent = nullptr;V _val;
};template<class V>//红黑树
class rb_tree
{typedef rb_tree_node<V> Node;
public:void inorder()//中序遍历{_inorder(_root);//调用函数}bool Is_RB_Tree()//判断是否为红黑树{int blackNum = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK) blackNum++;cur = cur->left;}return _is_rb_tree(_root, 0, blackNum);//调用判断函数}bool insert(V val);private:void _inorder(Node* node)//中序遍历函数{if (node == nullptr) return;_inorder(node->left);cout << node->_val << " ";_inorder(node->right);}bool _is_rb_tree(Node* node, int blackNow, int blackNum);//判断函数void Rotate_R(Node* cur);void Rotate_L(Node* cur);Node* _root = nullptr;
};template<class V>
void rb_tree<V>::Rotate_R(Node* cur)//右旋转
{Node* parent = cur->parent, *node_r = cur->right, *grandfather = parent->parent;if (node_r){node_r->parent = parent;}parent->left = node_r;cur->right = parent;cur->parent = grandfather;if (grandfather){if (grandfather->left == parent) grandfather->left = cur;else grandfather->right = cur;}else _root = cur;parent->parent = cur;
}template<class V>
void rb_tree<V>::Rotate_L(Node* cur)//左旋转
{Node* parent = cur->parent, *node_l = cur->left, *grandfather = parent->parent;if (node_l){node_l->parent = parent;}parent->right = node_l;parent->parent = cur;cur->left = parent;cur->parent = grandfather;if (grandfather){if (grandfather->left == parent) grandfather->left = cur;else grandfather->right = cur;}else _root = cur;
}template<class V>
bool rb_tree<V>::_is_rb_tree(Node* node, int blackNow, int blackNum)
{if (node == nullptr) return true;if (node->_col == BLACK) blackNow++;if (node->left == nullptr && node->right == nullptr){if (node->_col == RED && node->parent->_col == RED) return false;return blackNow == blackNum;}if (node != _root && node->_col == RED && node->parent->_col == RED) return false;return _is_rb_tree(node->left, blackNow, blackNum) &&_is_rb_tree(node->right, blackNow, blackNum);}template<class V>
bool rb_tree<V>::insert(V val)
{if (_root == nullptr)//插入为根节点{_root = new Node(val);_root->_col = BLACK;return true;}Node* parent = _root->parent, * cur = _root;while (cur){if (cur->_val == val) return false;//已存在该节点if (cur->_val > val){parent = cur;cur = cur->left;}else{parent = cur;cur = cur->right;}}//插入节点cur = new Node(val);cur->parent = parent;if (val < parent->_val){parent->left = cur;}else{parent->right = cur;}//根据颜色判断是否红黑树while (parent && parent->_col == RED)//父节点为红{Node* grandfather = parent->parent;assert(grandfather);//进入循环,说明一定有祖父节点assert(grandfather->_col == BLACK);//进入循环,说明祖父节点一定是黑色Node* uncle = nullptr;if (parent == grandfather->left) uncle = grandfather->right;else uncle = grandfather->left;if (parent == grandfather->left)//左{if (uncle && uncle->_col == RED)//变色 + 向上调整{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->parent;}else if (uncle == nullptr || uncle->_col == BLACK)//叔叔为空,或叔叔为黑{if (cur == parent->left)//cur为左子树,右单旋{Rotate_R(parent);grandfather->_col = RED;parent->_col = BLACK;}else//cur为右子树,左+右旋+变色{Rotate_L(cur);Rotate_R(cur);grandfather->_col = RED;cur->_col = BLACK;}break;}else{assert(false);}}else//右{if (uncle && uncle->_col == RED)//变色 + 向上调整{parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->parent;}else if (uncle == nullptr || uncle->_col == BLACK)//叔叔为空,或叔叔为黑{if (cur == parent->right)//cur为右子树,左单旋{Rotate_L(parent);grandfather->_col = RED;parent->_col = BLACK;}else//cur为左子树,右+左旋+变色{Rotate_R(cur);Rotate_L(cur);grandfather->_col = RED;cur->_col = BLACK;}break;}else{assert(false);}}}_root->_col = BLACK;//根节点一定为黑色return true;
}

人类精神必须置于技术之上——Albert Einstein


如有错误,敬请斧正

手把手教你实现红黑树相关推荐

  1. mysql 红黑树_微信大牛教你深入了解数据库索引

    | 作者刘国斌,腾讯微信事业群研发工程师,目前从事企业微信的后台研发工作,已经参与企业微信消息系统.群聊.客户联系等企业微信多个核心功能的迭代. 数据库查询是数据库的最主要功能之一. 我们都希望查询数 ...

  2. 【两步】教你学会画红黑树

    目录 红黑树的特性 第一步,画2-3-4树. 第二步,用这棵2-3-4树,画红黑树. 彩蛋 红黑树的特性 1.每个节点不是红色就是黑色 2.根节点是黑色 3.每个叶子节点(NIL节点,空节点)是黑色的 ...

  3. 程序员面试、算法研究、编程艺术、红黑树、机器学习5大系列集锦

    (七月在线:https://www.julyedu.com/,面试 & 算法 & 机器学习在线课程) 作者:July--结构之法算法之道blog之博主. 时间:2010年10月-201 ...

  4. 程序员面试 算法研究 编程艺术 红黑树 机器学习5大系列集锦

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 程序员面 ...

  5. 程序员面试、算法研究、编程艺术、红黑树、机器学习5大经典原创系列集锦与总结

    程序员面试.算法研究.编程艺术.红黑树.机器学习5大经典原创系列集锦与总结 (七月在线:https://www.julyedu.com/,面试 & 算法 & 机器学习在线课程) 作者: ...

  6. (转载)程序员面试、算法研究、编程艺术、红黑树、机器学习5大系列集锦

    作者:July–结构之法算法之道blog之博主. 时间:2010年10月-2018年5月,一直在不断更新中.. 出处:http://blog.csdn.net/v_JULY_v . 说明:本博客中部分 ...

  7. 神级:程序员面试、算法研究、编程艺术、红黑树、机器学习5大经典原创系列集锦与总结

    https://blog.csdn.net/v_JULY_v/article/details/6543438 https://blog.csdn.net/v_JULY_v/article/detail ...

  8. 【转自JULY大佬】程序员面试、算法研究、编程艺术、红黑树、机器学习5大系列集锦

    感谢原作者分享,转载自   https://blog.csdn.net/v_JULY_v/article/details/6543438 程序员面试.算法研究.编程艺术.红黑树.机器学习5大经典原创系 ...

  9. 程序员面试、算法研究、编程艺术、红黑树、数据挖掘5大经典原创系列集锦与总结

    点击打开链接(具体详情 点击链接) 程序员面试.算法研究.编程艺术.红黑树.数据挖掘5大经典原创系列集锦与总结 (七月在线:点击打开链接,面试 & 算法 & 机器学习在线课程) 作者: ...

最新文章

  1. android 设置按钮高度,如何在本机android中设置按钮的高度
  2. html百度蜘蛛跳转代码,php搜索引擎劫持,百度蜘蛛劫持,搜索引擎蜘蛛劫持原理及代码分享...
  3. Origin绘图之条形图上加曲线拟合图
  4. PAT乙级(1005 继续(3n+1)猜想)
  5. dbnetlib sqlserver不存在或拒绝访问_部署IIS+PHP+SQL server环境
  6. Zabbix 5.0 配置简单WEB网页监测和触发器
  7. mysql5.6.38 设置密码_Percona Server MySQL 5.6.38修改root密码(忘记root密码)
  8. MongoDB学习(黑马教程)-3-数据库MongoDB的删除文档操作
  9. cs服务器网页管理端,sXe服务器端怎么管理
  10. ArcGIS Pro 学习路径
  11. 几种css炫酷背景欣赏
  12. 怎样判断路由器的好坏和选择路由器?
  13. AndroidStudio|读取SD卡中的sqlite数据
  14. ExifTool 抽取、修改Image tag 信息
  15. 华为OD机试 - 自动曝光(C 语言解题)【独家】
  16. CrossCompiler And Auto tools
  17. 官网被报危险网站和降权的应对措施
  18. Go 语言中的字符串拼接
  19. Android UI库推荐
  20. mysql for mac 10.12_mac 10.12 版本 安装mysql - sylvia的博客

热门文章

  1. 信息安全——大整数包的设计!
  2. 【数值分析学习笔记】——1、数值分析中的误差
  3. 看见阿里的语音识别系统很好
  4. 解读蓝牙耳机出口沙特要做什么认证?
  5. 维基解密网店被封,呼吁全球抵制Coinbase
  6. 关于计算机领域的各种学习交流网站
  7. 正三角形旋转一周得到的图形是_将图中的直角三角形绕最长的边旋转一周可以得到的一个几何体,从正面看这个几何体所得到的平面图形是()A.B...
  8. 考研必备100个网站
  9. R语言Markowitz马克维茨投资组合理论分析和可视化
  10. Unity 使用NavMesh实现简易的摇杆功能