底层实现红黑树_map,set的底层实现:红黑树[多图,手机慎入]

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

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

我们时候用到了红黑树?

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

为什么需要红黑树?

map,set底层都提供了排序功能,且查找速度快。红黑树实际上是AVL的一种变形,但是其比AVL(平衡二叉搜索树)具有更高的插入效率,当然查找效率会平衡二叉树稍微低一点点,毕竟平衡二叉树太完美了。但是这种查找效率的损失是非常值得的。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(logn)时间内做查找,插入和删除,这里的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 boolinsertRBTree(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 (elemValuedata){//elemValue小于该节点的值,转左子树

50 x=x->left;51 }else if (elemValue==x->data){//有相等的直接返回false

52 return false;53 }54 }55 rbTreeNode* z=newrbTreeNode();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源码剖析、百度。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值