概述:R-B Tree,又称为“红黑树”。本文参考了《算法导论》中红黑树相关知识,加之自己的解,然后以图文的形式对红黑树进行说明。本文的主要内容包括:红黑树的特性,红黑树的时间复杂度和它的证明,红黑树的左旋、右旋、插入等操作。

1 R-B Tree简介

R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

2 R-B Tree时间复杂度

红黑树的时间复杂度为: O(lgn)
定理:一棵含有n个节点的红黑树的高度至多为2log(n+1).

3 R-B Tree基本操作

R-B Tree的基本操作是添加删除。 添加和删除操作,都会用到两个基本的方法:左旋右旋,统称为旋转。旋转是为了保持红黑树的特性而提供的辅助方法,因为当我们进行添加、删除节点时,可能改变红黑树的特性(例如,删除一个黑色节点之后,就不满足“从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点”这个特性);这里,我们就需要旋转方法的辅助来让树保持红黑树的特性。

3.4 添加操作

向一颗含有n个节点的红黑树中插入一个节点,可以在时间O(lgn)内完成。

将节点z插入红黑树T内。需要执行的操作依次时:首先,将T当作一颗二叉树,将z插入;然后,将z着色为红色;最后,通过RB-INSERT-FIXUP来对节点重新着色并旋转,以此来保证删除节点后的树仍然是一颗红黑树。

(01) 将T当作一颗二叉树,将z插入。
    因为红黑树本身就是一颗二叉树,所以,我们可以根据二叉树的性质将z插入。

(02) 将z着色为红色。
  在介绍为什么将则着色为红色之前,我们重新温习一下红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

将插入的节点着色为红色,不会违背“特性(5)”;而若将插入的节点着色为黑色,会违背该特性。

(03) 通过RB-INSERT-FIXUP来对节点重新着色并旋转。
  因为(02)中插入一个红色节点之后,虽然没有违背“特性(5)”,但是却可能违背了其它特性(例如,若被插入节点的父节点也是红色;插入后,则违背了“特性(4)”)。我们需要通过RB-INSERT-FIXUP进行节点颜色的调整以及旋转等工作,让树仍然是一颗红黑树。

总的来说:当节点z被着色为红色节点,并插入二叉树时,有三种情况。

情况一:被插入的节点是根节点。
    直接把此节点涂为黑色。

情况二:被插入的节点的父节点是黑色。
    什么也不需要做。节点被插入后,仍然是红黑树。

情况三:被插入的节点的父节点是红色。
    那么,该情况与红黑树的“特性(5)”相冲突。情况三包含了“Case 1”、“Case 2” 和“Case 3”三种情况,情况三的目的是恢复红黑树的特性,它的处理思想是:将红色的节点移到根节点;然后,将根节点设为黑色。下面介绍情况三的三种情况。

Case 1:叔叔是红色

Case 1 现象说明:当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。
Case 1 处理策略:
    (01) 将“父节点”设为黑色。
    (02) 将“叔叔节点”设为黑色。
    (03) 将“祖父节点”设为“红色”。
    (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。

Case 2:叔叔是黑色,且当前节点是右孩子

Case 2 现象说明:当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子
Case 2 处理策略:
    (01) 将“父节点”作为“新的当前节点”。
    (02) 以“新的当前节点”为支点进行左旋。

Case 3:叔叔是黑色,当前节点是做孩子

Case 3:叔叔是黑色,且当前节点是左孩子
Case 3 现象说明:当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子
Case 3 处理策略:
    (01) 将“父节点”设为“黑色”。
    (02) 将“祖父节点”设为“红色”。
    (03) 以“祖父节点”为支点进行右旋。

 #include<iostream>
using namespace std;
enum Color
{BLACK,RED
};
template<class K,class V>
struct RBTreeNode
{RBTreeNode(const K& key,const V&value,const Color col = RED):_left(NULL),_right(NULL),_parent(NULL),_col(col),_key(key),_value(value){}RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _col;K _key;V _value;
};
template<class K,class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:RBTree():_root(NULL){}bool Insert(const K& key, const V& value){if (_root == NULL){_root = new Node(key, value, BLACK);return true;}Node* parent = NULL;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{break;}}cur = new Node(key, value, RED);if (parent->_key <key){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//调色while (cur != _root && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED){uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}//当叔叔节点为黑色,且S为F的右孩子,处理步骤;1 以父节点进行左旋 2将父节点变黑祖父节点变红,3然后进行右旋else{if (cur == parent->_right){RotateL(parent);swap(cur, parent);}RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}}else  //往右子树插{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){uncle->_col = parent->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){RotateR(parent);swap(cur, parent);}RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}}}_root->_col = BLACK;return true;}void InOrder(){_InOrder(_root);cout << endl;}
protected:void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if(subRL){subRL->_parent = parent;}subR->_left = parent;subR->_parent = parent->_parent;parent = subR;if (parent->_parent == NULL){_root = parent;}else{if (parent->_key < parent->_parent->_key){parent->_parent->_left = parent;}else{parent->_parent->_right = parent;}}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if(subLR){subLR->_parent = parent;}subL->_right = parent;subL->_parent = parent->_parent;parent->_parent = subL;parent = subL;if (parent->_parent == NULL){_root = parent;}else{if (parent->_key < parent->_parent->_key){parent->_parent->_left = parent;}else{parent->_parent->_right = parent;}}}void _InOrder(Node*& root){if (root == NULL){return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}protected:Node* _root;
};
void TestRBTree()
{RBTree<int, int> t1;int a[10] = { 5, 2, 9, 6, 7, 3, 40, 1, 8 };for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i){t1.Insert(a[i], i);t1.InOrder();}cout << "IsBalanceTree:" << t1.IsBalanceTree() << endl;
}
int main()
{TestRBTree();system("pause");return 0;
}

