笔试算法题(51):简介 - 红黑树(RedBlack Tree)

红黑树(Red-Black Tree)

  • 红黑树是一种BST,但是每个节点上增加一个存储位表示该节点的颜色(R或者B);通过对任何一条从root到leaf的路径上节点着色方式的显示,红黑树确保所有路径的差值不会超过一倍,最终使得BST接近平衡;

  • 红黑树内每个节点包含五个属性:color, key, left,
    right和p,p表示指向父亲节点的指针;一棵BST需要同时满足下述五个性质才能称作红黑树:

    每个节点只能是红色或者黑色节点中的一种;

    根节点必须是黑色;

    每个叶节点(NULL)必须是黑色;

    如果一个节点是红色,则它的两个子节点必须是黑色;

    对于树中任何一个节点,该节点到其叶节点的所有路径上的黑色节点数相同


  • 红黑树的空间复杂度为O(N);支持三种操作:search, insert,
    delete,并且所有操作的时间复杂度都为O(logN),最好情况跟最坏情况的复杂度相同。对于search操作而言,其依赖BST的性质,所以不需
    要依赖节点的着色信息;着色信息仅为了保证BST的平衡性,insert和delete操作则可能破坏BST的平衡性,所以这两种操作需要对红黑树中节点
    的着色信息进行调整。
     


 1 //左旋操作中,oldroot的右子节点成为新的root,root的左子节点成为oldroot的右子节点,
2 //oldroot成为新root的左子节点
3 template <class KeyType>
4 void Node<KeyType>::RotateLeft(Node<KeyType> * & root) {
5 Node<KeyType> * oldRoot = root;
6 root = root->mySubtree[RIGHT];
7 oldRoot->mySubtree[RIGHT] = root->mySubtree[LEFT];
8 root->mySubtree[LEFT] = oldRoot;
9 }
10
11 //右旋操作中,oldroot的左子节点成为新的root,root的右子节点成为oldroot的左子节点,
12 //oldroot成为新root的右子节点
13 template <class KeyType>
14 void Node<KeyType>::RotateRight(Node<KeyType> * & root) {
15 Node<KeyType> * oldRoot = root;
16 root = root->mySubtree[LEFT];
17 oldRoot->mySubtree[LEFT] = root->mySubtree[RIGHT];
18 root->mySubtree[RIGHT] = oldRoot;
19 }
20
21 //向T索引的红黑树中插入新节点z,使用BST的性质查找z的插入位置,并且将新节点z标
22 //注为红色;
23 RB-INSERT(T, z)
24 y ← nil[T]
25 x ← root[T]
26 while x ≠ nil[T]
27 do y ← x
28 if key[z] < key[x]
29 then x ← left[x]
30 else x ← right[x]
31 p[z] ← y
32 if y = nil[T]
33 then root[T] ← z
34 else if key[z] < key[y]
35 then left[y] ← z
36 else right[y] ← z
37 left[z] ← nil[T]
38 right[z] ← nil[T]
39 color[z] ← RED
40 RB-INSERT-FIXUP(T, z)

插入一个节点并标注为红色的操作可能破坏红黑树的性质2和性质4;当插入节点为根节点的时候破坏性质2,此时直接将其变成黑色就可以恢复;当破坏性质4的时候则需要一系列的恢复操作;
case1:原树为空,新节点为根节点;恢复策略为将其改成黑色;
case2:新节点的父节点是黑色;满足所有红黑树规则;
case3:新节点的父节点是红色,父节点的兄弟节点是红色;恢复策略为将新节点的父节点和父节点的兄弟节点改成黑色,其祖父节点改成红色,针对祖父节点重新调用该方法;
case4:新节点的父节点是红色,父节点的兄弟节点是黑色,新节点为父节点的右子;恢复策略为以新节点的父节点为支点左旋;
case5:新节点的父节点是红色,父节点的兄弟节点是黑色,新节点为父节点的左子;恢复策略为将新节点的父节点改成黑色,祖父节点改成红色,并以祖父节点为支点右旋;


 1 RB-INSERT-FIXUP(T, z)
