通过上篇博客知道,二叉搜索树的局限在于不能完成自平衡,从而导致不能一直保持高性能。

   AVL树则定义了平衡因子绝对值不能大于1,使二叉搜索树达到了严格的高度平衡

   

   还有一种能自我调整的二叉搜索树,

   红黑树 : 通过标记节点的颜色(红/黑),使其拥有自平衡的二叉搜索树。

    

   红黑树性质 :

      • 性质1:每个节点要么是黑色,要么是红色。
      • 性质2:根节点是黑色。
      • 性质3:每个叶子节点(NIL)是黑色。
      • 性质4:每个红色结点的两个子结点一定都是黑色。
      • 性质5:所有路径都包含数量相同的黑结点

    这些约束强制了红黑树的关键性质: 红黑树没有一条路径会比其他路径的两倍长(同一起点)。所以这个树大致上是平衡的,不会像二叉搜索树出现极端情况。

    是性质4和5导致路径上确保了这个结果。最短的路径只有黑色节点,最长路径有交替的红色和黑色节点。因为所有的路径黑色节点数量相同,所以没有路径能多于任何其他路径的两倍长。

    

    红黑树节点定义:

enum Colour
{
RED,
BLACK,
}; template<class K,class V>
class RBtreeNode
{
RBtree<K,V>* _left;
RBtree<K,V>* _right;
RBtree<K,V>* _parent; pair<K,V> _kv;
Colour _col;
}; template<class K,class V>
class RBTree
{
typedef RBtreeNode<K,V> Node;
public:
bool Insert(const pair<K,V>& kv);
private:
Node* _root = nullptr;
}

   红黑树的插入:

      在结点插入后,需要遵循红黑树性质

      新结点默认是红色,所以需要判断红黑树的性质是否遭到破坏(插入节点与父亲节点都为红色,违反性质4)

      有以下三种情况:

      1.u为红   --->   p,u-->黑  g-->红    cur=g,向上调整

      

      2.cur和p在g的同一边,u不存在/为黑 --- cur,p在g左---  左左 : g右旋, g--->红, p-->黑   

                                                                                     cur,p在g右 --- 右右 : g左旋, g--->红,p--->黑

                             

    3.cur和p不在g的同一边,u不存在/为黑  --- p在g左,cur在p右--- 左右: p左旋

                                  p在g右,cur在p左--- 右左: p右旋

                               --->变成情况2处理

          

      插入结点代码:

bool Insert(const pair<K,V> _kv)
{
//插入结点
if(root == nullptr)
{
root=new Node(kv);
root->_col = BLACK;
return true;
}
Node* parent = nullptr;
Node* cur = root;
while(cur)
{
if(cur->kv.first < kv.first) else if(cur->kv.first > kv.first) else
return false;
}
cur = new Node(kv);
cur->_col = RED; //父节点连接插入的结点
if(parent->kv.first < kv.first)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
...
} //颜色调整
//红黑树遭到破坏: 红红相连
while(parent && parent->_col==RED)
{
Node* g = parent->_parent;
//叔叔在右边
if(parent == g->_left)
{
Node* u = g->_right;
//叔叔为红,变色调整
if(u && u->_col==RED)
{
parent->_col = BLACK;
u->_col = BLACK;
g->_col = RED; cur = g;
parent = cur->_parent;
}
//叔叔非红,旋转调整
else
{
//父亲和孩子没有对齐,左旋变齐
if(cur == parent->_right)
{
RotateL(parent);
swap(parent,cur);
}
//对齐,右旋并调色,完成调整
RotateR(g);
parent->_col = BLACK;
g->_col = RED; break;
}//end of 叔非红处理
}
//叔叔在左边
else
{
//....
} }//end of 红红相连 //按规定将其根置为黑 : 防止根为cur情况
_root->_col = BLACK;
return true;
}

    

     STL标准的红黑树是这样的, 根的父亲不是nullptr而是header,使红黑树构成了闭环.

    header->_left = rbtree.begin(), header->_right = rbtree.end(), header->_parent = root.

    利用性质验证红黑树代码:

//判断是否为红黑树
bool isRBTree()
{
pNode root = _header->_parent; if(root == nullptr) return true;
//1.根是否黑色
if(root->_color == RED)
{
cout<<"根节点必须是黑色!"<<endl;
return false;
}
//2.每条路径黑色个数相同?
//可以任意遍历一条(最右)路径获取黑色节点数量
pNode cur = root;
int black_count = 0;
while(cur)
{
if(cur->_color == BLACK)
++black_count;
cur = cur->_right;
}
int k = 0;
return _isRBTree(root,k,black_count); } //看每一条路径是否和基准值相同
bool _isRBTree(pNode root,int curCount,int count)
{
//终止条件: 一条路径走完
if(root==nullptr){
if(curCount != count)
{
cout<<"每个路径黑色节点个数不同"<<endl;
return false;
}
return true;
} if(root->_color == BLACK)
++curCount; //3.没有红色连续的?
pNode parent = root->_parent;
if(parent && parent->_color == RED && root->_color == RED)
{
cout<<"有红色连续的节点"<<endl;
return fasle;
} return _isRBTree(root->_left,curCount,count)
&& _isRBTree(root->_right,curCount,count);
}

      

  

    

DS 红黑树详解的更多相关文章

  1. nginx 红黑树详解

    1 介绍 这部分终于整理完了,太耗时间了,留下来备忘吧! 之前看STL源码时,只是研究了红黑树的插入部分.在stl源码剖析的书中,也没有涉及到删除操作的分析,这次对删除操作也进行了详细的研究, 并且还 ...

  2. DS AVL树详解

    先说说二叉搜索树: 是有序的二叉树,根值>左节点值,右节点值>根值. 如果要查找某个值,二叉搜索树和二分查找一样,每进行一次值比较,就会减少一半的遍历区间. 但是,如果树插入的值一直递增/ ...

  3. 【Java入门提高篇】Day30 Java容器类详解(十二)TreeMap详解

    今天来看看Map家族的另一名大将——TreeMap.前面已经介绍过Map家族的两名大将,分别是HashMap,LinkedHashMap.HashMap可以高效查找和存储元素,LinkedHashMa ...

  4. <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  5. Java集合详解6:TreeMap和红黑树

    Java集合详解6:TreeMap和红黑树 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储 ...

  6. 红黑树原理详解及golang实现

    目录 红黑树原理详解及golang实现 二叉查找树 性质 红黑树 性质 operation 红黑树的插入 golang实现 类型定义 leftRotate RightRotate Item Inter ...

  7. Java集合详解6:这次,从头到尾带你解读Java中的红黑树

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  8. stl map底层之红黑树插入步骤详解与代码实现

    转载注明出处:http://blog.csdn.net/mxway/article/details/29216199 本篇文章并没有详细的讲解红黑树各方面的知识,只是以图形的方式对红黑树插入节点需要进 ...

  9. Tree--RedBlackTree详解(2 - 3 - 4Tree)(红黑树)

    #topics h2 { background: #2B6695; color: #FFFFFF; font-family: "微软雅黑", "宋体", &qu ...

随机推荐

  1. 洛谷 P1462 通往奥格瑞玛的道路 题解

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  2. shell 命令行参数(getopt和getopts)

    getopt 命令 使用getopt命令,可以解析任何命令行选项和参数,但是用法比较复杂.getopt的命令用法如下: $ getopt --help 用法: getopt optstring par ...

  3. [算法模板]倍增求LCA

    倍增LCA \(fa[a][i]\)代表a的第\(2^{i}\)个祖先. 主体思路是枚举二进制位,让两个查询节点跳到同一高度然后再向上跳相同高度找LCA. int fa[N][21], dep[N]; ...

  4. python 操作es

    Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上. Lucene 可能是目前存在的,不论开源还是私有的,拥有最先进,高性能和全功能搜索 ...

  5. 服务器负载过高问题分析-不是cpu高负载也不是IO负载如何处理(阿里 几乎是必考题)

    关于top命令 经常问load average 参考:load average 定义(网易面试) jvm dump的使用 参考:Jvm dump jstack jmap jstat 介绍与使用(内存与 ...

  6. 4款五星级的3D模型资源包

    HI,晚上好各位,今晚我们将为大家介绍4款五星级的3D模型资源包. ANIMALS FULL PACK ANIMALS FULL PACK包含了由PROTOFACTOR制作的24款高质量的动物模型,包 ...

  7. tornado多进程模式不同进程写不同日志

    #coding: utf- ''' Author: Time: Target: ''' import logging import logging.handlers import os import ...

  8. Java基础 awt Graphics2D 生成矩形图片并向其中画一条直线

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  9. win 程序开机自启动设置

    若程序设置了开机自启动,但是仍没有效果,可能是被什么拦截了,或者什么原因.导致开机并没有自启动,那么如何解决呢? 解决方法:将软件的快捷方式 或 单个软件 直接拷贝到 如下目录,即可强制实现开机自启动 ...

  10. JS的base64编码解码

    Unicode问题解法 有个小坑是它只支持ASCII. 如果你调用btoa("中文")会报错: Uncaught DOMException: Failed to execute ' ...