4 运行结果

 5 红黑树的应用

红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(lgn),效率非常之高。
例如,Java中的TreeSet和TreeMap,C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。

这里大致介绍下,红黑树和AVL树的差异。AVL树也是特殊的二叉树,它的特性是“任何节点的左右子树的高度之差不超过1”。基本上,用到红黑树的地方都可以用AVL树(自平衡二叉查找树)去替换。但是一般情况下,在执行添加、删除节点时,AVL树比红黑树执行的操作更多一些,效率更低一些;而且红黑树也是相对平衡的二叉树(从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点)。因此,红黑树的效率会高更一点。

转载于:https://blog.51cto.com/10798301/1819434

红黑树 RBTree相关推荐

  1. 红黑树(RB-Tree)比AVL强在哪?

    前言 以前本科同学在找工作的时候,就被面试官问到过关于红黑树的问题.因为当时我的知识面不广,所以也不知道红黑树是个什么东西,也没放在心上.在看过了STL源码后才知道原来有很多底层实现都用的红黑树.简单 ...

  2. C++ 泛型编程 实现红黑树RBTree

    代码如下: #include <iostream> #include <ctime> using namespace std;enum COLOR {BLACK,RED };t ...

  3. 红黑树RBTree原理(超易懂)

    红黑树脑图 目录 文章目录 红黑树的定义 四点特征 为什么红黑树是近似平衡的 (1)首先,我们来看,如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢? (2)现在把红色节点加 ...

  4. 《恋上数据结构第1季》红黑树(未完)

    红黑树(Red Black Tree) 红黑树介绍 红黑树 与 4阶B树 红黑树 与 2-3-4树 等价转换 红黑树基础代码 完整的红黑树系列代码(恐怖如斯) 二叉树 BinaryTree.java ...

  5. 关于hash,hashCode, hashMap,红黑树

    小刘老师讲HashMap源码 小刘老师讲红黑树 hash,hashCode,hashMap 1.前提知识 数组: 列表: 散列表 什么是hash? hash也称散列,哈希,基本原理就是把任意长度的输入 ...

  6. HashMap底层红黑树实现(自己实现一个简单的红黑树)

    文章整理于小刘老师讲源码 视频学习链接:小刘老师讲解红黑树 JDK集合源码之HashMap解析(上) JDK集合源码之HashMap解析(下) 1.树结构入门 1.1 什么是树? 树(tree)是一种 ...

  7. 红黑树效率为甚恶魔是log_Linux内核-深入理解红黑树与B+树应用场景

    一.红黑树和B树应用场景有何不同? 2者都是有序数据结构,可用作数据容器.红黑树多用在内部排序,即全放在内存中的,微软STL的map和set的内部实现就是红黑树.B树多用在内存里放不下,大部分数据存储 ...

  8. 红黑树分析与JDK8中HashMap源码解析

    红黑树分析与JDK8中HashMap源码解析 BST O(1), O(n), O(logn), O(nlogn) 的区别 红黑树-RBTree 插入数据 HashMap中红黑树的插入操作 HashMa ...

  9. C++ RBTree(红黑树) 算法(附完整源码)

    C++ RBTree红黑树的算法 RBTree(红黑树) 的完整源码(定义,实现,main函数测试) RBTree(红黑树) 的完整源码(定义,实现,main函数测试) #include<ios ...

  10. 数据结构 红黑树(RBTree)的原理与实现

    学习红黑树之前你应该保证你学过AVL树,也就是平衡二叉搜索树 数据结构 AVL树 AVL树是一棵高度平衡的二叉搜索树,其要求每个结点的高度差不能大于1,这样子就保证了其查询的时间复杂度为log2(N) ...

最新文章

  1. jquery选中checkbox
  2. python paramiko并发_使用Python paramiko模块利用多线程实现ssh并发执行操作
  3. 经典MySQL语句大全和常用SQL语句命令的作用。
  4. SoJpt Boot 2.2-3.8 发布,Spring Boot 使用 Jfinal 特性极速开发
  5. virtualbox 中ubantu虚拟机范文win7文件夹
  6. java 循环效率_Java For循环效率测试
  7. Flutter布局常用widgets
  8. DialogBoxIndirectParam
  9. 可以解压日文的软件_日文换成中文字体就不好看?我偏不信这个邪!
  10. ML算法整理(一)线性回归与梯度下降 python实现
  11. java生命游戏_大神们 急求一个生命游戏的java代码 谢谢各路大神!
  12. hping 详解_hping3 使用详解
  13. ArcGIS:使用镶嵌功能将地理空间数据云下载的多幅DEM合并为一幅
  14. spark大数据的学习
  15. [转]下载安装IDM Integration Module和其使用方法
  16. 【AD】如何画双层PCB板,双层PCB板布线规则
  17. 智能锁忘记密码怎么办
  18. 红旗linux8.0安装教程,RedHat Linux 红旗9.0安装图解
  19. 个人主页HTML源码程序 搭建超级简单
  20. Jsoup爬取网络内容(包括图片文件),保存到本地和保存到数据库(一)

热门文章

  1. 演说之禅:演说中的 1-7-7法则
  2. PyTorch:Embedding初始化及自定义
  3. Eclipse — 如何快速生成servlet类和配置文件(web里)
  4. # C语言程序设计第二次作业——顺序结构
  5. Spring常用注解用法总结
  6. 花开花落,我们都很渺小
  7. HDOJ 4223 (DP)
  8. ORACLE SQL功能优化系列(一)
  9. HCIE-Security Day20:GRE协议:实验(一)配置基于静态路由的GRE隧道
  10. Security+ 学习笔记55 隐私和合规性