目录
1.2-2 要删除节点D为黑色,兄弟节点有左孩子,右孩子为空
1.2-3 要删除节点D为黑色,兄弟节点有右孩子,左孩子为空
1.2-4 要删除节点为黑色,兄弟节点左右孩子都存在,且为红色
当我们真正热爱这世界时,我们才真正生活在这世上。——泰戈尔
前面我发布了三篇关于红黑树操作的博客,那这一篇就是对前三篇做一个汇总,前三篇的内容基本上都在本篇文章中,到这里红黑树的内容就全部结束了,以下就是红黑树的所有内容,各位看官请看!
前三篇链接
初识红黑树:数据结构-----红黑树简介-CSDN博客
红黑树的插入:数据结构-----红黑树的插入-CSDN博客
红黑树的删除:数据结构-----红黑树的删除操作-CSDN博客
红黑树是一种自平衡的二叉查找树,是一种高效的查找树。它是由 Rudolf Bayer 于1972年发明,在当时被称为对称二叉 B 树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的红黑树。
红黑树如图所示:
在此之前我们学习了AVL树,既然AVL树有了高效率的查找功能,那需要红黑树干什么呢?下面看对比就知道了。
红黑树(Red-Black Tree)和AVL树(Adelson-Velsky and Landis Tree)都是自平衡二叉搜索树,用于在动态数据集上进行高效的插入、删除和搜索操作。它们之间有一些相似之处,但也存在一些关键的区别。如下所示:
平衡性比较:
AVL树:平衡二叉树是一种绝对平衡的二叉树,其满足每个节点的左右子树的高度只差不超过1,所以其在查找方面上是非常迅捷的,但是在插入和删除操作的时候要不断去旋转来满足平衡条件。
红黑树:红黑树是一种弱平衡的二叉树,其不需要像AVL树那样满足左右子树高度差不超过1,红黑树树的高度最多是2倍的对数级别,所以红黑树的插入和删除操作方面更具有灵活性,但是有一些方面性能还是不如AVL树的。
插入和删除性能比较:
AVL树:AVL树在插入和删除过程中必须满足绝对平衡,所以要频繁的进行旋转操作,时间复杂度比较大
红黑树:红黑树是满足弱平衡状态,有红黑两种颜色去控制树的结构,在插入和删除过程中不需要多次旋转操作,这方面是优于平衡二叉树的。
操作效率比较:
AVL树:平衡二叉树满足绝对平衡,其查找效率绝对是最快的,时间复杂度为 O(logn).
红黑树:虽然红黑树的查找时间复杂度也是O(logn),但是相较于平衡二叉树,操作速度是要慢一些的。
对比总结
AVL树:适合应用于搜索场景,以查为主。
红黑树:适合用于频繁插入、删除场景,其实用性更加强。
总的来说各有各的特色吧,现实生活和工作中用的比较多的方面那肯定是红黑树的了,所以学好红黑树很重要!!!
红黑树的相关应用场景:
红黑树具有良好的效率,它可在 O(logN) 时间内完成查找、增加、删除等操作。因此,红黑树在业界应用很广泛,比如 Java 中的 TreeMap,JDK 1.8 中的 HashMap、C++ STL 中的 map 均是基于红黑树结构实现的。
既然知道了红黑树的优秀,多余的就不多说了,所以这里就开始学习红黑树的知识点了,首先先了解红黑树的特性,需要什么条件才可以满足红黑树。
对于一个红黑树必须满足以下的6个特性:
1.红黑树是一个二叉排序树
2.每个节点要么是红色,要么是黑色
3.根结点是黑色的
4.叶子节点(外部节点,NULL节点、失败的节点)都是黑色的
5.红色节点的父节点和子节点都是黑色的(不存在两个相邻的红色节点)
6.对于每一个节点,从该节点到任一叶子结点的路径上,其所含黑色节点的数量相同
红黑树上面这6条性质可能对于有些人不太好记住或者记错,别急,我下面送各位一个顺口溜,保证你们看了就懂:
顺口溜解释:
左根右:表示红黑树满足 左子节点<根节点<右子节点,也就是满足排序条件
根叶黑:表示跟节点和叶子节点都是黑色的a
不红红:表示不能有两个连续的红色节点(父节点和子节点不可能同时是红色的)
黑路同:表示从任意应该节点走到子节点路径上的黑色节点数量是相同的
记住了这个顺口溜就等于记住了红黑树的特性,是不是很简单呢?来下面看几个简单的判断是否为红黑树的示例:
示例1:
很明显这个不是红黑树,为什么呢?没有排序啊!!!
示例2:
这个也不是红黑树,因为不满足 “不红红” 的特性。
示例3:
这个也不是红黑树,可能有点不太好看,看到13->8->1->6 这条路径,发现有什么不同呢?很明显,这里不满足 “黑路同” 的性质,相较于其他路径这里多了一个黑色节点的数量。
根据红黑树的要求,我们可以去定义红黑树节点和树的结构体,如下所示:
- //宏定义颜色
- #define red 0
- #define black 1
-
- //数据类型Datatype
- typedef char Datatype;
- //红黑树节点存储结构
- typedef struct node {
- Datatype data;
- int color;
- int key;//排序键值,根据key大小排序
- struct node* par;//父节点指针
- struct node* left, * right;//左右子节点指针
- }Node;
-
- //红黑树的定义rbtree
- typedef struct tree {
- Node* root;//指向根节点指针
- Node* nil;//叶子节点(哨兵)
- }rbtree;
在数据结构当中,旋转操作是一种很常见的操作,可能去实现数据结构平衡或者其他相关特性的要求,同样的的AVL树和红黑树里边也是要进行旋转操作的,通过旋转来满足平衡的特性。旋转分两种:左旋(Left Rotation)和右旋(Right Rotation)
左旋是一种将某个节点的右子节点旋转上来的操作。也就是说当前节点的右子节点顶替了自己,然后自己变为右子节点的左子节点,以保持树的平衡。
操作如下:
- 将当前节点的右子节点设为新的父节点。
- 将新的父节点的左子节点设为当前节点的右子节点。
- 如果当前节点有父节点,将新的父节点替代当前节点的位置。
- 将当前节点设为新的父节点的左子节点。
代码实现:
- //左旋(以x为旋转点,向左旋转)
- void left_rotate(rbtree* T, Node* x) {
- Node* y = x->right;//标记到右子节点
- x->right = y->left;//y的左子节点代替x的右子节点
- if (x->right != T->nil)
- x->right->par = x;//如果不为空(nil)其父节点指向x
- y->par = x->par;//把y的父节点指向x的父节点,此时x与y没有直接联系了
- if (x->par == T->nil) {//判断x的父节点是否为根结点
- T->root = y;//如果是的话,y就变为根结点
- }
- else {
- //y顶替x的位置
- if (x == x->par->left)
- x->par->left = y;//如果x是父节点的左边,那y就代替x成为左子节点
- else
- x->par->right = y;//如果x是父节点的右边,那y就代替x成为右子节点
- }
- //y的左子节点指向x,x的父节点指向y
- y->left = x;
- x->par = y;
- }
同样的右旋也是将左子节点顶替自己成为父节点, 然后自己成为左子节点的右子节点。
操作如下:
- 将当前节点的左子节点设为新的父节点
- 将新的父节点的右子节点设为当前节点的左子节点
- 如果当前节点有父节点,将新的父节点替代当前节点的位置
- 将当前节点设为新的父节点的右子节点
代码实现:
- //右旋(以x为旋转点,向右旋转)
- void right_rotate(rbtree* T, Node* x) {
- Node* y = x->left;//标记到左子节点y
- x->left = y->right;//y的右子节点代替x的左子节点
- if (x->left != T->nil)
- x->left->par = x;
- y->par = x->par;//y的父节点指向x的父节点
- if (x->par == T->nil)
- T->root = y;//如果x是根结点的话,那么y代替x成为根结点
- else {
- if (x == x->par->left)
- x->par->left = y;
- else
- x->par->right = y;
- }
- //y的右子节点指向x,x的父节点为y
- y->right = x;
- x->par = y;
- }
再讲之前,我分享一个网址给大家(链接:Red/Black Tree Visualization),这个是一个红黑树模拟器的网址,你们可以去进行红黑树插入删除遍历等操作,可以自己试试看。如下图所示:
废话不多说了,上正文!
红黑树的插入操作分两步走:
注意:插入节点初始为红色
原因分析:因为红黑树中任意一个节点到叶子节点路径所含黑色节点数量相同,也就是说如果我插入的节点为黑色的话,那么就会破坏红黑树的要求,所以插入的节点必须是红色节点,才能保证红黑树的性质。
下面就开始讨论红黑树的几种插入情况:
这是最简单的插入情况,当插入第一个节点的时候,红黑树为空我们只需要让根节点指向这个节点即可。操作如下:
- 根节点指向此节点
- 把根节点染黑
这种情况的话我们可以根据自己喜好去处理,如果出现了重复的key,那么就把这个key里面的值进行更新;或者我们不进行插入操作,因为key不可以重复,直接退出插入操作。
这很好处理,直接插入就行了,因为父节点为黑色,插入节点为红色,所以不会影响红黑树的平衡性。
- 直接插入即可
这种情况是最为复杂的,由于父节点颜色是红色,所以要进行平衡调整,所以要去进一步的讨论才行。那具体根据什么去调整呢?是看叔叔节点的颜色来调整(父节点的兄弟节点),具体分以下几种情况:
大的有两种情况,要看父节点是祖父节点的左边还是右边,下面我就以父节点为左子节点为例子:
下文图标说明:
t 表示插入的节点
P表示父节点
B表示叔叔节点
PP表示祖父节点
如果叔叔节点的颜色是红色的话,这里不需要进行旋转操作,只需要让父节点和叔叔节点颜色变为黑色,祖父节点颜色变为红色即可。流程如下:
这里的话又要去分两种情况:
- 插入节点是父节点的左子节点
- 插入节点是父节点的右子节点
如果插入的节点是父节点的左子节点的话,那么要进行以下操作:
如果插入节点是作为父节点的右子节点的话,要进行以下操作:
这里的操作跟4.1基本上是一模一样的,只是对称过去是了,但是我还是想详细列出来吧,下面接着看。
操作步骤如下:
同样的也是分以下两种情况讨论:
以上这些就是红黑树的插入全部可能了,是不是很多啊,其实还好啦!只要我们把这些情况一个一个分类,然后思路捋一捋很容易弄明白的,后面讲到红黑树的删除还有更多种情况呢!还有就是,这些图片是我自己画的,呃画得不太好,不好意思哈。
红黑树是二叉排序树,查找也跟AVL树是一样的,根据key的值的大小去向左向右查找,找到就返回即可。代码如下:
- //根据key查找
- Node* Search_key(rbtree* T, int target) {
- assert(T);
- assert(T->root);
- Node* cur = T->root;
- while (cur) {
- if (cur->key == target)
- return cur;//找到就返回
- else if (cur->key > target)
- cur = cur->left;
- else
- cur = cur->right;
- }
- printf("The target is not exist\n");
- return NULL;
- }
红黑树的删除所有情况如下所示:
- 删除的是叶子节点(下面又分2种情况)
- 删除节点的颜色是红色
- 删除节点的颜色是黑色(下面再分5种情况)
- 兄弟节点没有左右孩子
- 兄弟节点左孩子为红色,右孩子为黑色
- 兄弟节点右孩子为红色,左孩子为黑色
- 兄弟节点有左右孩子,且都为红色
- 兄弟节点有左右孩子,且都为黑色(兄弟节点为红色)
- 删除的只有左子节点,没有右子节点
- 删除的只有右子节点,没有左子节点
- 删除的既有左子节点,又有右子节点
以上就是红黑树删除操作的全部情况,非常清晰,那这里就要去进行一个一个来讨论了。
以下图片标注说明
D:表示要删除的节点
P:表示删除节点的父节点
B:表示D的兄弟节点
LN:表示B的左子节点
RN:表示B的右子节点
如果删除的是叶子节点,那就要去看删除节点的颜色来操作,以下分两种情况:
注意事项
删除的是叶子结点,右两种可能,也就是要删除的叶子结点是左叶子结点或者是右叶子结点,下面我会去通过删除左叶子结点来去讨论上面这些过程,如果要删除右叶子结点,这里只需要进行对称操作就行了
直接删除,因为删除掉红色节点不会影响到红黑树的基本特性
如果要删除节点的颜色为黑色的话,那么这里就要考虑到被删除节点的兄弟节点的颜色了:
操作如下:
- 删除D节点
- P的颜色变为黑色
- B的颜色变为红色
操作如下:
- 删除D节点
- 对B进行右旋
- LN的颜色变为P的颜色
- P的颜色变为黑色
- 对P进行左旋
操作如下:
- 删除D节点
- B的颜色变P的颜色
- P的颜色变为黑色
- 对P进行左旋
操作如下:
- 删除D节点
- 对P进行左旋
- B的颜色变为P的颜色
- P的颜色染为黑色
- RN的颜色染为黑色
对于这种情况的话,父节点P的颜色那就是必须为黑色了,操作如下:
- 删除节点D
- 对P进行左旋
- B的颜色染黑
- LN的颜色染红
这里只讨论了删除节点作为左叶子节点的情况,还有作为右叶子结点的情况还没有说,但是操作跟上面这5种是一模一样的,只是个对称而已,这里就不多说了,各位可以自己照着上面的方式进行画图理解
对于这种情况,也就只有下图这种样式:
- 将D的值替换为LC的值
- 删除LC节点
对于这种情况,也是只有下图的样式:
- 将D的值替换为RC的值
- 删除RC节点
对于这种情况处理,我们在前面学习二叉排序树的时候就已经知道了,首先要找到这个节点的后驱来替代这个节点,也就是在这个节点右子树找到最小的那个节点temp,替代这个被删除的节点D,然后问题就转换为删除temp节点,对于t删除emp节点就转化为上面三大类的删除情况(递归即可)。
- #include
- #include
- #include
- #include
-
- //宏定义颜色
- #define red 0
- #define black 1
-
- //数据类型Datatype
- typedef char Datatype;
- //红黑树节点存储结构
- typedef struct node {
- Datatype data;
- int color;
- int key;
- struct node* par;//父节点指针
- struct node* left, * right;//左右子节点指针
- }Node;
-
- //红黑树的定义rbtree
- typedef struct tree {
- Node* root;//指向根节点指针
- Node* nil;//叶子节点(哨兵)
- }rbtree;
-
-
- //创建初始化红黑树
- rbtree* Create_inittree();
- //插入数据
- void Insert_node(rbtree* T, Datatype data, int key);
- //已有数据,自增加key创建红黑树
- void Create_wholetree(rbtree* T, Datatype* data, int n);
- //中序遍历
- void inorder_travel(Node* nil, Node* root);
- //key查找
- Node* Search_key(rbtree* T, int target);
- //删除节点操作
- void Delete_node(rbtree* T, Node* target);
-
-
- //主函数
- int main() {
- rbtree* T = Create_inittree();
- Datatype d[] = { "ABCDEFG" };
- int n = sizeof(d) / sizeof(Datatype) - 1;
- Create_wholetree(T, d, n);
-
- inorder_travel(T->nil, T->root);
-
- Node* p = Search_key(T, 2);
- printf("查找结果 %d:%c\n", p->key, p->data);
-
- Delete_node(T, p);
- printf("删除后遍历结果:\n");
- inorder_travel(T->nil, T->root);
- }
-
- //创建初始化红黑树
- rbtree* Create_inittree() {
- rbtree* T = (rbtree*)malloc(sizeof(rbtree));
- assert(T);
- T->nil = (Node*)malloc(sizeof(Node));
- assert(T->nil);
- //T->nil是不储存数据的节点,作为空节点代替NULL,也就是哨兵节点(表示空)
- T->nil->color = black;
- T->nil->par = NULL;
- T->nil->left = T->nil->right = NULL;
- T->root = T->nil;
- return T;
- }
-
- //创建一个节点
- Node* Create_node(rbtree*T ,Datatype data, int key) {
- Node* new_node = (Node*)malloc(sizeof(Node));
- assert(new_node);
- new_node->data = data;
- new_node->color = red;//初始化颜色红色
- //左右父节点为nil哨兵节点
- new_node->left=new_node->right = T->nil;
- new_node->par = T->nil;
- new_node->key = key;
- return new_node;
- }
-
- //左旋(以x为旋转点,向左旋转)
- void left_rotate(rbtree* T, Node* x) {
- Node* y = x->right;//标记到右子节点
- x->right = y->left;//y的左子节点代替x的右子节点
- if (x->right != T->nil)
- x->right->par = x;//如果不为空(nil)其父节点指向x
- y->par = x->par;//把y的父节点指向x的父节点,此时x与y没有直接联系了
- if (x->par == T->nil) {//判断x的父节点是否为根结点
- T->root = y;//如果是的话,y就变为根结点
- }
- else {
- //y顶替x的位置
- if (x == x->par->left)
- x->par->left = y;//如果x是父节点的左边,那y就代替x成为左子节点
- else
- x->par->right = y;//如果x是父节点的右边,那y就代替x成为右子节点
- }
- //y的左子节点指向x,x的父节点指向y
- y->left = x;
- x->par = y;
- }
- //右旋(以x为旋转点,向右旋转)
- void right_rotate(rbtree* T, Node* x) {
- Node* y = x->left;//标记到左子节点y
- x->left = y->right;//y的右子节点代替x的左子节点
- if (x->left != T->nil)
- x->left->par = x;
- y->par = x->par;//y的父节点指向x的父节点
- if (x->par == T->nil)
- T->root = y;//如果x是根结点的话,那么y代替x成为根结点
- else {
- if (x == x->par->left)
- x->par->left = y;
- else
- x->par->right = y;
- }
- //y的右子节点指向x,x的父节点为y
- y->right = x;
- x->par = y;
- }
-
- //插入后平衡调整
- void Insert_adjust(rbtree* T, Node* t) {
- //如果父节点的颜色是红色那就进行调整操作了
- if (t->par->color == red) {
- Node* p = t->par;
- Node* pp = p->par;
- //01 p节点是pp左子节点
- if (p == pp->left) {
- Node* uncle = pp->right;
- //01-1 叔叔节点颜色是红色
- if (uncle->color == red) {
- p->color = black;
- uncle->color = black;
- pp->color = red;
- t = pp;
- }
- //01-2 叔叔节点颜色是黑色
- else {
- //01-2-1 插入节点t是p的左子节点
- if (t == p->left) {
- p->color = black;
- pp->color = red;
- right_rotate(T, pp);
- t = p;
- }
- //01-2-2 插入节点t是p的右子节点
- else if(t==p->right){
- left_rotate(T, p);
- t->color = black;
- pp->color = red;
- right_rotate(T, pp);
- }
- }
- }
- //02 p节点是pp的右子节点
- else {
- Node* uncle = pp->left;
- //02-1 叔叔节点颜色是红色
- if (uncle->color == red) {
- pp->color = red;
- p->color = black;
- uncle->color = black;
- t = pp;
- }
- //02-2 叔叔节点颜色是黑色
- else {
- //02-2-1 插入节点t是p的右子节点
- if (t == p->right) {
- p->color = black;
- pp->color = red;
- left_rotate(T,pp);
- t = p;
- }
- //02-2-2 插入节点t是p的左子节点
- else {
- right_rotate(T, p);
- t->color = black;
- pp->color = red;
- left_rotate(T, pp);
- }
- }
- }
- }
- //根节点标记黑色
- T->root->color = black;
- }
-
- //插入节点
- void Insert_node(rbtree* T, Datatype data,int key) {
- assert(T);
- Node* t = Create_node(T ,data, key);
- Node* root = T->root;//快指针
- Node* cur=T->nil;//慢指针
- //1.如果根节点为空
- if (T->root==T->nil) {
- T->root = t;//根结点指向新创建的节点
- }
- else {
- while (root != T->nil) {
- cur = root;//cur标记为root的上一个节点(父节点)
- if (t->key > root->key)
- root = root->right;
- else if (t->key < root->key)
- root = root->left;
- //如果出现插入重复的key值,就退出,不进行插入操作
- else {
- printf("Don't insert the same key!\n");
- free(t);
- t = NULL;
- return;
- }
- }
- }
- //判断插入的位置
- if (key < cur->key)
- cur->left = t;//小的话就插入左边
- else
- cur->right = t;//大的话就插入右边
- t->par = cur;//新插入的父节点指针指向cur
- Insert_adjust(T, t);//平衡调整
- }
-
- //已有数据,自增加key创建红黑树
- void Create_wholetree(rbtree* T, Datatype* data, int n) {
- for (int i = 0; i < n; i++) {
- Insert_node(T, data[i], i+1);
- }
- }
-
- //中序遍历
- void inorder_travel(Node* nil,Node* root) {
- if (root == nil)
- return;
- inorder_travel(nil, root->left);
- printf("%d: %c\n", root->key, root->data);
- inorder_travel(nil, root->right);
- }
-
- //根据key查找
- Node* Search_key(rbtree* T, int target) {
- assert(T);
- assert(T->root);
- Node* cur = T->root;
- while (cur) {
- if (cur->key == target)
- return cur;//找到就返回
- else if (cur->key > target)
- cur = cur->left;
- else
- cur = cur->right;
- }
- printf("The target is not exist\n");
- return NULL;
- }
-
- //删除黑色叶子节点调整
- void Del_b_adjust(rbtree* T, Node* x) {
- //被删除节点x父节点的左边
- if (x == x->par->left) {
- Node* p = x->par;//父节点
- Node* b = p->right;//兄弟节点
- p->left = T->nil;
- //删除节点x
- free(x);
- x = NULL;
- //1.兄弟节点为黑色
- if (b->color == black) {
- //1-1没有侄子节点
- if (b->left == T->nil && b->right == T->nil) {
- p->color = black;
- b->color = red;
- }
- //1-2左侄节点红色
- else if (b->left->color == red && b->right == T->nil) {
- right_rotate(T, b);
- b->par->color = p->color;
- p->color = black;
- left_rotate(T, p);
- }
- //1-3右侄子节点红色
- else if (b->left == T->nil && b->right->color == red) {
- b->color = p->color;
- p->color = black;
- left_rotate(T, p);
- }
- //1-4 两个侄子节都是红色
- else {
- left_rotate(T, p);
- b->color = p->color;
- b->right->color = black;
- p->color = black;
- }
- }
- //2.兄弟节点为红色
- else {
- left_rotate(T, p);
- b->color = black;
- p->right->color = red;
- }
- }
-
- //被删除节点在父节点的右边
- else {
- Node* p = x->par;
- Node* b = p->left;
- p->right = T->nil;
- free(x);
- x = NULL;
- //1.兄弟节点黑色
- if (b->color == black) {
- //1-1没有侄子节点
- if (b->left == T->nil && b->right == T->nil) {
- p->color = black;
- b->color = red;
- }
- //1-2兄弟有右子节点
- else if (b->right->color == red && b->left == T->nil) {
- left_rotate(T, b);
- b->par->color = p->color;
- p->color = black;
- right_rotate(T, p);
- }
- //1-3 兄弟有左子节点
- else if (b->left->color == red && b->right == T->nil) {
- b->color = p->color;
- p->color = black;
- b->left->color = black;
- right_rotate(T, p);
- }
- //1-4 兄弟有左右子节点
- else {
- right_rotate(T, p);
- b->color = p->color;
- p->color = black;
- b->left->color = black;
- }
- }
- //2.兄弟节点为红色
- else {
- right_rotate(T, p);
- b->color = black;
- p->left->color = red;
- }
- }
- }
- //查找删除替身节点(找后驱)
- Node* node_successor(rbtree* T, Node* root) {
- while (root->left != T->nil)
- root = root->left;
- return root;
- }
- //删除节点操作
- void Delete_node(rbtree* T, Node* target) {
- //1.删除的节点是叶子节点
- if (target->left == T->nil && target->right == T->nil) {
- //1-01如果这个节点是红色节点
- if (target->color == red) {
- if (target == target->par->left)
- target->par->left = T->nil;
- else
- target->par->right = T->nil;
- free(target);
- target = NULL;
- }
- //1-02 如果是黑色叶子节点进入到调整
- else
- Del_b_adjust(T, target);
- }
- //2.删除的只有一个左孩子的节点
- else if (target->left != T->nil && target->right == T->nil) {
- Node* lc = target->left;
- target->data = lc->data;
- target->key = lc->key;
- target->left = T->nil;
- free(lc);
- lc = NULL;
- }
- //3.删除的只有一个右孩子的节点
- else if (target->left == T->nil && target->right != T->nil) {
- Node* rc = target->right;
- target->data = rc->data;
- target->key = rc->key;
- target->right = T->nil;
- free(rc);
- rc = NULL;
- }
- //4.删除的节点有左右孩子
- else {
- Node* sub = node_successor(T, target->right);//找到替代者
- target->data = sub->data;
- target->key = sub->key;
- Delete_node(T, sub);//递归进入到前三种删除方式
- }
-
- T->root->color = black;//根结点为黑色
- }
好了,以上就是红黑树的全部内容了,我们下一期开始学习新的数据结构----图,下次见咯!
分享一张壁纸: