红黑树详解

什么是红黑树?

​ 红黑树,是一种二叉搜索树的特化,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。
​ 红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(logN),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

红黑树的性质

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

为什么满足以上性质的二叉树就可以满足最短路径长度小于等于最长路径长度的两倍呢?

在极端情况下,根据性质2和3,假设一条路径全为黑色节点,另一条路径黑红节点交错,此时是满足最短路径长度小于等于最长路径长度的两倍的,其他非极端条件下也同样满足。

红黑树的实现

0.红黑树的节点

由左右父三个节点的指针、保存的数据val、节点的颜色组成

class RBTNode
{
public:RBTNode<T>* _left;RBTNode<T>* _right;RBTNode<T>* _parent;T val;color _col;RBTNode(const T& v):_left(nullptr),_right(nullptr),_parent(nullptr),val(v){}
};

1.红黑树的插入操作

我们假设原红黑树是正确的,假设插入节点是黑色节点,它会破坏性质3,这种破坏想要重新调整为红黑树是十分困难的,原因是它要控制每条路径黑节点的数量,因此对每条路径都要调整,而假如插入节点是红色节点,那么只需要对有限个节点进行变色+旋转就可以把树重新调整为红黑树。

因此这里我们假定插入节点是红色节点。

这里把红黑树的插入分为三种情况:

定义:当前节点,父节点(当前节点的父亲),舅节点(父节点的兄弟节点),祖父节点(父节点的父节点)

1.插入节点的父节点是黑节点:此时没有违反红黑树的任何一条性质,直接按照AVL树的插入性质进行插入就可以。

2.插入节点的父节点是红节点,舅节点不存在或存在但为黑节点:此时违反了红黑树的性质2

  • 当父节点在祖父节点左侧时,假如插入节点在祖父节点的左侧,对祖父节点进行右单旋,对父节点和祖父节点进行变色处理。当插入节点在祖父节点的右侧,对父节点进行左单旋,对祖父节点进行右单旋,再对当前节点和祖父节点进行变色处理,此时就完成了红黑树的插入。
  • 当父节点在祖父节点右侧时,假如插入节点在祖父节点的右侧,对祖父节点进行左单旋,对父节点和祖父节点进行变色处理。当插入节点在祖父节点的左侧,对父节点进行右单旋,对祖父节点进行左单旋,再对当前节点和祖父节点进行变色处理,此时就完成了红黑树的插入。

3.插入节点的父节点是红色,舅节点是红节点:此时违反了红黑树的性质2

  • 此时只需要对父节点和舅节点和祖父节点进行变色处理,此时不知道祖父节点是不是根节点,因此要继续向上处理!

4.插入节点就是根节点:直接插入黑节点

最后!记得把根节点设置为黑节点,防止循环向上变色时把根节点处理为红色

代码实现:

pair<iterator, bool> insert(const T x){KeyOfT kot;if (_root == nullptr){_root = new Node(x);_root->_col = BLACK;return make_pair(iterator(_root), true);}Node* cur = _root;Node* parent = nullptr;while (cur){if (kot(x)>kot(cur->val)){parent = cur;cur = cur->_right;}else if (kot(x) < kot(cur->val)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(x);cur->_col = RED;cur->_parent = parent;Node* newnode = cur;if (kot(x)>kot(parent->val)){parent->_right = cur;}else{parent->_left = cur;}while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle&& uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(parent);parent->_col = BLACK;grandfather->_col = RED;}else{RotateL(parent);RotateR(grandfather);cur->_col=BLACK;grandfather->_col = RED;}break;}}if (parent == grandfather->_right){Node* uncle = grandfather->_left;if (uncle&& uncle->_col == RED){parent->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}else{RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode), true);}

左旋代码:

void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}}

右旋代码:

void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}}

2.验证红黑树是否平衡函数

对红黑树是否平衡的检查主要检查的是性质2和性质3,通过验证是否有两个连续的红节点可以验证性质2,通过递归获取每条路径的黑节点个数和提前计算好的基准值进行对比就可以验证性质3

代码实现:

bool isbalance(){if (_root == nullptr){return true;}if (_root->_col != BLACK){return false;}Node* cur = _root;int count = 0;while (cur){if (cur->_col == BLACK){count++;}cur = cur->_left;}int num = 0;return _isbalance(_root, count, num);}
bool _isbalance(Node* _root,int count,int num){if (_root == nullptr){if (num == count){return true;}return false;}if (_root->_col == BLACK){num++;}if (_root->_col == RED && _root->_parent->_col == RED){return false;}return _isbalance(_root->_left, count, num) && _isbalance(_root->_right, count, num);}

3.红黑树的迭代器

红黑树的迭代器设计中有困难主要是++和–操作符的重载,我们知道红黑树按照中序遍历得到的数据是有序的,我们要模拟中序遍历这个过程实现++和–

begin()函数返回红黑树中序遍历的第一个节点构建的迭代器,也就是红黑树的最左节点,利用循环可以找到

