[RED-BLACK TREE] Deletion

zeo·2021년 9월 9일
0

rbtree.c

#include "rbtree.h"
#include <stdlib.h>
#include <stdio.h>

//NIL 생성
node_t nil_node = {RBTREE_BLACK, 988, NULL, NULL, NULL};
node_t *NIL = &nil_node;

int rbtree_erase(rbtree *t, node_t *p) {
  // TODO: implement erase
  // node_t *temp = t -> root; // 루트 노드
  node_t *target_node = p; //삭제 대상 노드

  node_t *y = NULL; // splice 대상 y , 초기값 NULL 설정

  // target의 자식 노드가 0, 1개인 경우: splice 대상 y는 target 자신
  if (target_node -> left == NULL || target_node -> right == NULL) y = target_node;
  else y = successor(target_node);

  // 2. y의 자식 노드 x 결정
  // y가 잘려나가면 그 밑의 노드를 이어주어야 하므로
  node_t *x = NULL; //
  if (y -> left != NULL) x = y -> left;
  else x = y -> right;

  // exception case2: y가 root node인 경우
  if (y -> parent == NULL) {
    t -> root = x;
  }
  else {
    if (x == NULL) x = NIL; 

    if (y == y -> parent -> left) y -> parent -> left = x; 
    else y -> parent -> right = x; // y 연결 해제

    x -> parent = y -> parent;
  }
  
  // y가 삭제 대상이 아닐 경우, 값 복사
  if (y != target_node) {
    target_node -> key = y -> key;
  }

  //y가 black인 경우
  if (y -> color == RBTREE_BLACK) delete_fixup(t, x);
  
  free(y); //삭제 처리

  // NIL 제거
  if(NIL -> parent !=NULL) {
    if(NIL == NIL -> parent -> left) NIL -> parent -> left = NULL;
    else NIL -> parent -> right = NULL;

    NIL -> parent = NULL;
  }

  return y;
}


node_t *rbtree_min(const rbtree *t) {
  // TODO: implement find
  node_t *curr = t-> root;
  while (curr ->left != NULL) curr = curr ->left; 

  return curr;
}

node_t *successor(node_t *curr) {
  // case1: right subtree is non-empty
  if (curr->right != NULL) return rbtree_min(curr->right);
  // case2: right-subtree is empty
  node_t *temp;
  temp = curr->parent;
  // 조건을 만족할 때까지 트리를 타고 올라간다
  // 조건: curr의 조상 중 처음으로 left child가 되는 노드의 부모 노드를 찾는다
  while( temp != NULL && temp->right == curr){
      curr = temp;
      temp = temp->parent;
  }
  // check impossible cases(루트노드까지 올라간 경우)
  if (temp == NULL){
      printf("there is no successor of given node!\n");
  }
  return temp;
}


void delete_fixup(rbtree *t, node_t *x) { 
//black 노드가 빠짐으로서 생긴 불균형을 다시 맞춰주기 위한 함수

  node_t *sibling_node = NULL;
  // if (x -> parent -> left == x) sibling_node = x -> parent -> right;
  // else sibling_node = x -> parent -> left;

  // x는 항상 double black을 가리키게 됨
  while(x != NULL && x-> parent != NULL && x -> color == RBTREE_BLACK) { // x는 루트노드가 아니면서, BLACK일 때 
    if (x == x -> parent -> left) {
      sibling_node = x -> parent -> right;

        // case1) 형제노드가 red이므로, x-> parent는 무조건 black
        
        if (sibling_node -> color == RBTREE_RED) {
          x -> parent -> color = RBTREE_RED;
          sibling_node -> color = RBTREE_BLACK;
          left_rotate(t, x -> parent);
          sibling_node = x -> parent -> right; // 새로운 형제 노드 설정 (case 2, 3, 4 대입 가능 상태로 만들어줌)
        }

        // case2) x는 double black, 형제 노드 black, 형제 자식노드(오, 왼) 모두 black
        
        if (sibling_node -> left-> color == RBTREE_BLACK && sibling_node -> right -> color == RBTREE_BLACK) {
          // 형제의 왼쪽 자식, 오른쪽 자식이 black인 경우 (빈 공간에 여유가 없는 상태이므로 부모에게 전달하거나 전체 높이를 1 줄이기)
          sibling_node -> color == RBTREE_RED; 
          // x와 형제 노드 모두 black을 parent에 주기
          // x는 double black -> black / 형제 노드는 black -> red가 됨
          // parent가 기존에 red였으면 black 이 되고, black이었으면 double black이 되므로 parent를 x로 설정해서 재귀 돌려주기
          x = x -> parent;
          // NIL 제거
          if (x -> left == NIL) {
            x -> left = NULL;
            NIL -> parent = NULL;
          }
        }
        
        else {
        
          // case3) x는 double black, 형제 노드 black, 형제의 왼쪽 자식 red, 형제의 오른쪽 자식 black
          
          if (sibling_node -> right -> color == RBTREE_BLACK) {
            sibling_node -> left -> color == RBTREE_BLACK;
            sibling_node -> color == RBTREE_RED;
            right_rotate(t, sibling_node);
            sibling_node = x -> parent -> right; 
            //새로운 형제노드는 black이 되며, 새로운 형제노드의 오른쪽 자식이 red가 됨
            
            //case4와 동일한 상황이 됨
            
          }
          else {
          
          // case4) x는 double black, 형제노드 black, 형제의 왼쪽 자식 black, 형제의 오른쪽 자식 red
          
            // 빠진 자리의 인접한 노드를 가져와 채우는 것
            sibling_node -> color = x -> parent -> color;
            x -> parent -> color = RBTREE_BLACK;
            sibling_node -> right -> color = RBTREE_BLACK;
            left_rotate(t, x -> parent);
            // NIL 제거
            if (x -> parent -> left == NIL) {
              x -> parent -> left = NULL;
              NIL -> parent = NULL;
            }
          }
        }
    }

    else {
      sibling_node = x -> parent -> left;
      // case1)
      if (x -> color == RBTREE_RED) {
          sibling_node -> color = RBTREE_BLACK;
          x -> parent -> color = RBTREE_RED; // 무조건 바꾸는 경우, recolor로 바꿔서 표기할것
          right_rotate(t, x);
          sibling_node = x -> parent -> left; // 새로운 형제 노드 설정
        }

      // case2)
      if (sibling_node -> right-> color == RBTREE_BLACK && sibling_node -> left -> color ==RBTREE_BLACK) {
          // 형제의 왼쪽 자식 또는 오른쪽 자식이 black인 경우
          sibling_node -> color == RBTREE_RED;
          x = x -> parent;
          // NIL 제거
          if (x -> left == NIL) {
            x -> left = NULL;
            NIL -> parent = NULL;
          }
      }
      else {
      // case3)
        if (sibling_node -> left -> color == RBTREE_BLACK) {
          sibling_node -> right -> color == RBTREE_BLACK;
          sibling_node -> color == RBTREE_RED;
          left_rotate(t, sibling_node);
          sibling_node = x -> parent -> left;
        }
        else {
      // case4)
          sibling_node -> color = x -> parent -> color;
          x -> parent -> color = RBTREE_BLACK;
          sibling_node -> left -> color = RBTREE_BLACK;
          right_rotate(t, x -> parent);
          if (x -> parent -> right == NIL) {
              x -> parent -> right = NULL;
              NIL -> parent = NULL;
        }
      }
    }
  }
}
if (x != NULL) x -> color = RBTREE_BLACK;
}







0개의 댓글