红黑树笔记——红黑树的插入操作
来源:互联网 发布:c语言求最小公倍数 编辑:程序博客网 时间:2024/04/29 01:14
红黑树的插入操作可以在O(logn)的时间内完成。开始插入节点的时候和二叉查找树一样,只需要最后将插入的节点着成红色,为了保证红黑树的性质,需要通过RB_InsertFixUp函数来调整该节点,对其重新着色并旋转。
下面先调用RB_Insert()函数将一个节点插入到红黑树中,同样先上伪代码
RB-INSERT(T, z) 1 y ← nil[T] 2 x ← root[T] 3 while x ≠ nil[T] 4 do y ← x 5 if key[z] < key[x] 6 then x ← left[x] 7 else x ← right[x] 8 p[z] ← y 9 if y = nil[T]10 then root[T] ← z11 else if key[z] < key[y]12 then left[y] ← z13 else right[y] ← z14 left[z] ← nil[T]15 right[z] ← nil[T]16 color[z] ← RED17 RB-INSERT-FIXUP(T, z)接着上C++代码并进行代码分析
bool RB_Insert(int key, int data) { RB_Node *p = root; RB_Node *insert_p = NIL; //找到插入在哪个节点之后 while(p != NIL) { insert_p = p; if(key < p->key) p = p->left; else if(key > p->key) p = p->right; else return false;//重复的数据不进行插入 } //初始化插入节点,注意插入节点初始的颜色为RED RB_Node *insert_node = new RB_Node(); insert_node->key = key; insert_node->data = data; insert_node->RB_COLOR = RED; insert_node->right = NIL; insert_node->left = NIL; //如果插入的是一颗空树,设定root就是插入节点 if(insert_p == NIL) { root = insert_node; root->parent = NIL; NIL->left = NIL->right = NIL->parent = root; } else//判断插入左节点还是右节点 { if(key < insert_p->key) insert_p->left = insert_node; else insert_p->right = insert_node; insert_node->parent = insert_p; } //修复红黑树的性质 RB_InsertFixUp(insert_node); return true; }为了保证红黑树的结构性质,需要调用RB_InsertFixUp函数来调整刚刚插入的节点
我们考虑下,如果一个红色节点(下文称用Z指向它)被插入到树中,那么有哪些红黑性质可能被破坏呢?只有性质2(根节点是黑色的,由于插入的可能是根节点)以及性质4(红色节点的子节点一定是黑色节点,其父节点是红色的),其它都不会被破坏。
如果插入的节点的父节点是黑色的,那么不需要做任何调整,这红黑树是正常的。如果父节点是红色,或插在树根的位置,那么就要进行调整以保证红黑树性质。
首先对性质4进行分析,我们知道,插入一个新的节点,这个节点肯定会被放到树的底部成为一个叶节点,那么这个红色节点就没有可能和自己的子节点同色(因为叶节点的子节点是NIL节点,都是黑色的),如果性质4被破坏的话,肯定是Z指向的节点的父节点是红色的。因此,为了使分析和解决更加容易和清晰,我们在对树进行调整以恢复红黑特性时,始终使得Z总是指向相邻红色的节点中的子节点(指针Z可能会向上升到树的中部或根部)。基于这个做法,我们可以知道,如果是性质2被破坏了的话,也就是Z指向根节点了,那么性质4肯定就符合了(因为Z的父节点是NIL,黑色的),因此对性质2的恢复变得很简单,只需要被根从红色变为黑色即可。
现在只需要处理性质4被破坏的问题,如果性质4被破坏了,也就是说,Z的父节点是红色的,那么,说明,Z一定有祖父节点,而且是黑色的(否则插入前原树就有问题,又或是调整时的方法不正确)。因此可以把问题放到以Z的祖父节点为根节点的子树内进行解决,这样可以把调整的范围最小化,而且这也是有可能的:只要不改变这子树的黑高度,那么就不会对树的其它部分产生影响。我们要做的就是在这个子树范围内把红黑性质调整回来。再看子树的根是否与其父节点同为红色,是的话,就再次用前面所说的去解决它,一直向上递归到红黑性质被恢复为止。
对性质4的恢复,根据Z的父节点是Z的祖节点的左子节点还是右子节点,分为两组对称的情况,每组有3种情况。下面我们以Z的父节点是Z祖节点的左子节点为例:
定义叔叔的含义:即祖父节点的另外一个子节点
情况1:z的叔叔y是红色的
如上图所示,在这种情况下,将父、叔节点都着为黑色,再将子树根节点着为红色,那么子树的黑高度没有发生改变,而且红黑性质得得到了调整。此时,再将Z指向子树的根节点,向上递归恢复红黑特性。
情况2:z的叔叔y节点是黑色的,而且z是父节点的左子节点
如上图,将Z的父节点与祖节点进行一次右旋,并把父节点着黑色,原来的祖节点着红色。这些子树的红黑特性得到了恢复,而且子树的黑高度没有变化。另外,由于子树根节点已经是黑色了(这个节点不会出现父子同为红色的问题了),所以不必再向上递归了,此时整个树的红黑特性都已经是正确的了。
情况3:z的叔叔y节点是黑色的,而且z是父节点的右子节点
如上图,将Z本身与其父节点进行一次左旋,让Z指向原来的父节点,就可以调整为情况2,而情况2已经得到解决。
由此红黑树插入后调整问题已经解决。
伪代码:
1 while color[p[z]] = RED 2 do if p[z] = left[p[p[z]]] 3 then y ← right[p[p[z]]] 4 if color[y] = RED 5 then color[p[z]] ← BLACK // Case 1 6 color[y] ← BLACK // Case 1 7 color[p[p[z]]] ← RED // Case 1 8 z ← p[p[z]] // Case 1 9 else if z = right[p[z]]10 then z ← p[z] // Case 211 LEFT-ROTATE(T, z) // Case 212 color[p[z]] ← BLACK // Case 313 color[p[p[z]]] ← RED // Case 314 RIGHT-ROTATE(T, p[p[z]]) // Case 315 else (same as then clause with "right" and "left" exchanged)16 color[root[T]] ← BLACK
RB_InsertFixUp C++源码:
void RB_InsertFixUp(RB_Node *node) { while(node->parent->RB_COLOR == RED) { if(node->parent == node->parent->parent->left) { RB_Node *uncle = node->parent->parent->right; //情况1,z的叔叔y是红色的 if(uncle->RB_COLOR == RED) { node->parent->RB_COLOR = BLACK; uncle->RB_COLOR = BLACK; node->parent->parent->RB_COLOR = RED; node = node->parent->parent; } else if(uncle->RB_COLOR == BLACK) { //情况3,z的叔叔y是黑色的,z是右孩子 if(node == node->parent->right) { node = node->parent; RB_LeftRotate(node); } //情况2,z的叔叔y是黑色的,但z是左孩子 else { node->parent->RB_COLOR = BLACK; node->parent->parent->RB_COLOR = RED; RB_RightRotate(node->parent->parent); } } } else { RB_Node *uncle = node->parent->parent->left; if(uncle->RB_COLOR == RED) { node->parent->RB_COLOR = BLACK; uncle->RB_COLOR = BLACK; uncle->parent->RB_COLOR = RED; node = node->parent->parent; } else if (uncle->RB_COLOR == BLACK) { if(node == node->parent->left) { node = node->parent; RB_RightRotate(node); } else { node->parent->RB_COLOR = BLACK; node->parent->parent->RB_COLOR = RED; RB_LeftRotate(node->parent->parent); } } } } root->RB_COLOR = BLACK; }
- 红黑树笔记——红黑树的插入操作
- 红黑树的插入操作
- 数据结构-----红黑树的插入操作
- 查找 -- 红黑树的插入操作
- 红黑树——旋转、插入操作
- 红黑树的插入操作详解(插入调整)
- 红黑树(二)红黑树的插入操作
- VI学习笔记——插入模式下的操作技巧
- 红黑树插入操作的C++实现
- 红黑树的插入删除操作图解
- 红黑树的基本插入和删除操作
- 红黑树插入操作和删除的代码
- 红黑树(2) - 插入操作
- 红黑树、插入删除操作
- 红黑树插入删除操作
- 红黑树插入操作
- 数据结构之红黑树(二)——插入操作
- 数据结构之红黑树(二)——插入操作
- 如何为ios程序增加itunes同步功能
- Oracle BIEE 11.1.1.5.0相关文档
- 几月黄花落满地
- foursquared 1
- SoundPool 和 MediaPlayer
- 红黑树笔记——红黑树的插入操作
- 用FileStream 类读写字节
- 抽象类和接口的详细区别
- to be professional,to be perfect
- bat文件介绍
- const的位置与区别
- mysql改成sqlserver产生的问题
- 剖析MySQL左连接/右连接/等值连接异同
- Integer自动打包机制