end()函数红黑树中序遍历的最后一个节点构建的迭代器,也就是空节点nullptr

1.前置++操作符的重载:

  • 如果右子树存在,找到右子树的最左节点,它就是下一个节点
  • 如果右子树不存在,向上循环找到第一个子节点不是父节点右节点的节点,它就是下一个节点
Self& operator++(){if (_node->_right){Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}

2.前置–操作符的重载:

  • 如果左子树存在,找到左子树的最右节点,它就是下一个节点

  • 如果左子树不存在,向上循环找到第一个子节点不是父节点左节点的节点,它就是下一个节点

    Self& operator--(){if (_node->_left){Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
    

红黑树(Red Black Tree)超详细解析相关推荐

  1. 红黑树Red/Black Tree

    红黑树Red/Black Tree 建立二进制搜索树,我们得到红/黑树,旨在解决BST可能变得不平衡的问题.(BST[二叉搜索树],是对于任意的node x,如果node y是node x的左边的节点 ...

  2. 数据结构--红黑树 Red Black Tree

    文章目录 1.概念 2.操作 2.1 左旋.右旋(围绕某个节点的左/右旋) 2.2 插入 2.3 删除 3. 代码 1.概念 二叉树在频繁动态增删后,可能退化成链表,时间复杂度由 O(lgn) 变成 ...

  3. Java集合系列---红黑树(基于HashMap 超详细!!!)

    1 平衡因子: 左右子树 高度之差 LL型 右旋 LR型 -->LL 右旋 RR -->左旋 RL -->RR 左旋 左旋:逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代, ...

  4. 红黑树(Red Black Tree)详解

    红黑树 红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组. 红黑树是在1972年由Rudolf Bayer发明的,当时被称为 ...

  5. 红黑树(Red–black tree)

    一.红黑树的概念: 在计算机科学中,红黑树是一种自平衡二叉搜索树.每个节点存储一个表示"颜色"("红"或"黑")的额外位,用于确保树在插入和 ...

  6. 红黑树(Red-Black Tree)解析

    这一篇我们来聊聊红黑树,写这篇文章的起因是在阅读HashMap源码时,发现JDK1.8对于HashMap的实现引入了红黑树来处理哈希冲突以提高性能(戳这里,有详述),而红黑树的数据结构和操作都是较为复 ...

  7. 数据结构——红黑树(red-black tree)

    RB-tree(红黑树)是一种平衡二叉搜索树,它每个节点上增加了一个存储位来表示节点的颜色,可以是 Red 或 Black,故得名.通过对任何一条从根到叶子的简单路径上各个节点的颜色进行约束,红黑树能 ...

  8. Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析

    前言: 本文也做了一次标题党,哈哈,其实写的还是很水,各位原谅我O(∩_∩)O. 介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看 ...

  9. 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析

    2019/07/13 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析 发表日期:2019/07/13 单片机开发板:巫妖王2.0, 使用同款开发板可直接上板测试 文档说明: 实现功能 : 一 ...

最新文章

  1. python中str和int区别_Python中的string方法和str方法有什么区别?
  2. 《吃土》读书笔记-笔记初稿
  3. 关于JS的传递方式的小理解
  4. 手机滤镜怎么移植到ps上_一分钟教你电脑端Lr、Ps滤镜预设/手机端Lr预设如何导入【图文教程】...
  5. 解读设计模式----策略模式(Strategy Pattern)
  6. cisco hsrp备份小实验
  7. 不重启mysqld更改root密码
  8. 【李宏毅机器学习】03:误差Error
  9. 什么才是真正的架构设计?
  10. codeblock的多个文件编译怎么_给一个iOS app配置多个环境变量
  11. Android app 页面加载统计工具
  12. An'droid TextView
  13. 客运综合管理系统项目解析-安全检查(模块)-车辆安检情况查询
  14. Linux系统安装Mediawiki
  15. 《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”
  16. 【官档整理】原生 MSDN 纯净版 WIN PE 创建 下载方法
  17. RocketMQ 优雅停机技巧
  18. 【观察】走进乌兰察布,揭秘UCloud优刻得首个自建自营云计算中心
  19. 高通QCS603/QCS605物联网系统芯片介绍,QCS603/QCS605处理器参数比较
  20. Cause: com.microsoft.sqlserver.jdbc.SQLServerException: 关键字 'user' 附近有语法错误

热门文章

  1. 清华北大计算机专业一般录取分数,考研考上清华北大的计算机专业需要有多努力?计算机考研院校排名!...
  2. html5中time属性怎么用,html5中返回TimeRanges对象的属性buffered
  3. 大庆 让胡路 长青 车检中心 检车流程
  4. Computing Curricula 2005--概述
  5. 软件工程 1:软件危机
  6. 最强的思考、写作的工具:超简单的卡片盒卢曼笔记法
  7. 基于javaweb的医院管理系统
  8. 基于ESP8266的环境监测系统
  9. 还是大家发生东莞十多个
  10. layer alert时 点击其他地方会关闭