红黑树说难不难,说简单不简单,我去看别人写的红黑树教学,是真的看不懂,于是自己想办法,实现了。
红黑树性质:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
插入:
插入的节点是红色节点,当插入节点的父亲节点是红色时,把父亲的颜色改为黑色。
删除:
先找到删除的目标节点,如果它没有儿子,或只有一个儿子,就地删除它,
否则递归寻找它的前驱,用前驱替代目标节点,删除前驱。
修正:
将插入,删除节点,引发的违背红黑树性质的行为,全部归为黑高不相等来进行黑高修正。
大致可分为五种情况,以较高子树作为基础先判断:
(以下以B代表黑色节点,R代表红色节点,同侧是指都是在一个节点的右边(或左边)的父亲和儿子节点)
1.它是B | 1.1父同侧的儿子是B | 1.1.1另一侧儿子是B |
1.1.2另一侧儿子是R | ||
1.2父同侧儿子是R |
| |
2.它是R | 2.1兄弟是B |
|
2.2兄弟是R |
|
- 1.1.1 情况,B -> (B, B),改为R->(B,B)即可,如果父亲也是R,则改父亲为B。
- 1.1.2 情况,B -> (R, B) ,向父亲方向旋转,然后酌情考虑一些变色操作即可平衡。
- 1.2 情况,B -> (?, R) ,想方设法将R节点上升作为子树的根节点(两次旋转),然后酌情考虑一些变色操作即可平 衡。
- 2.1 情况,R - B,向父亲方向旋转,然后交换父亲R,和另一个兄弟B的颜色,然后递归再去处理兄弟B的平衡(转化 为前3种情况)。
- 2.2 情况,R - R,把兄弟R改为B,即可平衡。
不画图出来推敲是不可能理解的,
高子树是左孩子右孩子都一样,
以上五种情况,只有第一种情况可能需要不断向上递归处理,其余情况均可在几次旋转之内操作达到平衡。
#include <iostream>
#include <cstdio>
#define max(a, b) (a > b? a: b)
using namespace std;
enum Color {red, black};
class Tree {
public:
Color color;
int num, num2, value, bHeight;
//num当前节点元素个数, num2当前子树元素个数
Tree *lChild, *rChild;
};
Tree *T, *NIL;
//NIL哨兵节点
inline void updateNode(Tree *th) {
if (th != NIL) {
th->num2 = th->lChild->num2 + th->rChild->num2 + th->num;
th->bHeight = max(th->lChild->bHeight, th->rChild->bHeight) + (th->color == black);
}
}
//旋转,op = true右旋, op = false左旋
inline void rTurn(Tree *&th, bool op = true) {
Tree *q = th;
if (op) {
th = th->lChild;
q->lChild = th->rChild;
th->rChild = q;
} else {
th = th->rChild;
q->rChild = th->lChild;
th->lChild = q;
}
}
void balance(Tree *par, Tree *&th) {
if (th != NIL) {
if (th->lChild->bHeight != th->rChild->bHeight) {
bool op = th->lChild->bHeight > th->rChild->bHeight;
Tree *&th1 = op? th->lChild: th->rChild;
Tree *&th3 = op? th1->rChild: th1->lChild;
if (th1->color == black) {
if (th3->color == black) {
Tree *th4 = op? th1->lChild: th1->rChild;
if (th4->color == black) {
//1.B->(B, B)
th1->color = red;
if (th->color == red) {
th->color = black;
}
} else {
//2.B->(R, B)
rTurn(th, op);
if ((op? th->rChild: th->lChild)->color == black) {
th4->color = black;
}
}
} else {
//3.B->(?, R)
rTurn(th1, !op);
rTurn(th, op);
Tree *q = op? th->rChild: th->lChild;
if (q->color == red) {
q->color = black;
if (par == NIL) {
th->color = black;
}
} else {
th->color = black;
}
}
} else {
Tree *&th2 = op? th->rChild: th->lChild;
if (th2->color == black) {
//4.R-B
rTurn(th, op);
th->color = black;
(op? th->rChild: th->lChild)->color = red;
balance(th, op? th->rChild: th->lChild);
} else {
//5.R-R
th2->color = black;
}
}
}
if (th->lChild != NIL) updateNode(th->lChild);
if (th->rChild != NIL) updateNode(th->rChild);
updateNode(th);
}
}
void insertNode(Tree *&th, int value, Tree *par = NIL) {
if (th == NIL) {
Tree *q = new Tree;
q->num = q->num2 = 1;
q->value = value;
q->lChild = q->rChild = NIL;
q->bHeight = 1;
q->color = par == NIL? black: red;
if (par->color == red) {
par->color = black;
++par->bHeight;
}
th = q;
} else if (th->value == value) {
++th->num;
++th->num2;
} else {
insertNode(value < th->value? th->lChild: th->rChild, value, th);
}
balance(par, th);
}
void deleteNode(Tree *&th, int value, Tree *&par = NIL, Tree *q = NULL) {
if (q == NULL) {
if (th == NIL) {
return ;
} else if (th->value == value){
if (th->num > 1) {
--th->num;
--th->num2;
} else if (th->lChild == NIL || th->rChild == NIL){
Tree *p = th;
th = th->lChild == NIL? th->rChild: th->lChild;
delete p;
} else {
deleteNode(th->lChild, value, th, th);
}
} else {
deleteNode(value < th->value? th->lChild: th->rChild, value, th);
}
} else {
if (th == NIL) {
q->num = par->num;
q->value = par->value;
Tree *p = par;
par = par->lChild;
delete p;
} else {
deleteNode(th->rChild, value, th, q);
}
}
balance(par, th);
}
int getRank(Tree *th, int value) {
if (th == NIL){
return 0;
} else if (th->value < value){
return th->lChild->num2 + th->num + getRank(th->rChild, value);
} else {
return getRank(th->lChild, value);
}
}
int getSa(Tree *th, int sa) {
if (th == NIL){
return -1;
} else{
int lower_sa = th->lChild->num2 + 1;
int upper_sa = lower_sa + th->num;
if (sa >= lower_sa && sa < upper_sa) {
return th->value;
} else if (sa < lower_sa) {
return getSa(th->lChild, sa);
} else {
return getSa(th->rChild, sa - upper_sa + 1);
}
}
}
int getPre(Tree *th, int value) {
if (th == NIL) {
return -1 << 30;
} else if (th->value < value) {
int x = getPre(th->rChild, value);
return (x != -1 << 30)? x: th->value;
} else {
return getPre(th->lChild, value);
}
}
int getSuf(Tree *th, int value) {
if (th == NIL) {
return 1 << 30;
} else if (th->value > value) {
int x = getSuf(th->lChild, value);
return (x != 1 << 30)? x: th->value;
} else {
return getSuf(th->rChild, value);
}
}
int main()
{
NIL = new Tree;
NIL->num = NIL->num2 = 0;
NIL->color = black;
NIL->bHeight = 0;
T = NIL;
int n, opt, x;
scanf("%d", &n);
int i = 0;
for(i = 0; i < n; i++) {
scanf("%d%d", &opt, &x);
switch (opt) {
case 1:insertNode(T, x);break;
case 2:deleteNode(T, x);break;
case 3:printf("%d\n", getRank(T, x) + 1);break;
case 4:printf("%d\n", getSa(T, x));break;
case 5:printf("%d\n", getPre(T, x));break;
case 6:printf("%d\n", getSuf(T, x));break;
}
}
return 0;
}
写完插入,删除,查找排名,前驱后继等,也有210行这种了,也不简单了。