이진탐색트리의 일종.
균형 잡힌 트리 : 높이가 O(logn)
Search, Insert, Delete 연산을 최악의 경우에도 O(logn)
시간복잡도 : O(1)
이진탐색트리의 특성을 유지
시간복잡도: O(1)
Left-Rotate(T, x) // x를 기준으로, y와 left rotate
{
y = right[x];
// x와 b를 연결한다.
// 1. y의 왼쪽자식 (b)를 x의 오른쪽 자식으로 만든다.
right[x] = left[y];
// 2. b를 x의 오른쯕 자식으로 만든다.
parent[ left[y] ] = x;
// x의 부모노드를 y의 부모노드로 만든다.
parent[y] = parent[x];
// x의 부모를 y와 연결
// x가 root일 경우, y가 root가 된다.
if (parent[x] == NIL[T])
root[T] = y;
else if (x == left[ parent[x] ])
left[ parent[x] ] = y;
else
right[ parent[x] ] = y;
// x와 y의 연결
left[y] = x;
parent[x] = y;
}
RB-Insert(T, z)
{
x = NIL[T];
y = Root[T];
while (x)
{
y = x;
if (key[z] < key[x])
x = left[x];
else
x = right[x];
}
parent[z] = y;
if (y == NIL[T])
Root[T] = z;
else if (key[z] < key[y])
left[y] = z;
else
right[y] = z;
left[z] = NIL[T];
right[z] = NIL[Y];
color[z] = RED;
RB-Insert-Fixup(T, z);
}
위의 insert함수에서 RB-Insert-Fixup이 나오기전까지
이진탐색트리의 insert와 같다.
하지만 그대로 끝낸다면, 위반될수있는 조건들이 있다.
시간복잡도: O(logn)
늘 존재한다. 왜냐하면, z의 부모노드가 red이므로, root노드가 아니기때문!
그렇기때문에, z의 할아버지노드가 있다는 가정하에 RB-Insert-Fixup을 만든다.
고려해야할 케이스는 총 6가지이다.
z노드가 z노드의 할아버지 노드의 왼쪽에 위치한노드일때, 3가지
z노드가 z노드의 할아버지 노드의 오른쪽에 위치한노드일때, 3가지
따라서, 1,2,3의 케이스는 4,5,6의 케이스와 대칭관계이다.
RB_Insert-Fixup(T, z)
{
while (parent[z] && color[ parent[z] ] == RED) // 부모와 자식이 red로 연속되는동안
{
if (parent[z] == left[ parent[ parent[z] ] ])// 할버지노드의 왼쪽일때
{
y = right[ parent[ parent[z] ] ]; // y는 z의 삼촌노드
if (color[y] == RED) // CASE1 : 삼촌노드가 red인경우
{
// z도 red, z의 부모도 red, 삼촌노드도 red, 할아버지노드는 black
color[ parent[z] ] = BLACK;
color[y] = BLACK;
color[ parent[ parent[z] ] = RED;
}
else // CASE2, CASE3: 삼촌노드가 black인 경우
{
// CASE2 : z가 부모의 오른쪽 자식일때
if (z == right[ parent[z] ])
{
z = parent[z];
Left_Rotate(T, z);
}
// CASE3 : z가 부모의 왼쪽 자식일때
color[ parent[z] ] = BLACK;
color[ parent[ parent[z] ] ] = RED;
Right_Rotate(T, parent[ parent[z] ]);
}
}
else
// 대칭으로, CASE4, CASE5, CASE6의 경우
}
// CASE1을 반복하다가 빠져나온 경우를 고려
// 루트가 red인 경우를 고려
color[ root[T] ] = BLACK;
}
보통 BST에서 처럼 delete를 한다.
실제로 삭제된 노드 y가 red였으면 종료.
y가 black이었을경우, RB_Delete_Fixup호출
RB_Delete(T, z)
{
// z의 자식이없거나, 1개일때
if (left[z] == NIL[T] || right[z] == NIL[T])
y = z;
else // z의 자식이 2개일때
y = Tree_Successor(z); // 무조건 최대 자식이 1
// x는 y의 자식노드
if (left[y] != NIL[T])
x = left[y];
else
x = right[y];
// 부모연결
parent[x] = parent[y];
// y가 root일때
if (parent[y] == NIL[T])
root[T] = x;
else if (y == left[ parent[x] ])
left[ parent[y] ] = x;
else
right[ parent[y] ] = x;
// z의 successor를 삭제한 경우
if (y != z)
key[z] = key[y]; // 데이터 카피
// 삭제했던 노드가 black이었다면!
if (color[y] == BLACK)
RB_Delete_Fixup(T, x);
return y;
}
위의 delete함수에서 RB-Delete-Fixup이 나오기전까지
이진탐색트리의 delete와 같다.
하지만 그대로 끝낸다면, 위반될수있는 조건들이 있다.
RB_Delte_Fixup에서의 인자는 z가 아닌 x이다.
시간복잡도: O(logn)
고려해야할 케이스는 총 8가지이다.
x노드가 부모의 왼쪽자식일 경우 4가지
x노드가 부모의 오른쪽자식일 경우 4가지
따라서, 1,2,3,4의 케이스는 5,6,7,8의 케이스와 대칭관계이다.
// x는 원래삭제했던, y의 자식노드. y의 자리를 차지하고있는 노드
RB_Delete_Fixup(T, x)
{
// x가 red라면, black으로 변환후 종료
while (x != root[T] && color[x] == BLACK)
{
if (x == left[ parent[x] ])
{
// w는 x의 형제노드
w = rignt[ parent[x] ];
// CASE1
if (color[w] == RED)
{
color[w] = BLACK;
Left_Rotate[T, p[x]];
w = right[ parent[x] ];
}
// CASE2, w의 자식이 둘다 black노드인 경우
if (color[ left[w] ] == BLACK && color[ right[w] ] == BLACK)
{
color[w] = RED;
x = parent[x];
} // CASE3, CASE4
else
{
// CASE3, w의 오른쪽자식이 black인 경우, x는 doule black상태
if (color[ right[w] ] == BLACK)
{
color[ left[w] ] = BLACK;
color[w] = RED;
Right_Rotate(T, w);
}
// CASE4 : x의 double black을 나눠준다.
color[w] = color[ parent[x] ];
color[ parent[x] ] = BLACK;
color[ right[w] ] = BLACK;
Left_Rotate(T, parent[x]);
// 해결후, while문을 빠져나가기위해서
x = root[T];
}
}
else if (x == right[ parent[x] ])
{
대칭적상황
}
}
color[x] = black;
}