본문 바로가기
Coding/C

[C] RB Tree 구현

by 暻煥 2024. 2. 5.

 

rb_tree.h

/* rb_tree.h */

#ifndef _RB_TREE_H_
#define _RB_TREE_H_

#include <stdbool.h>

typedef struct rb_tree_t rb_tree_t;
typedef struct rb_node_t rb_node_t;
typedef enum rb_color_e rb_color_e;

enum rb_color_e {
    RED,
    BLACK,
};

struct rb_node_t {
    void* data;

    struct rb_node_t* left;
    struct rb_node_t* right;
    struct rb_node_t* parent;
    enum rb_color_e color;
};

struct rb_tree_t {
    struct rb_node_t* root;
    struct rb_node_t* leaf;

    /*
     * if (a > b)
     *  return true;
     * else
     *  return false;
     */
    bool (*larger_than)(void* a, void* b);

    /*
     * if (a==b)
     *  return true;
     * else 
     * return false;
     */
    bool (*equal)(void* a, void* b);
};

void rb_tree_init(rb_tree_t* tree, bool (*larger_than)(void* a, void* b), bool (*equal)(void* a, void* b));
rb_node_t* rb_exist(rb_tree_t* tree, void* data);
void rb_insert(rb_tree_t* tree, void * new_data);
bool rb_delete(rb_tree_t* tree, void* data);
void rb_destroy(rb_tree_t* tree);

void rb_for_inorder(rb_tree_t* tree, void (*probe)(void *data));
void rb_for_preorder(rb_tree_t* tree, void (*probe)(void* data));
void rb_for_postorder(rb_tree_t* tree, void (*probe)(void* data));

#endif

 

rb_tree.c

/* rb_tree.c */

#include <stdlib.h>

#include "rb_tree.h"

rb_node_t* __rb_min(rb_tree_t *tree, rb_node_t* node)
{
    while (node->left != tree->leaf)
        node = node->left;

    return node;
}

rb_node_t *rb_exist(rb_tree_t *tree, void* data)
{
    rb_node_t* x = tree->root;
    rb_node_t* p = NULL;

    if (tree->root == tree->leaf)
        return NULL;

    while (x != NULL && !tree->equal(data, x->data)) {
        p = x;

        if (tree->larger_than(p->data, data))
            x = p->left;
        else
            x = p->right;

        if (x == tree->leaf)
            return NULL;
    }

    return x;
}

static rb_node_t* alloc_rb_node(void)
{
    rb_node_t* ret;
    ret = (rb_node_t*)malloc(sizeof(rb_node_t));

    if (!ret)
        return NULL;

    ret->color = BLACK;
    ret->parent = NULL;
    ret->left = NULL;
    ret->right = NULL;

    return ret;
}

static void free_rb_node(rb_node_t *node)
{
    free(node);
}

static void rb_rotate_left(rb_tree_t *tree, rb_node_t* x)
{
    rb_node_t* y;

    y = x->right;
    x->right = y->left;

    if (y->left != tree->leaf)
        y->left->parent = x;

    y->parent = x->parent;

    if (!x->parent)
        tree->root = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;

    x->parent = y;
    y->left = x;
}

static void rb_rotate_right(rb_tree_t *tree, rb_node_t* y)
{
    rb_node_t* x;
    
    x = y->left;
    y->left = x->right;

    if (x->right != tree->leaf)
        x->right->parent = y;

    if (!y->parent)
        tree->root = x;
    else if (y == y->parent->left)
        y->parent->left = x;
    else
        y->parent->right = x;

    y->parent = x;
    x->right = y;
}

static void rb_insert_fixup(rb_tree_t *tree, rb_node_t* n)
{
    while (n != tree->root && n->parent->color == RED) {
        rb_node_t* p = n->parent;
        rb_node_t* g = p->parent;
        rb_node_t* u = (p == g->left) ? g->right : g->left;
        bool is_p_left = (p == g->left) ? true : false;

        if (u && u->color == RED) {
            n->parent->color = BLACK;
            u->color = BLACK;
            g->color = RED;
            n = g;
        } else {
            if (n == (is_p_left ? p->right : p->left)) {
                /*
                 * p==left && n==right
                 * p==right && n==left
                 */
                n = n->parent;
                if (is_p_left)
                    rb_rotate_left(tree, n);
                else
                    rb_rotate_right(tree, n);
            }

            n->parent->color = BLACK;
            g->color = RED;
            if (is_p_left)
                rb_rotate_right(tree, g);
            else
                rb_rotate_left(tree, g);
        }
    }
    tree->root->color = BLACK;
}

