红黑树在二叉搜索树的基础上建立,每个点新增颜色与父亲,以颜色关系达到左右子树的相对平衡
结构
相比二叉树,多了父指针以及颜色的变量。
typedef struct node {
int nValue;
struct node* left;
struct node* right;
struct node* father;
int color;
}*binarytree, Binarytree;
红黑树的性质:
- 每个结点不是红色的就是黑色的。
- 根是黑色的。
- 终端结点会被认为是黑色的。
- 不允许有两个红色结点为父子关系。
- 从任意结点向下出发,所经历的黑结点数目相同。
- 不会有某一条路径的长度大于其他路径的二倍。
红黑树的前置知识:左右旋
按照BST树(二叉搜索树)的规则对某一结点进行改造,以调节平衡。
左旋用于处理由右的右引起的不平衡。
右旋用于处理由左的左引起的不平衡。
右旋图示:
左旋同理。
左旋代码:
void left_rotate(binarytree now) {
binarytree x = now->father;
binarytree a = now;
binarytree b = a->right;
binarytree e = b == nullptr ? nullptr : b->left;
if (x != nullptr) {
if (x->right == a) x->right = b;
if (x->left == a) x->left = b;
}
if(b) b->father = x;
a->right = e;
if(b) b->left = a;
if (e != nullptr) e->father = a;
a->father = b;
}
右旋代码:
void right_rotate(binarytree now) {
binarytree x = now->father;
binarytree a = now;
binarytree b = a->left;
binarytree e = b == nullptr ? nullptr : b->right;
if (x != nullptr) {
if (x->left == a) x->left = b;
if (x->right == a) x->right = b;
}
if(b) b->father = x;
a->left = e;
if (b) b->right = a;
if (e != nullptr) e->father = a;
a->father = b;
}
红黑树的添加结点
当一个新结点被添加时,我们先认为他是红色的。再进行旋转、变色操作。
注意,添加位置按照BST(二叉搜索树)的规则进行添加。
规则如下:令新节点为Z
- 当根节点为空时,Z成为根节点。
- 如果他的父亲是黑色的,结束 。
- 如果他的父亲是红色的,且他的叔叔也是红色的,那么,父亲、叔叔变黑,爷爷变红,将爷爷作为新的Z,重新讨论。
- 如果他的父亲为红且叔叔为黑,父亲是爷爷的左孩子,且Z是父亲的右孩子,以父亲为旋转点左旋,父亲成为新的Z,并继续判断其是否符合情况5。
- 如果他的父亲为红且叔叔为黑,父亲是爷爷的左孩子,且Z是父亲的左孩子,爷爷变红,以爷爷为旋转点右旋。
- 如果他的父亲为红且叔叔为黑,父亲是爷爷的右孩子,且Z是父亲的左孩子,以父亲为旋转点右旋,父亲成为新的Z,并继续判断其是否符合情况7。
- 如果他的父亲为红且叔叔为黑,父亲是爷爷的右孩子,且Z是父亲的右孩子,爷爷变红,以爷爷为旋转点左旋。
依照如上规则,进行创建。
如上规则对照图示:
代码:
红黑树的添加结点 / 创建一颗红黑树
binarytree create_rbt(int a[], int len) {
binarytree root = (binarytree)malloc(sizeof(Binarytree));
root->nValue = a[0];
root->left = nullptr;
root->right = nullptr;
root->color = Black;
root->father = nullptr;
binarytree now;
bool f = false;
for (int i = 1; i < len; i++) {
now = root;
f = false;
while (!f) {
if (a[i] > now->nValue) {
if (now->right == nullptr) {
now->right = (binarytree)malloc(sizeof(Binarytree));
now->right->nValue = a[i];
now->right->left = nullptr;
now->right->right = nullptr;
now->right->father = now;
now = now->right;
f = true;
}
else now = now->right;
}
else {
if (now->left == nullptr) {
now->left = (binarytree)malloc(sizeof(Binarytree));
now->left->nValue = a[i];
now->left->left = nullptr;
now->left->right = nullptr;
now->left->father = now;
now = now->left;
f = true;
}
else now = now->left;
}
}
now->color = Red;
while (now != nullptr) {
if (now->father == nullptr) { // 1
printf("1: \n");
now->color = Black;
now = nullptr;
continue;
}
if (now->father->color == Black) {// 2
printf("2: \n");
now->color = Red;
now = nullptr;
continue;
}
trav_front(root);
printf("\n");
binarytree tf = now->father;
binarytree ta = (tf == tf->father->left) ? tf->father->right : tf->father->left;
binarytree tg = now->father->father;
printf("now = %d f = %d a = %d g = %d\n", now ? now->nValue : -1, tf ? tf->nValue : -1, ta ? ta->nValue : -1, tg ? tg->nValue : -1);
if(ta) printf("%d-----%d\n", ta->nValue, ta->color);
if (ta != nullptr && ta->color == Red) { // 3
printf("3: \n");
tf->color = Black;
ta->color = Black;
tg->color = Red;
now = tg;
continue;
}
if (tf != nullptr && tf == tg->left && now == tf->right) { // 4
printf("4: \n");
now = tf;
left_rotate(now);
continue;
}
if (tf != nullptr && tf == tg->left && now == tf->left) { // 5
printf("5: \n");
tf->color = Black;
tg->color = Red;
if (tg->father == nullptr) {
root = tf;
}
right_rotate(tg);
now = nullptr;
continue;
}
if (tf != nullptr && tf == tg->right && now == tf->left) { // 6
printf("6: \n");
printf("now = %d f = %d a = %d g = %d\n", now ? now->nValue : -1, tf ? tf->nValue : -1, ta ? ta->nValue : -1, tg ? tg->nValue : -1);
now = tf;
left_rotate(now);
continue;
}
if (tf != nullptr && tf == tg->right && now == tf->right) { // 7
printf("7: \n");
tf->color = Black;
tg->color = Red;
if (tg->father == nullptr) {
root = tf;
}
right_rotate(tg);
now = nullptr;
continue;
}
}
}
root->father = nullptr;
get_bstfa(root);
return root;
}