삽입/삭제시 #2,#4,#5 속성을 위반함. 이들을 해결하기 위해서 구조를 바꾸면, 자연스럽게 균형이 잡히게 된다.
삽입노드는 무조건 RED인 이유 -> 삽입 후에도 #5 속성을 만족하기 위해서
삽입 후 #2, #4 속성을 위반할 경우가 발생하므로, 다음의 알고리즘 수행을 수행해서 속성 위반을 해결
while (부모가 RED) {
CASE 1. if 부모/삼촌 == RED이면, 부모/삼촌 모두 BLACK으로 바꾸고, 할아버지를 RED로 변경 할아버지에서 다시 시작 // CASE 2/3. 삼촌 == BLACK else { // CASE 2. if 할아버지/부모/자신 꺾인 상태 회전해서 부모/자신을 펴준다. CASE 3 상태가 됨 // CASE 3. 할아버지/부모/자신 펴진 상태 부모/할아버지 서로 색바꾸기 할아버지 기준 회전 }
}
// 종료전
루트를 BLACK으로 변경
아래의 CASE 2,3은 좌우 대칭으로 동작
수평으로 배치된 두개의 레드가 있다면, 색상을 블랙으로 변경하고 부모를 레드로 바꿀 수 있다.
삭제 색 결정법
- 삭제하려는 노드의 자녀가 없거나 하나라면, 삭제 후 노드의 색은 자기자신의 색
- 삭제하려는 노드의 자녀가 둘이라면, 삭제 후 노드의 색은 삭제된 노드의 색
삭제색이 RED이면, 어떠한 속성도 위반하지 않는다
삭제색이 BLACK이면, #2, #4, #5 속성을 위반할 수 있다
#2. 루트노드는 블랙
#4. 노드가 RED면, 자녀는 BLACK (레드는 연속하면 안됨)
#5. 임의의 경로(자신을 제외)부터 자손 NIL까지 BLACK의 개수 동일
블랙이 지워졌을 때, 블랙높이가 -1 됨. #5 속성이 깨짐
해당 위치(아래의 그림에서 회색 노드)에서 #5 를 만족시키도록 조정
- 부모 - 형제 - RED자손 -> 꺾인상태 -> 형제기준 회전 -> 펴주기
- 부모 - 형제 - RED자손 -> 펴진상태 -> 부모기준 회정 -> 구부리기
while (타겟이 루트아님 && 타겟 == BLACK) {
// CASE 1.
if 형제 == RED
형제/부모 서로 색바꾸기, 부모기준 회전 (타겟이 내려가도록)
// CASE 2.
if 형제 == BLACK, 형제의 자식 둘다 블랙
형제/자신의 블랙을 부모로 올리기 -> 형제를 RED로 변경, 부모에서 다시 fixup
else {
// CASE 3.
if 형제 == BLACK, 부모/형제/(형제의 꺾인 자식) == RED
자식 RED와 형제 서로 색바꾸기, 펴지게 회전 (RED가 바깥쪽에 오게)
CASE 4가 됨
// CASE 4. 형제 == BLACK, 부모/형제/(형제의 펴진 자식) == RED
부모/형제 서로 색바꾸기
형제의(펴진 자식) = BLACK
부모기준 회전 (타겟이 내려가도록)
타겟을 루트로 설정 -> while 종료
}
}
// 종료전
타겟을 BLACK으로 변경
typedef enum { RBTREE_RED, RBTREE_BLACK } color_t;
typedef int key_t;
typedef struct node_t {
color_t color;
key_t key;
struct node_t *parent, *left, *right;
} node_t;
typedef struct {
node_t *root;
node_t *nil; // for sentinel
} rbtree;