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

[QQ群:
189191838,对算法和C++感兴趣可以进来]

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

另外,就上一篇文章的问题,还请大家各抒己见!一道面试题: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源码剖析、百度。

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

时间: 2024-10-28 21:56:46

map,set的底层实现:红黑树[多图,手机慎入]的相关文章

map,hash_map, hash_table, 红黑树 的原理和使用

在刷算法题的时候总是碰到好多题,号称可以用hash table来解题.然后就蒙圈了. 1.首先,map和hash_map的区别和使用: (1)map底层用红黑树实现,hash_map底层用hash_table 实现.所以map的时间复杂度为O(logn), hash_map为O(1). (2)map和hash_map都在stl中,直接include,但是在Mac系统中要#include <ext/hash_map>和 using namespace __gnu_cxx; (3)以map为例来说

TreeMap:是基于红黑树的Map接口的实现

> TreeMap:是基于红黑树的Map接口的实现. 红黑树:平衡二叉树 取出时,可以有三种方式:前序遍历,中序遍历,后序遍历 >排序: A 自然排序  --TreeMap无参构造 TreeMap<key类型,value类型> map= new TreeMap<key类型,value类型>(); //key类应当实现Comparable接口,并重写hashCode()和equals()方法 B 比较器排序-TreeMap 比较器有参构造 TreeMap<key类型

红黑树并没有我们想象的那么难(下)

SGI STL map 实现概述 根据上一节的红黑树分析, 结合 sgi stl map 的实现, 看看红黑树的源码是如何实现的. 以下主要以代码的注释为主. sgi stl map 底层实现是 _Rb_tree类, 为了方便管理, _Rb_tree 内置了 _M_header, 用于记录红黑树中的根节点, 最小节点和最大节点. 在插入删除中都会对其进行维护. 找到一副美艳的图片: 我只会展开插入和删除的代码. _Rb_tree 有 insert_unique() 和 insert_equal(

史上最清晰的红黑树讲解(上)

http://www.cnblogs.com/CarpenterLee/p/5503882.html 本文以Java TreeMap为例,从源代码层面,结合详细的图解,剥茧抽丝地讲解红黑树(Red-Black tree)的插入,删除以及由此产生的调整过程. 总体介绍 Java TreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Compara

TreeMap红黑树

Java TreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator). TreeMap底层通过红黑树(Red-Black tree)实现,也就意味着containsKey(), get(), put(), remove()都有着log(n)的时间复杂度.其具体算法实现参照了<算法导论>. 出于性能原因,TreeMap是非同步

一种新的删除红黑树节点的算法

转载请注明出处:http://blog.csdn.net/mxway/article/details/38080315 下面维基百科上红黑树的5个性质 1.      节点是红色或黑色 2.      根是黑色 3.      所有叶子都是黑色(叶子是NIL节点) 4.      每个红色节点必须有两个黑色的子节点.(从每个叶子到根的所有路径上不能有两个连续的红色节点.) 5.      从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点. 根据上面的5个性质,我们可以得出下面的结论:

红黑树并没有我们想象的那么难(上)

红黑树并没有想象的那么难, 初学者觉得晦涩难读可能是因为情况太多. 红黑树的情况可以通过归结, 通过合并来得到更少的情况, 如此可以加深对红黑树的理解. 网络上的大部分红黑树的讲解因为没有「合并」. 红黑树的五个性质: 性质1. 节点是红色或黑色. 性质2. 根是黑色. 性质3. 所有叶子都是黑色(叶子是NIL节点). 性质4. 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) 性质5. 从任一节点到其每个叶子的所有简单路径 都包含相同数目的黑色节点. 红

红黑树C语言实现--源于算法导论

一.概念 红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是RED或BLACK.通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,红黑树确保没有一条路径会比其他路径长2倍,因而是近似于平衡的. 二.定义 一棵红黑树是满足下面红黑性质的二叉搜索树: 1.每个结点或是红色,或是黑色: 2.根节点是黑色的: 3.每个叶节点(NIL)是黑色的: 4.如果一个结点是红色的,则它的两个子结点都是黑色的: 5.对每个结点,从该结点到其所有后代叶节点的简单路径上,均包含相同

红黑树的性质

红黑树是一种自平衡的二叉查找树,除了符合二叉查找树的基本性质外,它还具有下列附加特性: 1.节点是红色或黑色. 2.根节点是黑色. 3.每个叶子节点都是黑色的空节点(NIL节点). 4 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的红色节点) 5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点. 下图中这棵树,就是一颗典型的红黑树: 调整有两种方法: 变色和旋转,二旋转又分为两种形式,左旋转和右旋转. 红黑树的应用很多,JDK中的集合类TreeMap和T