2 while color[p[z] = RED
3 do if p[z] = left[p[p[z]]
4 then y ← right[p[p[z]]
5 if color[y] = RED
6 then color[p[z] ← BLACK ? Case 3
7 color[y] ← BLACK ? Case 3
8 color[p[p[z]] ← RED ? Case 3
9 z ← p[p[z] ? Case 3
10 else if z = right[p[z]
11 then z ← p[z] ? Case 4
12 LEFT-ROTATE(T, z) ? Case 4
13 color[p[z] ← BLACK ? Case 5
14 color[p[p[z]] ← RED ? Case 5
15 RIGHT-ROTATE(T, p[p[z]) ? Case 5
16 else (same as then clause with "right" and "left" exchanged)
17 color[root[T] ← BLACK
18
19 //
20 RB-DELETE(T, z)
21 if left[z] = nil[T] or right[z] = nil[T]
22 then y ← z
23 else y ← TREE-SUCCESSOR(z)
24 if left[y] ≠ nil[T]
25 then x ← left[y]
26 else x ← right[y]
27 p[x] ← p[y]
28 if p[y] = nil[T]
29 then root[T] ← x
30 else if y = left[p[y]
31 then left[p[y] ← x
32 else right[p[y] ← x
33 if y 3≠ z
34 then key[z] ← key[y]
35 copy y‘s satellite data into z
36 if color[y] = BLACK
37 then RB-DELETE-FIXUP(T, x)
38 return y

case1:x的兄弟w是红色
case2:x的兄弟w是黑色,并且w的两个孩子是黑色
case3:x的兄弟w是黑色,并且w的左孩子是红色,w的右孩子是黑色
case4:x的兄弟w是黑色,并且w的右孩子是红色


 1 RB-DELETE-FIXUP(T, x)
2 while x ≠ root[T] and color[x] = BLACK
3 do if x = left[p[x]
4 then w ← right[p[x]
5 if color[w] = RED
6 then color[w] ← BLACK ? Case 1
7 color[p[x] ← RED ? Case 1
8 LEFT-ROTATE(T, p[x]) ? Case 1
9 w ← right[p[x] ? Case 1
10 if color[left[w] = BLACK and color[right[w] = BLACK
11 then color[w] ← RED ? Case 2
12 x ← p[x] ? Case 2
13 else if color[right[w] = BLACK
14 then color[left[w] ← BLACK ? Case 3
15 color[w] ← RED ? Case 3
16 RIGHT-ROTATE(T, w) ? Case 3
17 w ← right[p[x] ? Case 3
18 color[w] ← color[p[x] ? Case 4
19 color[p[x] ← BLACK ? Case 4
20 color[right[w] ← BLACK ? Case 4
21 LEFT-ROTATE(T, p[x]) ? Case 4
22 x ← root[T] ? Case 4
23 else (same as then clause with "right" and "left" exchanged)
24 color[x] ← BLACK

笔试算法题(51):简介 - 红黑树(RedBlack Tree),布布扣,bubuko.com

时间: 2024-08-25 16:02:29

笔试算法题(51):简介 - 红黑树(RedBlack Tree)的相关文章

[Data Structure] 红黑树( Red-Black Tree ) - 笔记

1.  红黑树属性:根到叶子的路径中,最长路径不大于最短路径的两倍. 2. 红黑树是一个二叉搜索树,并且有 a. 每个节点除了有左.右.父节点的属性外,还有颜色属性,红色或者黑色. b. ( 根属性 ) 红黑树的根只能是黑色 c. ( 红色属性 ) 红色节点的子节点只能是黑色 d. ( 黑色属性 ) 从给定的节点到其后代叶子节点的每一条路径上,出现的黑色节点数目一样.其中,从某个节点到其后代叶子节点的路径上出现的黑色节点数,被称为该节点的黑高度( black-height ). 3. 红黑树上的

[转]SGI STL 红黑树(Red-Black Tree)源代码分析

STL提供了许多好用的数据结构与算法,使我们不必为做许许多多的重复劳动.STL里实现了一个树结构-Red-Black Tree,它也是STL里唯一实现的一个树状数据结构,并且它是map, multimap,set,multiset的底层实现,如果学会了Red-Black Tree,那么对我们高效的运用STL是很有帮助的. 1. 什么是红黑树 红黑树是二叉查找树的一种,由于它能够保证树的高度比较底,所以是一种性能较好的查找树.它需要满足以下几条性质: 1.每个结点或是红的,或是黑的 2.根结点是黑

数据结构-红黑树(Red-Black Tree)的C++实现模板

红黑树的实现还真不简单,各种染色旋转足足折腾了笔者几天.. 不过收获也是巨大的.笔者现在终于明白为啥二叉搜索树这么重要了,确实很有用. 下面上代码. 细心的朋友可能会觉得似乎少了那么几个接口,没错,因为 Precessor(求前驱) / Successor(求后继) / getMaximum (求树中最大值)/ getMinimum(求树中最小值)/ Inorder Traversal(中序遍历)/ Postorder Traversal(后序遍历) 这些操作都可以直接用笔者二叉搜索树(BST)

手撸红黑树-Red-Black Tree 入门

一.学习红黑树前的准备: 熟悉基础数据结构 了解二叉树概念 二.红黑树的规则和规则分析: 根节点是黑色的 所有叶子节点(Null)是黑色的,一般会认定节点下空节点全部为黑色 如果节点为红色,那么子节点全部为黑色 从某一节点出发,到达叶子节点的所有分支上,黑色节点的数量相同 由规则4引出的一个定义,从根节点到叶子节点的黑色节点数量成为 树的黑色高度.我们会发现由于红色节点下全部为黑色节点,那么最极端的情况就是,根节点出发,左子树全部为黑色节点,右子树为红色-黑色轮换,这样设想下不难发现,树的最长路

笔试算法题(47):简介 - B树 &amp; B+树 &amp; B*树

B树(B-Tree) 1970年由R. Bayer和E. Mccreight提出的一种适用于外查找的树,一种由BST推广到多叉查找的平衡查找树,由于磁盘的操作速度远小于存储器的读写速度,所以要求在尽量少 的操作次数内完成CPU分配的任务,B树就按照此原则设计,B树与红黑树的主要区别在于B树节点可以有超过2个子女,从而大大降低树的高度以减少查询时 间: 一棵M阶B树(Balanced Tree of Order M)是一棵平衡的M路搜索树,满足性质: 根节点至少有两个子女: 除根节点和叶子节点外的

笔试算法题(50):简介 - 广度优先 &amp; 深度优先 &amp; 最小生成树算法

广度优先搜索&深度优先搜索(Breadth First Search & Depth First Search) BFS优缺点: 同一层的所有节点都会加入队列,所以耗用大量空间: 仅能非递归实现: 相比DFS较快,空间换时间: 适合广度大的图: 空间复杂度:邻接矩阵O(N^2):邻接表O(N+E): 时间复杂度:O(V+E): DFS优缺点: 无论是系统栈还是用户栈保存的节点数都只是树的深度,所以空间耗用小: 有递归和非递归实现: 由于有大量栈操作(特别是递归实现时候的系统调用),执行速度

笔试算法题(07):还原后序遍历数组 &amp; 半翻转英文句段

出题:输入一个整数数组,判断该数组是否符合一个二元查找树的后序遍历(给定整数数组,判定其是否满足某二元查找树的后序遍历): 分析:利用后序遍历对应到二元查找树的性质(序列最后一个元素必定是根节点,从左向右第一个比根节点大的元素开始直到根节点之前的所有元素必定在右子树,之前的所有元素必定在左子树): 解题: 1 bool PostOrderCheck(int *array, int i, int j) { 2 /** 3 * 如快速排序一样,解决小子文件 4 * */ 5 if(j-i+1 ==

笔试算法题(24):找出出现次数超过一半的元素 &amp; 二叉树最近公共父节点

出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字: 分析: 解法1:首先对数组进行排序,时间复杂度为O(NlogN),由于有一个数字出现次数超过了数组的一半,所以如果二分数组的话,划分元素肯定就是这个数字: 解法2:首先创建1/2数组大小的Hash Table(哈希表可以替代排序时间,由于一个数字出现超过了数组的一半,所以不同元素个数肯定不大于数组的一半),空间复杂度O(N),顺序扫描映射数 组元素到Hash Table中并计数,最后顺序扫描Hash Table,计数超过数组

笔试算法题(06):最大连续子数组和 &amp; 二叉树路径和值

出题:预先输入一个整型数组,数组中有正数也有负数:数组中连续一个或者多个整数组成一个子数组,每个子数组有一个和:求所有子数组中和的最大值,要求时间复杂度O(n): 分析: 时间复杂度为线性表明只允许一遍扫描,当然如果最终的最大值为0表明所有元素都是负数,可以用线性时间O(N)查找最大的元素.具体算法策略请见代码和注释: 子数组的起始元素肯定是非负数,如果添加的元素为正数则记录最大和值并且继续添加:如果添加的元素为负数,则判断新的和是否大于0,如果小于0则以下一个元素作为起始元素重新开始,如果大于