void rb_insert(rb_tree_t *tree, void* new_data)
{
    rb_node_t* x = tree->root;
    rb_node_t* p = NULL;
    rb_node_t* n = alloc_rb_node();

    n->color = RED;
    n->left = tree->leaf;
    n->right = tree->leaf;
    n->data = new_data;

    while (x != tree->leaf) {
        p = x;
        if (tree->larger_than(x->data, n->data))
            x = x->left;
        else
            x = x->right;
    }

    n->parent = p;
    
    if (p == NULL)
        tree->root = n;
    else if (tree->larger_than(n->data, p->data))
        p->right = n;
    else
        p->left = n;

    if (n == tree->root) {
        n->color = BLACK;
        return;
    }

    if (n->parent == tree->root)
        return;

    rb_insert_fixup(tree, n);
}

/* put 'v' to location of 'u' */
static void rb_trans_plant(rb_tree_t *tree, rb_node_t* u, rb_node_t* v)
{
    if (u == tree->root)
        tree->root = v;
    else if (u == u->parent->left)
        u->parent->left = v;
    else
        u->parent->right = v;

    v->parent = u->parent;
}


static void rb_delete_fixup(rb_tree_t *tree, rb_node_t* x)
{
    rb_node_t* b;

    while (x != tree->root && x->color == BLACK) {
        if (x == x->parent->left) {
            b = x->parent->right;

            if (b->color == RED) {
                b->color = BLACK;
                x->parent->color = RED;
                rb_rotate_left(tree, x->parent);
                b = x->parent->right;
            }

            if (b->left->color == BLACK && b->right->color == BLACK) {
                b->color = RED;
                x = x->parent;
            } else {
                if (b->right->color == BLACK) {
                    b->left->color = BLACK;
                    b->color = RED;
                    rb_rotate_right(tree, b);
                    b = x->parent->right;
                }

                b->color = x->parent->color;
                x->parent->color = BLACK;
                b->right->color = BLACK;
                rb_rotate_left(tree, x->parent);
                x = tree->root;
            }

        } else {
            b = x->parent->left;

            if (b->color == RED) {
                b->color = BLACK;
                x->parent->color = RED;
                rb_rotate_right(tree, x->parent);
                b = x->parent->left;
            }

            if (b->left->color == BLACK && b->right->color == BLACK) {
                b->color = RED;
                b = b->parent;
            } else {
                if (b->left->color == BLACK) {
                    b->right->color = BLACK;
                    b->color = RED;
                    rb_rotate_left(tree, b);
                    b = x->parent->left;
                }

                b->color = x->parent->color;
                x->parent->color = BLACK;
                b->left->color = BLACK;
                rb_rotate_right(tree, x->parent);
                x = tree->root;
            }
        }
    }
    x->color = BLACK;
    tree->root->color = BLACK;
}

bool rb_delete(rb_tree_t *tree, void *data)
{
    rb_node_t* t = rb_exist(tree, data);
    rb_node_t* x;
    rb_node_t* y;
    rb_color_e origin_corlor;

    if (!t)
        return false;

    origin_corlor = t->color;

    if (t->left == tree->leaf) {
        x = t->right;
        rb_trans_plant(tree, t, t->right);
    } else if (t->right == tree->leaf) {
        x = t->left;
        rb_trans_plant(tree, t, t->left);
    } else {
        y = __rb_min(tree, t->right);
        origin_corlor = y->color;

        /* child of y is leaf */
        x = y->right;

        if (y->parent == t)
            x->parent = y;
        else {
            rb_trans_plant(tree, y, y->right);
            y->right = t->right;
            y->right->parent = y;
        }
        rb_trans_plant(tree, t, y);
        y->left = t->left;
        y->left->parent = y;
        y->color = t->color;
    }

    free_rb_node(t);

    if (origin_corlor == BLACK) {
        rb_delete_fixup(tree, x);
    }

    return true;
}

static void __rb_destroy(rb_tree_t* tree, rb_node_t* node)
{
    if (node == tree->leaf)
        return;

    __rb_destroy(tree, node->left);
    __rb_destroy(tree, node->right);
    free(node);
}

void rb_destroy(rb_tree_t *tree)
{
    rb_node_t* node = tree->root;

    __rb_destroy(tree, node);
}

static void __rb_for_inorder(rb_tree_t* tree, rb_node_t* node, void (*probe)(void* data))
{
    if (node == tree->leaf)
        return;

    __rb_for_inorder(tree, node->left, probe);
    probe(node->data);
    __rb_for_inorder(tree, node->right, probe);
}

void rb_for_inorder(rb_tree_t *tree, void (*probe)(void* data))
{
    rb_node_t* node = tree->root;
    __rb_for_inorder(tree, node, probe);
}

