zoukankan      html  css  js  c++  java
  • map,set的底层实现:红黑树[多图,手机慎入]

     

          最近天下有一种颇不太平的感觉,各地的乱刀砍人,到处是贪官服法。京东准备上市了,阿里最近也提交申请了,猎豹也逆袭了,据说猎豹移动在国际市场上表现甚是抢眼。只有屌丝还在写着代码。花开花又谢,花谢花又开,为什么这么多人没有安全感呢?是转型社会给大家带来了浮躁,还是什么?不得而知!

        另外,就上一篇文章的问题,还请大家各抒己见!一道面试题:C++相比C#或者java的优势到底在哪里

         OK,下面进入今天的主题。红黑树。

    我们时候用到了红黑树?

         C++STL中map,set的底层实现全是用的红黑树,java,C#等语言同样如此。

    为什么需要红黑树?

          map,set底层都提供了排序功能,且查找速度快。红黑树实际上是AVL的一种变形,但是其比AVL(平衡二叉搜索树)具有更高的插入效率,当然查找效率会平衡二叉树稍微低一点点,毕竟平衡二叉树太完美了。但是这种查找效率的损失是非常值得的。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。

    何为红黑树?

          这里二叉平衡树的概念我就不提了。红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。

    性质1 节点是红色或黑色。
    性质2 根节点是黑色。
    性质3 每个叶节点(NIL节点,空节点)是黑色的。
    性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
    性质5 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
    这些约束的好处是:保持了树的相对平衡,同时又比AVL的插入删除操作的复杂性要低许多。

    操作:    

         我们知道平衡二叉树要保持他的平衡性,旋转是一项必不可少的工作。同样,红黑树是一颗准平衡二叉树,旋转也是一项重要工作。旋转有向左旋转,向右旋转,左右旋转,右左旋转。其实左右和右左旋转就是左、右旋转的二次使用,我们这里只谈论向左旋转、向右旋转。

         树的旋转:

      

    左右旋转的就是上图所示了,代码如下:

     1 void leftRoate(rbTreeNode* x){//左旋转
     2     rbTreeNode* y=x->right;
     3     y->parent=x->parent;
     4     if (x->parent==NULL)
     5         root=y;
     6     x->right=y->left;
     7     if (y->left!=NULL)
     8         y->left->parent=x;
     9     if (x->parent!=NULL&&x->parent->left==x){
    10         x->parent->left=y;
    11     }else if (x->parent!=NULL&&x->parent->right==x){
    12         x->parent->right=y;
    13     }
    14     y->left=x;
    15     x->parent=y;
    16 }
    17 void rightRoate(rbTreeNode* x){//右旋转
    18     rbTreeNode* y=x->left;
    19     x->left=y->right;
    20     y->parent=x->parent;
    21     if (x->parent==NULL)
    22         root=y;
    23     if (x->left!=NULL)
    24         x->left->parent=x;
    25     if (x->parent!=NULL&&x->parent->left==x){
    26         x->parent->left=y;
    27     }else if (x->parent!=NULL&&x->parent->right==x){
    28         x->parent->right=y;
    29     }
    30     y->right=x;
    31     x->parent=y;
    32 }

         红黑树的插入:

         一直搜查到叶子节点X,X的父节点会出现以下几种情况:

        1、父节点是空,或者父节点的颜色是黑色。直接插入。

        2、父节点是红色:

                   1)父节点是爷爷结点的左结点

                       a,叔叔结点存在,且是红色

                       b,叔叔结点不存在,或者是黑色

                  2)父节点是爷爷结点的右孩子

                      c,叔叔结点存在且也为红色

                      d,叔叔结点不存在,或者为黑色。

     

        第二种情况:

     红黑树的插入操作就是上图所示:代码如下,

     1 void keepRBTreeBlance(rbTreeNode* x,rbTreeNode* y){
     2     x->color=red;
     3     while(x!=NULL&&x->parent!=NULL&&x->parent->color==red){//父节点是红色
     4         if (x->parent==x->parent->parent->left){//父节点是爷爷结点的左节点
     5             rbTreeNode* z=x->parent->parent->right;//叔叔结点
     6             if(z&&x->parent->color==red){//叔叔结点存在,且也为红色。父和叔都置黑,爷爷置红。
     7                 x->parent->color=black;//父置黑
     8                 z->color=black;//shushu置黑
     9                 x->parent->parent->color=red;//爷爷置红
    10                 x=x->parent->parent;
    11             }else{//叔叔结点时黑色或者叔叔结点不存在的情况。
    12                 if (x==x->parent->right){//////........................问题
    13                     //rbTreeNode* temp=x;
    14                     x=x->parent;
    15                     leftRoate(x);
    16                 }
    17                 x->parent->color=black;
    18                 x->parent->parent->color=red;
    19                 rightRoate(x->parent->parent);
    20             }
    21         }else if (x->parent==x->parent->parent->right){//父节点是爷爷结点的右节点
    22             rbTreeNode* z=x->parent->parent->left;//叔叔结点
    23             if (z&&z->color==red){//都是红色
    24                 x->parent->color=black;//父置黑
    25                 z->color=black;//shushu置黑
    26                 x->parent->parent->color=red;//爷爷置红
    27                 x=x->parent->parent;
    28             }else{
    29                 if (x==x->parent->left){//如果是左孩子,需要一次右转身跳投
    30                     x=x->parent;
    31                     rightRoate(x);
    32                 }
    33                 x->parent->color=black;//同时改变颜色。
    34                 x->parent->parent->color=red;
    35                 leftRoate(x->parent->parent);
    36             }
    37         }
    38     }
    39     root->color=black;
    40 }
    41 
    42 bool insertRBTree(elemType elemValue){
    43     rbTreeNode* y=header;
    44     rbTreeNode* x=root;
    45     while(x!=NULL){
    46         y=x;
    47         if (elemValue>x->data){//elemValue大于该节点的值,转右子树
    48             x=x->right;
    49         }else if (elemValue<x->data){//elemValue小于该节点的值,转左子树
    50             x=x->left;
    51         }else if (elemValue==x->data){//有相等的直接返回false
    52             return false;
    53         }
    54     }
    55     rbTreeNode* z=new rbTreeNode();
    56     z->data=elemValue;
    57     if (y==header){//空直接插入
    58         z->color=black;
    59         root=z;
    60         return true;
    61     }else{
    62         if (y->data>elemValue)
    63             y->left=z;
    64         else
    65             y->right=z;
    66     }
    67     z->parent=y;
    68     keepRBTreeBlance(z,y);
    69     return true;
    70 }

         红黑树的删除操作类似于B-树的删除,需要注意保持它的红黑平衡性。红黑的搜索那就和B-树的查找一模一样了,其实任何排序树的操作都是一样的。比如下面将要讲到的B+树。

        B树系列还有一篇是B+树,敬请期待。

        参考文献:STL源码剖析、百度。

        版权所有,欢迎转载,但是转载请注明出处:潇一

  • 相关阅读:
    【安全运维】在Windows平台利用sysmon进行安全分析
    【渗透测试】利用分块传输绕安全狗
    【渗透测试】如何获取目标网站真实IP
    【渗透测试】渗透测试常用在线工具
    【读书笔记】《互联网企业安全建设高级指南》6-17
    【安全运维】linux安全加固项目
    【安全运维】初识osquery
    【渗透测试】使用隧道模式访问目标数据库
    【企业安全】使用文件hash进行威胁分析
    【编程开发】python学习-判断是否是私网IP地址
  • 原文地址:https://www.cnblogs.com/xiaoyi115/p/3719192.html
Copyright © 2011-2022 走看看