红黑树详解实现 C++
红黑树详解&实现 C++
红黑树
红黑树是一种自平衡二叉查找树,可以保证在最坏情况下基本动态集合操作的时间复杂度为O(lgn)
性质
- 红黑树是一棵满足红黑性质的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是
RED
或BLACK
- 通过对任何一条从根到叶子的简单路径上各个结点的颜色进行约束,
红黑树确保没有一条路径会比其他路径长出两倍
,因而近似于平衡,可以保证最坏情况下基本动态集合操作的时间复杂度为O(lgn)
- 红黑性质:
- 每个节点是黑色或红色
- 根节点是黑色的
- 每个叶节点都是黑色的
- 若一个节点是红色,则其两个子结点都是黑色的
- 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
- 若一个结点没有子结点或父结点,则该结点相应指针属性的值为NIL,可以把
这些NIL视为指向二叉树的叶节点(外部结点)的指针
,而把带关键字的结点视为树的内部结点
- 从某个结点x出发(不含该节点)到达一个也节点的任意一条简单路径上的黑节点个数成为该节点的黑高(black-height),即为bh(x),红黑树黑高为其根节点黑高
旋转
- 左旋和右旋操作修改红黑树都在
O(1)
时间内完成,旋转只有指针改变,其他所有属性保持不变 左旋右旋修改的树和未修改之前进行中序遍历产生的关键字值列表相同
左旋
C++代码
void RedBlackTree::leftRotate(Node* x) {Node *y = x->right; // 保存x右子树x->right = y->left; // 将y的左子树作为x的右孩子if (y->left != NIL) {// 若y的左子树y->left->parent = x;}// y的双亲设为x的双亲y->parent = x->parent;if (x->parent == NIL) {// 若x为根结点,则旋转后的y作为根节点root = y;} else if (x == x->parent->left) {// 若x是x双亲的左子树,则旋转后y作为x原双亲的左子树x->parent->left = y;} else {// 反之亦然x->parent->right = y;}// 旋转后y作为x的双亲,x作为y的左子树y->left = x;x->parent = y;
}
伪代码
LEFT-ROTATE(T,x)
y = x.right //set y
x.right = y.left // turn y's subtree into x's right subtree
if y.left ≠ T.nily.left.p = x
y.p = x.p
if x.p == T.nilT.root = y
elseif x == x.p.leftx.p.left = y
elsex.p.right = y
y.left = x // put x on y's left
x.p = y
右旋
C++代码
void RedBlackTree::rightRotate(Node* x) {// 与左旋相反Node *y = x->left;x->left = y->right;if (y->right != NIL) {y->right->parent = x;}y->parent = x->parent;if (x->parent == NIL) {root = y;} else if (x == x->parent->left) {x->parent->left = y;} else {x->parent->right = y;}y->right = x;x->parent = y;
}
伪代码
右旋操作的伪代码与左旋相反,交换right
和left
即可
图解
插入
- 在
O(lgn)
时间内完成向一个棵含有n
个结点的红黑树插入一个新节点,并将新节点着色为红色
- 因为新节点着色为红色可能违反其中的一跳红黑性质,故插入后对结点
重新着色并旋转
,以保持红黑性质
C++代码
void RedBlackTree::insert(Node* z) {Node *x = root;Node *y = NIL;while (x != NIL) {// 找到z应插入的位置// y为z应插入位置的双亲y = x;if (z->data < x->data) {x = x->left;} else {x = x->right;}}z->parent = y;if (y == NIL) {// 若z的双亲y为NIL,则z为rootroot = z;} else if (z->data < y->data) {// z结点关键字小于y,z作为y的左子树y->left = z;} else {// 反之为右子树y->right = z;}// 设置新插入结点的左右子树为NIL,着色为红色z->left = NIL;z->right = NIL;z->color = RED;// 进行插入调整以维护红黑性质insertFixup(z);
}
伪代码
RB-INSERT(T, z)
y = T.nil
x = T.root
while x ≠ T.nily = xif z.key < x.keyx = x.leftelse x = x.right
z.p = y
if y == T.nilT.root = z
elseif z.key < y.keyy.left = z
elsey.right = z
z.left = T.nil
z.right = T.nil
z.color = RED
RB-INSERT-FIXUP(T, z)
插入调整操作
- 插入操作必然不会破坏性质1,插入的新结点的左右孩子节点必然是叶子结点,着色均为黑色,满足性质3,故不会破坏性质3,而插入的新节点着色为红色,其代替了一个黑色的叶子节点,同时它的叶子结点为黑色,故不会破坏性质5。
- 故插入操作只可能会破坏性质2和性质4,即根结点为黑色且红色结点不能有黑色的孩子节点。
需要考虑六中情况,其中三种情况另外三种情况左右对称,这取决于z
的双亲结点是祖父结点的左孩子还是右孩子,在z
的双亲是左孩子的情况下,区别于z
的叔结点的颜色不同。
情况1
结点z
和其双亲、叔结点都是红色的,因为结点z
的祖父结点是黑色的,故将z
的双亲结点和叔结点着色为黑色,解决z
及其双亲结点都是红色的问题,同时将z
的祖父结点着色为红色,保证经过当前子树的简单路径的黑色结点数量不变,维护性质5,无论z
是左孩子还是右孩子都可以依此来处理。此时,将z
的祖父结点作为新的z
结点继续调整,现在性质4的破坏只可能发生在新的红色结点z
和它的双亲结点之间,条件是如果其父亲结点也是红色的,因为当前新的红色结点z
的后代子树已经被调整,保证其满足红黑性质,迭代到当前的z
继续调整,若当前的z
为根节点,则跳出循环并将当前结点着色为黑色即可,性质1、性质3和性质4不会被破坏,维护了性质2,由于根节点变为黑色,不影响性质5,故满足红黑性质
情况2
结点z
的叔结点y
是黑色的且z
是一个右孩子,此时z
变为z
的双亲结点,z
上升一层,通过左旋操作使得z
再下降一层,z
的祖父结点不变,由于z
和z
的双亲结点都是红色,故能够维护性质5不变,经过上述操作,将情况2转变为情况3处理
情况3
结点z
的叔结点y
是黑色的且z
是一个左孩子,此时改变结点z
的双亲结点的颜色为黑色,再经过右旋操作维护性质5。在情况2和情况3中,因为唯一着色为红色的z
的祖先节点会因为情况3的右旋操作称为一个黑色结点的子结点,必然不会破坏性质2,同时两种情况的操作调整红黑树以维持性质4,性质1和性质3必然不会被破坏,能够保证红黑树满足红黑性质
C++代码
void RedBlackTree::insertFixup(Node* z) {while (z->parent->color == RED) {if (z->parent == z->parent->parent->left) {Node *y = z->parent->parent->right;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->right) {z = z->parent;leftRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;rightRotate(z->parent->parent);}} else {Node *y = z->parent->parent->left;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->left) {z = z->parent;rightRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;leftRotate(z->parent->parent);}}}root->color = BLACK;
}
伪代码
RB-INSERT-FIXUP(T, z)
while z.p.color == REDif z.p == z.p.p.lefty = z.p.p.rightif y.color == REDz.p.color = BLACK // case1y.color = BLACK // case1z.p.p.color = RED // case1z = z.p.p // case1else if z == z.p.rightz = z.p // case2LEFT-ROTATE(T,z) // case2z.p.color = BLACK // case3z.p.p.color = RED // case3RIGHT-ROTATE(T, z.p.p) // case3else(same as then caluse with "right" and "left" exchanged)y = z.p.p.leftif y.color == REDz.p.color = BLACKy.color = BLACKz.p.p.color = REDz = z.p.pelse if z == z.p.leftz = z.pRIGHT-ROTATE(T,z)z.p.color = BLACKz.p.p.color = REDLEFT-ROTATE(T, z.p.p)T.root.color = BLACK
图解
删除操作
- 红黑树的删除需要考虑四种情况,在考虑四种情况的同时,在整个过程中维护结点
y
为从树中删除的结点或移至树内的结点,当待删除结点z
子节点少于两个时,y
指向待删除结点,否则y
指向z
的后继结点,之后将y
代替z
的位置并删除z
。 - 由于
y
的颜色可能改变,用originalColor
记录y
改变前的颜色,同时赋予y
与z
同样的颜色,再删除操作结束时,若原来的颜色是黑色的,则会引起红黑性质的破坏,因为若是前两种情况,y
指向删除结点z
,若z
为黑色则会破坏红黑性质,若为红色则不会破坏红黑性质;若是后两种情况,y
指向删除后代替z
的结点,且为y
着色为z
的颜色,故z
位置的颜色不变,不会引起红黑性质的破坏,但y
原来的原色若为黑色,则会破坏红黑性质,需要进行调整,若为红色则不会破坏红黑性质 - 维护指针
x
指向y
原来的位置,前两种情况x
指向y
的原始位置,即z
的左孩子或右孩子,后两种情况x
也指向y
的原始位置,此时为y
的右孩子,因为右孩子之后将代替y
情况1
待删除结点z
只有左子树,则让左子树代替待删除结点,再删除结点z
情况2
待删除结点z
只有右子树,则让右子树代替待删除结点,再删除结点z
情况3
待删除结点有两个子树,选取待删除结点的直接后继结点y
,若其直接后继结点y
是待删除结点z
的右孩子,则直接将其用右孩子结点代替,再删除结点z
情况4
待删除结点有两个子树,选取待删除结点的直接后继结点y
,若其直接后继结点y
不是待删除结点z
的右孩子,则将直接后继结点y
用y
的右孩子代替,再将y
从原本以y
为根结点的子树中删除,并用y
代替z
,再删除结点z
,y
为z
右子树中关键字最小的结点,必然没有左子树,若也无右子树,即y
为叶子结点,上述操作会直接删除y
C++代码
void RedBlackTree::remove(Node *z) {Node *y = z;Node *x = NIL;bool originalColor = y->color;if (z->left == NIL) {x = z->right;transplant(z, z->right);} else if (z->right == NIL) {x = z->left;transplant(z, z->left);} else {y = treeMinimum(z->right);originalColor = y->color;x = y->right;if (y->parent == z) {x->parent = y;} else {transplant(y, y->right);y->right = z->right;y->right->parent = y;}transplant(z, y);y->left = z->left;y->left->parent = y;y->color = z->color;}if (originalColor == BLACK) {deleteFixUp(x);}
}
伪代码
RB-DELETE(T, z)
y = z
y-original-color = y.color
if z.left == T.nilx = z.rightRB-TRANSPLANT(T, z, z.right)
elseif z.right == T.nilx = z.leftRB-TRANSPLANT(T, y, y.right)
elsey = TREE-MINIMUM(z.right)y-original-color = y.colorx = y.rightif y.p == zx.p = yelseRB-TRANSPLANT(T, y, y.right)y.right = z.righty.right.p = yRB-TRANSPLANT(T, z, y)y.left = z.lefty.left.p = yy.color = z.color
if y-original-color == BLACKRB-DELETE-FIXUP(T, x)
删除调整操作
- 删除操作中,被删除结点或被移动来代替删除结点的颜色若为红色则能够保持红黑性质,原因如下
- 树中黑高不变
- 不存在相邻的两个红色结点,因为
y
在树中占据z
的位置,在考虑到z
的颜色,树中y
的新位置不可能有两个相邻的红色结点,若y
不是z
的右孩子,则y
原右孩子x
代替y
的位置,若y
是红色,则x
一定是黑色,代替后不可能出现两个红色结点相邻 - 若
y
为红色,则不可能是根结点,故根结点仍然是黑色的
- 被删除结点或被移动来代替删除结点的颜色若为黑色就可能已经引入一个或多个红黑性质被破坏的情况,可能如下问题
- 若
y
是原来的根结点,y
的一个红色孩子成为新的根结点,违反性质2 - 若
x
和x
的双亲都是红色的,违反性质4 - 在树中移动
y
导致先前包含y
的任何简单路径上黑结点数量少1
,故y
的任何祖先都不满足性质5
- 若
- 为改正上述问题,将占有
y
原来位置的结点x
视为还有一重额外的黑色
,在这种假设下,性质5成立,红黑树满足条件,当黑色结点y
删除或移动时,将黑色“下推”给结点x
,现在问题变为结点x
可能既不是黑色也不是红色,而是红黑色或双重黑色,违反性质1,而结点的color
属性仍然为BLACK
或RED
,额外的黑色是针对x
结点的,而不反映在其color
属性上 - 删除调整操作有为八种情况,以
x
是其双亲左孩子为例,x
是双亲右孩子与其对称 - 考虑调整完成的条件
当x
指向红黑结点,即x
结点的color
属性为RED
,将x
着色为黑色,当x
情况1
x
的兄弟结点w
是红色的,因为w
必须有黑色子结点,所以可以改变w
和x
双亲结点的颜色,然后对x
双亲做一次左旋而不违反红黑性质,现在w
指向x
新的兄弟结点,颜色为黑色,这样就从情况1转到情况2、情况3或情况4处理
情况2
x
的兄弟结点w
为黑色且w
的两个子结点都是黑色的,因为w
也是黑色的,所以从x
和w
去掉一重黑色,使得x
只有一重黑色而w
为红色,为补偿从x
和w
中去掉的黑色,在原来是红色或黑色的x
双亲上新增一重黑色,将x
指向x
的双亲继续调整。若是由情况1进入情况2,则新的x
是红黑色的,因为原来的x
的双亲是红色的,现在x
上升代替其双亲并上推一层黑色给双亲,此时红黑色的x
的color
属性为RED
,循环终止,将x
着色为黑色后调整结束;若新x
结点是根结点,也跳出循环,root
着色为黑色,删除x
多余的黑色,调整结束
情况3
x
的兄弟结点w
为黑色且w
左孩子是红色的而w
右孩子是黑色的,交换w
和其左孩子的颜色,在对w
进行右旋操作,而不违反红黑树的性质,此时x
的新兄弟结点w
是一个有红色结点右孩子的黑色结点,转变为情况4
情况4
x
的兄弟结点w
为黑色且w
右孩子是红色的,将双亲结点的颜色赋予w
并将双亲结点染色成黑色,w
的右孩子结点也染色成黑色,将双亲结点左旋,此时对于当前以w
为根结点的子树,根结点的颜色较之前x
的双亲为根时没有改变,x
将一重黑色上推给x
的双亲,而w
将自身原来的黑色推给其原来为红色的右孩子,此时右孩子占据原来w
结点的位置,这样既不会违反红黑性质,也去除x
多余的一重黑色,维护了性质1,满足红黑性质,将x
指向为根结点跳出循环,调整结束。
C++代码
void RedBlackTree::deleteFixUp(Node *x) {while (x != root && x->color == BLACK) {if (x == x->parent->left) {Node *w = x->parent->right;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;leftRotate(x->parent);w = x->parent->right;}if (w->left->color == BLACK && w->right->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->right->color == BLACK) {w->left->color = BLACK;w->color = RED;rightRotate(w);w = x->parent->right;}w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;leftRotate(x->parent);x = root;}} else {Node *w = x->parent->left;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;rightRotate(x->parent);w = x->parent->left;}if (w->right->color == BLACK && w->left->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->left->color == BLACK) {w->right->color = BLACK;w->color = RED;leftRotate(w);w = x->parent->left;}w->color = x->parent->color;x->parent->color = BLACK;w->left->color = BLACK;rightRotate(x->parent);x = root;}}}x->color = BLACK;
}
伪代码
RB-DELETE-FIXUP(T, x)while x != T.root and x.color == BLACKif x == x.p.leftw = x.p.rightif w.color == REDw.color = BLACK // case1x.p.color = RED // case1LEFT-ROTATE(T, x.p) // case1w = x.p.right // case1if w.left.color == BLACK and w.right.color == BLACKw.color = RED // case2x = x.p // case2elseif w.right.color == BLACK // case3w.left.color = BLACK // case3w.color = RED // case3RIGHT-ROTATE(T, w) // case3w = x.p.right // case3w.color = x.p.color // case4x.p.color = BLACK // case4w.right.color = BLACK // case4LEFT-ROTATE(T, x.p) // case4x = T.root // case4elsew = x.p.leftif w.color == REDw.color = BLACK // case1x.p.color = RED // case1LEFT-ROTATE(T, x.p) // case1w = x.p.left // case1if w.right.color == BLACK and w.left.color == BLACKw.color = RED // case2x = x.p // case2elseif w.left.color == BLACK // case3w.right.color = BLACK // case3w.color = RED // case3LEFT-ROTATE(T, w) // case3w = x.p.left // case3w.color = x.p.color // case4x.p.color = BLACK // case4w.left.color = BLACK // case4RIGHT-ROTATE(T, x.p) // case4x = T.root // case4
x.color = BLACK
图解
移动替换操作
将u
替换用v
替换,考虑u
为根结点、左孩子、右孩子的情况,以及v
是否为NIL
的情况
C++代码
void RedBlackTree::transplant(Node *u, Node *v) {if (u->parent == NIL) {root = v;} else if (u == u->parent->left) {u->parent->left = v;} else {u->parent->right = v;}v->parent = u->parent;
}
伪代码
RB-TRANSPLANT(T, u, v)
if u.p == T.nilT.root = v;
elseif u == u.p.leftu.p.left = v
else u.p.right = v
v.p = u.p
查找最小值操作
根据二叉搜索树定义,不断向左寻找,找到最左的顶点即可,操作与二叉搜索树相同
C++代码
Node* RedBlackTree::treeMinimum(Node *x) {while (x->left != NIL) {x = x->left;}return x;
}
伪代码
TREE-MINIMUM(x)
while x.left != NILx = x.left
return x
搜索操作
操作与二叉搜索树相同
C++代码
Node* RedBlackTree::search(int data) {Node *x = root;while (x != NIL) {if (data < x->data) {x = x->left;} else if (data > x->data) {x = x->right;} else {break;}}return x;
}
伪代码
ITERATIVE-TREE-SEARCH(x, k)while x != NIL and k != x.keyif k < x.keyx = x.leftelsex = rightreturn x
实现代码
/*
author : eclipse
email : eclipsecs@qq.com
time : Sun Jul 12 19:25:40 2020
*/
#include<bits/stdc++.h>
using namespace std;struct Node {int data;Node *left;Node *right;Node *parent;bool color;Node(int value, Node *leftChild, Node *rightChild, Node *p, bool colour) : data(value), left(leftChild), right(rightChild), parent(p), color(colour) {}
};class RedBlackTree {
private:static const bool RED = true;static const bool BLACK = false;Node *NIL;Node *root;void leftRotate(Node* x);void rightRotate(Node* x);void insertFixup(Node* z);void insert(Node *z);void transplant(Node *u, Node *v);void remove(Node *z);Node* treeMinimum(Node *x);void deleteFixUp(Node *x);void inOrderTraverse(Node *x);Node* search(int data);
public:RedBlackTree();void insert(int data);void inOrderTraverse();void remove(int data);
};RedBlackTree::RedBlackTree() {NIL = new Node(0, NULL, NULL, NULL, BLACK);root = NIL;
}void RedBlackTree::leftRotate(Node* x) {Node *y = x->right;x->right = y->left;if (y->left != NIL) {y->left->parent = x;}y->parent = x->parent;if (x->parent == NIL) {root = y;} else if (x == x->parent->left) {x->parent->left = y;} else {x->parent->right = y;}y->left = x;x->parent = y;
}void RedBlackTree::rightRotate(Node* x) {Node *y = x->left;x->left = y->right;if (y->right != NIL) {y->right->parent = x;}y->parent = x->parent;if (x->parent == NIL) {root = y;} else if (x == x->parent->left) {x->parent->left = y;} else {x->parent->right = y;}y->right = x;x->parent = y;
}void RedBlackTree::insert(int data) {Node *x = new Node(data, NIL, NIL, NIL, RED);insert(x);
}void RedBlackTree::insert(Node* z) {Node *x = root;Node *y = NIL;while (x != NIL) {y = x;if (z->data < x->data) {x = x->left;} else {x = x->right;}}z->parent = y;if (y == NIL) {root = z;} else if (z->data < y->data) {y->left = z;} else {y->right = z;}z->left = NIL;z->right = NIL;z->color = RED;insertFixup(z);
}void RedBlackTree::insertFixup(Node* z) {while (z->parent->color == RED) {if (z->parent == z->parent->parent->left) {Node *y = z->parent->parent->right;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->right) {z = z->parent;leftRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;rightRotate(z->parent->parent);}} else {Node *y = z->parent->parent->left;if (y->color == RED) {z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;z = z->parent->parent;} else {if (z == z->parent->left) {z = z->parent;rightRotate(z);}z->parent->color = BLACK;z->parent->parent->color = RED;leftRotate(z->parent->parent);}}}root->color = BLACK;
}void RedBlackTree::transplant(Node *u, Node *v) {if (u->parent == NIL) {root = v;} else if (u == u->parent->left) {u->parent->left = v;} else {u->parent->right = v;}v->parent = u->parent;
}Node* RedBlackTree::search(int data) {Node *x = root;while (x != NIL) {if (data < x->data) {x = x->left;} else if (data > x->data) {x = x->right;} else {break;}}return x;
}void RedBlackTree::remove(int data) {Node *x = search(data);if (x != NIL) {remove(x);printf("\nRemove element %d successfully!\n", data);} else {printf("\nElement %d not exist!\n", data);}
}void RedBlackTree::remove(Node *z) {Node *y = z;Node *x = NIL;bool originalColor = y->color;if (z->left == NIL) {x = z->right;transplant(z, z->right);} else if (z->right == NIL) {x = z->left;transplant(z, z->left);} else {y = treeMinimum(z->right);originalColor = y->color;x = y->right;if (y->parent == z) {x->parent = y;} else {transplant(y, y->right);y->right = z->right;y->right->parent = y;}transplant(z, y);y->left = z->left;y->left->parent = y;y->color = z->color;}if (originalColor == BLACK) {deleteFixUp(x);}
}Node* RedBlackTree::treeMinimum(Node *x) {while (x->left != NIL) {x = x->left;}return x;
}void RedBlackTree::deleteFixUp(Node *x) {while (x != root && x->color == BLACK) {if (x == x->parent->left) {Node *w = x->parent->right;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;leftRotate(x->parent);w = x->parent->right;}if (w->left->color == BLACK && w->right->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->right->color == BLACK) {w->left->color = BLACK;w->color = RED;rightRotate(w);w = x->parent->right;}w->color = x->parent->color;x->parent->color = BLACK;w->right->color = BLACK;leftRotate(x->parent);x = root;}} else {Node *w = x->parent->left;if (w->color == RED) {w->color = BLACK;x->parent->color = RED;rightRotate(x->parent);w = x->parent->left;}if (w->right->color == BLACK && w->left->color == BLACK) {w->color = RED;x = x->parent;} else {if (w->left->color == BLACK) {w->right->color = BLACK;w->color = RED;leftRotate(w);w = x->parent->left;}w->color = x->parent->color;x->parent->color = BLACK;w->left->color = BLACK;rightRotate(x->parent);x = root;}}}x->color = BLACK;
}void RedBlackTree::inOrderTraverse() {inOrderTraverse(root);
}void RedBlackTree::inOrderTraverse(Node *x) {if (x == NIL) {return;}inOrderTraverse(x->left);printf("%d ", x->data);inOrderTraverse(x->right);
}int main(int argc, char const *argv[]) {RedBlackTree *redBlackTree = new RedBlackTree();int N;scanf("%d", &N);for (int i = 0; i < N; i++) {int data;scanf("%d", &data);redBlackTree->insert(data);}redBlackTree->inOrderTraverse();redBlackTree->remove(1);redBlackTree->remove(2);redBlackTree->remove(3);redBlackTree->remove(4);redBlackTree->inOrderTraverse();return 0;
}
测试数据
10
1 2 3 12312 3213 4 23 45 90 89
测试结果
1 2 3 4 23 45 89 90 3213 12312
Remove element 1 successfully!Remove element 2 successfully!Remove element 3 successfully!Remove element 4 successfully!
23 45 89 90 3213 12312
鸣谢
算法导论
最后
- 上述伪代码和图解来自算法导论
- 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
发布评论