TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

红黑树

参考

漫画:什么是红黑树?

wikipedia

在线测试

Red Black Tree

动机

二叉搜索树(也叫二叉查找树,二叉排序树)利用二分法的思想,使得查找效率很高。最大查找次数是树的高度。但由于不平衡的原因,某些情况下,树的高度很高,查找近乎单链表遍历。AVL/红黑树就是为了均衡这种情况,让二叉搜索树变得稳定,可靠

不平衡的二叉树.png


性质

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

1 节点是红色或黑色。

2 根是黑色

3 所有叶子都是黑色(叶子是NIL节点)

4 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

5 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点

红黑树.png


变换规则

插入的节点是红色节点(如果设为黑色,就会导致根到叶子的路径上有一条路上,多一个额外的黑节点,这个是很难调整的。但是设为红色节点后,可能会导致出现两个连续红色节点的冲突,那么可以通过颜色调换(color flips)和树旋转来调整。)

1.变颜色的情况:当前节点的父节点是红色,且它的叔叔节点也是红色.

  • 把父节点设为黑色
  • 把叔叔节点设为黑色
  • 把祖父节点设为红色
  • 把当前结点指向祖父结点

2.左旋:当前节点的父节点是红色,叔叔节点是黑色。且当前的节点是右子树。

左旋以父节点作为左旋

左旋.gif

3.右旋:当前节点的父节点是红色,叔叔节点是黑色,且当前的节点是左子树。右旋

  • 把父节点变为黑色
  • 把祖父节点变为红色
  • 以祖父节点旋转

右旋.gif

实践

before

insert_0.png

insert 1

in_1.gif

after

in_1_new.png


before

in_7_old.png

insert 7

in_7.gif

after

in_7_new.png


before

in_6_old.png

insert 6 step1

in_6_1.gif

in_6_step1.png

insert 6 step2

in_6_2.gif

in_6_step2.png

insert 6 step3

in_6_3.gif

endding

in_6_step3.png

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#define RED 	BOOL_FLASE
#define BLACK BOOL_TRUE

class Node
{
int date;
bool color;
Node *left;
Node *right;
Node *parent;
Node *root;

public:

Node(int &date)
{
this->date = data;
}

//左旋以父节点作为左旋
void LeftRotation(Node *e)
{
Node *s = e->right;

if (e->parent == NULL) //e = root
root = s;
else if (e->parent->left = e) // e is left
e->parent->left = s;
else
e->parent->right = s;// e is right

if (s->left != NULL)
s->left->parent = e;

s->parent = e->parent;
e->parent = s;

e->right = s->left;
s->left = e;

}

//把父节点变为黑色
//把祖父节点变为红色
//以祖父节点旋转
//前两步在其他函数实现
void RightRotation(Node *s)
{
Node *e = s->left;

if (s->parent == NULL)
root = e;
else if (s->parent->left == s)
s->parent->left = e;
else if (s->parent->right == s)
s->parent->right = e;

if (e->right != NULL)
e->right->parent = s;

e->parent = s->parent;
s->parent = e;

s->left = e->right;
e->right = s;

}

//红黑树插入 递归
void InsertRBT(Node *root, int data)
{
//this->root 默认不为空
if (data > root->data)
{
if (root->right == NULL)
{
root->right = new Node(data);
root->right.color = RED;
}
else
InsertRBT(root->right, data);
}
else
{
if (root->left == NULL)
{
root->left = new Node(data);
root->right.color = RED;
}
else
InsertRBT(root->left, data);
}

InsertRBTFixedUp();

}

//红黑树插入 loop
void InsertRBT(Node *root, int data)
{
//this->root 默认不为空

Node *x = this->root;
Node *y = NULL;
Node *n = new Node(data);
n.color = RED;

while (x)
{
y = x;

if (data > x->data)
x = x->right;
else
x = x->left;

}

if (!y)
this->root = Node;
else if (date > y->date)
y->right = n;
else
y->left = n;

InsertRBTFixedUp();

}

//插入修正函数
InsertRBTFixedUp(Node *c)
{
//parent is black, is ok
while (c->parent->color == RED)
{
//(uncle is left, and red) or (uncle is right, and red)
if (c->parent->parent->left->color == RED && c->parent->parent->right->color == RED)
{
//变色
//把父节点设为黑色
//把叔叔节点设为黑色
//把祖父节点设为红色
//把当前结点指向祖父结点
c->parent->parent->right->color = BLACK;
c->parent->parent->left->color = BLACK;
c->parent->parent->color = RED;
c = c->parent->parent;
}
else if (c->parent->parent->left->color == BLACK || c->parent->parent->right->color == BLACK)
{
//旋转
//右旋
if (c == c->parent->left)
{
//把父节点变为黑色
//把祖父节点变为红色
//以祖父节点旋转
c->parent->color = BLACK;
c->parent->parent = RED;
RightRotation(c->parent->parent);
}
//左旋
else
{
//左旋以父节点作为左旋
LeftRotation(c->parent);
}
}
}

root->color = BLACK;
}

//todo: del
void DeleteRBT(Node *root, int data)
{

}

}

ending

76887678_p0_master1200.jpg

----------- ending -----------