static void __rb_for_preorder(rb_tree_t* tree, rb_node_t* node, void (*probe)(void* data))
{
    if (node == tree->leaf)
        return;

    probe(node->data);
    __rb_for_preorder(tree, node->left, probe);
    __rb_for_preorder(tree, node->right, probe);
}

void rb_for_preorder(rb_tree_t* tree, void (*probe)(void* data))
{
    rb_node_t* node = tree->root;
    __rb_for_preorder(tree, node, probe);
}

static void __rb_for_postorder(rb_tree_t* tree, rb_node_t* node, void (*probe)(void* data))
{
    if (node == tree->leaf)
        return;

    __rb_for_postorder(tree, node->left, probe);
    __rb_for_postorder(tree, node->right, probe);
    probe(node->data);
}

void rb_for_postorder(rb_tree_t* tree, void (*probe)(void* data))
{
    rb_node_t* node = tree->root;
    __rb_for_postorder(tree, node, probe);
}

void rb_tree_init(rb_tree_t* tree, bool (*larger_than)(void* a, void* b), bool (*equal)(void* a, void* b))
{
    tree->leaf = alloc_rb_node();
    tree->root = tree->leaf;

    tree->larger_than = larger_than;
    tree->equal = equal;
}

 

main.c

/* main.c */
#include <stdio.h>
#include <stdlib.h>

#include "rb_tree.h"

/* user defined data and operator */
struct data_t {
    int key;
};

struct data_t* alloc_data(void)
{
    return (struct data_t*)malloc(sizeof(struct data_t));
}

void free_data(void* data)
{
    free(data);
}

bool data_larger_than(void* a, void* b)
{
    if (((struct data_t *)a)->key > ((struct data_t*)b)->key)
        return true;

    return false;
}

bool data_equal(void* a, void* b)
{
    if (((struct data_t*)a)->key == ((struct data_t*)b)->key)
        return true;

    return false;
}

void data_print(void* d)
{
    struct data_t* data = (struct data_t *)d;
    printf("%d ", data->key);
}

/* main */
enum menu_e {
    INSERT = 1,
    DELETE = 2,
    PRINT_IN_ORDER = 3,
    EXIT = 99,
};

void print_main_menu(void)
{
    printf("::: MENU :::\n");
    printf("1. insert\n");
    printf("2. delete\n");
    printf("3. print(in order)\n");
    printf("------------\n");
    printf("99. exit\n");
    printf("------------\n");
}

int main()
{
    struct rb_tree_t rb_tree;
    rb_tree_init(&rb_tree, data_larger_than, data_equal);

    while (true) {
        int select;

        print_main_menu();
        scanf("%d", &select);

        switch (select)
        {
        case INSERT:
        {
            int key;
            printf("input value : ");
            scanf("%d", &key);
            struct data_t* data = alloc_data();
            if (data) {
                data->key = key;

                if (!rb_exist(&rb_tree, data))
                    rb_insert(&rb_tree, data);
                else {
                    printf("ERROR: %d alreday exist\n", key);
                    free_data(data);
                }
            } else
                printf("memory alloc fail\n");
        }
        break;
        case DELETE:
        {
            int key;
            printf("input value : ");
            scanf("%d", &key);
            struct data_t* data = alloc_data();
            if (data) {
                data->key = key;
                if (!rb_delete(&rb_tree, data))
                    printf("ERROR: %d does not exist\n", key);
                free_data(data);
            } else
                printf("memory alloc fail\n");
        }
        break;
        case PRINT_IN_ORDER:
        {
            printf("print in order : \n");
            rb_for_inorder(&rb_tree, data_print);
            printf("\n");
        }
        break;
        case EXIT:
        {
            goto out;
        }
        break;
        default:
            break;
        }
        printf("\n");
    }

out:
    rb_for_postorder(&rb_tree, free_data);
    rb_destroy(&rb_tree);

    return 0;
}

 


※ 참고

https://www.programiz.com/dsa/red-black-tree

 

Red-Black Tree

Red-Black Tree In this tutorial, you will learn what a red-black tree is. Also, you will find working examples of various operations performed on a red-black tree in C, C++, Java and Python. Red-Black tree is a self-balancing binary search tree in which ea

www.programiz.com

https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

 

Red/Black Tree Visualization

 

www.cs.usfca.edu

.

'Coding > C' 카테고리의 다른 글

[C] Priority Queue  (0) 2025.11.16
[C] Quick Sort  (0) 2025.11.15
[C] Heap의 특정 index 값 수정  (1) 2024.02.07
[C] AVL Tree  (0) 2024.02.05