ν‹°μŠ€ν† λ¦¬ λ·°

728x90
λ°˜μ‘ν˜•
이진 탐색 트리λ₯Ό κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄, ꡬ글에 μ—¬λŸ¬ μ½”λ“œλ“€μ„ λ³΄μ•˜μ§€λ§Œ, 데이터 νƒ€μž…μ— 상관없이 μ‚¬μš©ν•  수 μžˆλŠ” μ½”λ“œλŠ” μ—†μ—ˆλ‹€. 이에 이진 검색 트리의 λ™μž‘ μ›λ¦¬λ‚˜ μ΄ν•΄λ³΄λ‹€λŠ”, κ΅¬ν˜„μ„ μ€‘μ μœΌλ‘œ 글을 μ •λ¦¬ν•΄λ³΄κ³ μž ν•œλ‹€.

 

BST?

 

Binary search tree - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Data structure in tree form sorted for fast lookup A binary search tree of size 9 and depth 3, with 8 at the root. The leaves are not drawn. In computer science, a binary search tree (

en.wikipedia.org

 μ•„μ£Ό κ°„λž΅ν•˜κ²Œ `BST(Binary Search Tree)`에 λŒ€ν•΄ μ„€λͺ…ν•˜μžλ©΄, λΆ€λͺ¨ λ…Έλ“œ(Parent Node)λ₯Ό κΈ°μ€€μœΌλ‘œ μ™Όμͺ½ μžμ‹(Left Child)은 λΆ€λͺ¨λ³΄λ‹€ μž‘μ€ 값이며 였λ₯Έμͺ½ μžμ‹(Right Child)은 λΆ€λͺ¨λ³΄λ‹€ 큰 값을 가진닀. `μ™„μ „μ΄μ§„νŠΈλ¦¬(Complete Binary Tree)`κ°€ 될 경우 νƒμƒ‰μ˜ νš¨μœ¨μ„±μ„ 높일 수 μžˆλŠ” μžλ£Œκ΅¬μ‘°μ΄λ‹€.

 

μ½”λ“œ

header

#ifndef BST_H
#define BST_H

typedef struct node {
	struct node *left;
	struct node *right;

	char data[0];
} node_t;

typedef struct binary_tree {
	node_t *root;
	int count;
} bst_t;

bst_t *init_bst();
void free_bst(bst_t *);
void ins_bst(bst_t *, const void *, const void *, int, int (*)(const void *, const void *));
void del_bst(bst_t *, const void *, int, int (*)(const void *, const void *));
void *find_data_in_bst(bst_t *, const void *, int (*)(const void *, const void *));
void list_bst(bst_t *, void (*)(const void *));
#endif

 νŠΈλ¦¬μ˜ 각 λ…Έλ“œλ₯Ό λ‚˜νƒ€λ‚΄λŠ” ꡬ쑰체인 `node_t`λΌλŠ” κ΅¬μ‘°μ²΄λ§ŒμœΌλ‘œλ„ κΈ°λŠ₯을 κ΅¬ν˜„ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ root λ…Έλ“œλ₯Ό ν¬μΈνŒ…ν•˜λŠ” `bst_t` ꡬ쑰체λ₯Ό 톡해, 보닀 νŽΈλ¦¬ν•˜κ²Œ μ‚¬μš©ν•  수 있고 `count`λ₯Ό 톡해 ν˜„μž¬ λ…Έλ“œμ˜ 수λ₯Ό 확인할 수 μžˆλ‹€.

 

init

bst_t *init_bst()
{
    bst_t *bst = (bst_t *)malloc(sizeof(bst_t));

    if (bst == NULL) {
        //error logging.
        return NULL;
    }

    bst->root = NULL;
    bst->count = 0;

    return bst;
}

 λ…Έλ“œλ“€μ„ 관리할 `bst_t` κ΅¬μ‘°μ²΄λŠ” μœ„μ™€ 같이 μ΄ˆκΈ°ν™” ν•  수 μžˆλ‹€.

 

free

static void free_node(node_t *node)
{
    if (node != NULL) {
        free_node(node->left);
        free_node(node->right);
        free(node);
    }
}

void free_bst(bst_t *bst)
{
    if (bst->root == NULL)
        return;

    free_node(bst->root);
    free(bst);
}

 `init`μ™€λŠ” 달리 `free`μ—μ„œλŠ” λͺ¨λ“  λ…Έλ“œλ₯Ό μˆœνšŒν•˜λ©΄μ„œ ν•΄μ œν•˜μ—¬μ•Ό ν•œλ‹€.

 

insert

static node_t *init_node(const void *data, int data_size)
{
    node_t *node= (node_t *)malloc(sizeof(node_t) + data_size);

    if (node == NULL) {
        // error logging.
        return NULL;
    }

    node->left = node->right = NULL;
    memcpy(node->data, data, data_size);

    return node;
}

void ins_bst(bst_t *bst, const void *data, const void *key, 
            int data_size, int (*cmp_node)(const void *, const void *))
{
    node_t *parent = NULL;
    node_t *temp = NULL;
    
    temp = bst->root;

    while (temp) {
        if (cmp_node(temp->data, key) == 0)
            return;

        parent = temp;
        
        if (cmp_node(parent->data, key) > 0)
            temp = parent->left;
        else
            temp = parent->right;
    }

    node_t *new = init_node(data, data_size);

    if (parent) {
        if (cmp_node(parent->data, key) > 0)
            parent->left = new;
        else
            parent->right = new;
    } else
        bst->root = new;

    bst->count++;
}

 ν˜„μž¬ μ‚½μž…ν•˜κ³ μž ν•˜λŠ” 값에 따라, μ–΄λ–€ λ…Έλ“œλ₯Ό `parent`둜 ν•˜μ—¬μ•Ό ν•˜λŠ”μ§€ νƒμƒ‰ν•œλ‹€. 결과에 따라 νƒμƒ‰ν•œ `parent`의 `child`κ°€ λœλ‹€. λ§Œμ•½ `parent`λ₯Ό 찾지 λͺ»ν•œλ‹€λ©΄, `root`κ°€ μ—†λŠ” μƒνƒœμ΄λ‹€.

 

delete

void del_bst(bst_t *bst, const void *key, int data_size, int (*cmp_node)(const void *, const void *))
{
    node_t *parent = NULL;
    node_t *child = NULL;
    node_t *temp = NULL;
    
    if (bst->root == NULL)
        return;

    temp = bst->root;

    while (temp != NULL && cmp_node(temp->data, key) != 0) {
        parent = temp;
        temp = (cmp_node(temp->data, key) > 0) ? parent->left : parent->right;
    }

    if (temp == NULL)
        return;

    if (temp->left == NULL && temp->right == NULL) {
        if (parent) {
            if (parent->left == temp)
                parent->left = NULL;
            else
                parent->right = NULL;
        } else 
            bst->root = NULL;
    } else if (temp->left == NULL || temp->right == NULL) {
        child = (temp->left != NULL) ? temp->left : temp->right;

        if (parent) {
            if (parent->left == temp)
                parent->left = child;
            else
                parent->right = child;
        } else
            bst->root = child;
    } else {
        // succesor parent
        node_t *s_parent = temp;
        node_t *succesor = temp->right;

        while (succesor->left != NULL) {
            s_parent = succesor;
            succesor = succesor->left;
        }

        if (s_parent->left == succesor)
            s_parent->left = succesor->right;
        else
            s_parent->right = succesor->right;

        memcpy(temp->data, succesor->data, data_size);
        temp = succesor;
    }

    bst->count--;
    free(temp);
}

 `delete`λŠ” λ‹€λ₯Έ κΈ°λŠ₯듀에 λΉ„ν•΄ λ‹€μ†Œ λ³΅μž‘ν•˜λ‹€. μ΄λŠ” 1) μžμ‹μ΄ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 경우, 2) μžμ‹μ΄ ν•˜λ‚˜ μ‘΄μž¬ν•˜λŠ” 경우, 3) μžμ‹μ΄ λ‘˜ μ‘΄μž¬ν•˜λŠ” κ²½μš°μ— 따라 μ²˜λ¦¬ν•΄μ£Όμ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 즉 μœ„μ˜ μ½”λ“œλŠ” μ‚­μ œν•˜κ³ μž ν•˜λŠ” λ…Έλ“œμ˜ μœ„μΉ˜κΉŒμ§€ 탐색 ν›„, μžμ‹μ˜ 쑴재 여뢀에 따라 μ²˜λ¦¬ν•˜λŠ” 것이닀.

 

find_data

void *find_data_in_bst(bst_t *bst, const void *key, int (*cmp_node)(const void *, const void *))
{
    node_t *cur_node = bst->root;
    int diff = 0;

    while (cur_node) {
        diff = cmp_node(cur_node->data, key);

        if (diff == 0)
            return cur_node->data;
        else if (diff > 0)
            cur_node = cur_node->left;
        else
            cur_node = cur_node->right;
    }

    return NULL;
}

 `root`λΆ€ν„° 순차적으둜 νƒμƒ‰ν•˜μ—¬, 찾고자 ν•˜λŠ” 값이 μžˆλŠ”μ§€ νƒμƒ‰ν•œλ‹€.

 

μ „μ²΄μ½”λ“œ

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "bst.h"

bst_t *init_bst()
{
    bst_t *bst = (bst_t *)malloc(sizeof(bst_t));

    if (bst == NULL) {
        //error logging.
        return NULL;
    }

    bst->root = NULL;
    bst->count = 0;

    return bst;
}

static void free_node(node_t *);
void free_bst(bst_t *bst)
{
    if (bst->root == NULL)
        return;

    free_node(bst->root);
    free(bst);
}

static node_t *init_node(const void *, int);
void ins_bst(bst_t *bst, const void *data, const void *key, 
             int data_size, int (*cmp_node)(const void *, const void *))
{
    node_t *parent = NULL;
    node_t *temp = NULL;
    
    temp = bst->root;

    while (temp) {
        if (cmp_node(temp->data, key) == 0)
            return;

        parent = temp;
        
        if (cmp_node(parent->data, key) > 0)
            temp = parent->left;
        else
            temp = parent->right;
    }

    node_t *new = init_node(data, data_size);

    if (parent) {
        if (cmp_node(parent->data, key) > 0)
            parent->left = new;
        else
            parent->right = new;
    } else
        bst->root = new;

    bst->count++;
}


void del_bst(bst_t *bst, const void *key, int data_size, int (*cmp_node)(const void *, const void *))
{
    node_t *parent = NULL;
    node_t *child = NULL;
    node_t *temp = NULL;
    
    if (bst->root == NULL)
        return;

    temp = bst->root;

    while (temp != NULL && cmp_node(temp->data, key) != 0) {
        parent = temp;
        temp = (cmp_node(temp->data, key) > 0) ? parent->left : parent->right;
    }

    if (temp == NULL)
        return;

    if (temp->left == NULL && temp->right == NULL) {
        if (parent) {
            if (parent->left == temp)
                parent->left = NULL;
            else
                parent->right = NULL;
        } else 
            bst->root = NULL;
    } else if (temp->left == NULL || temp->right == NULL) {
        child = (temp->left != NULL) ? temp->left : temp->right;

        if (parent) {
            if (parent->left == temp)
                parent->left = child;
            else
                parent->right = child;
        } else
            bst->root = child;
    } else {
        // succesor parent
        node_t *s_parent = temp;
        node_t *succesor = temp->right;

        while (succesor->left != NULL) {
            s_parent = succesor;
            succesor = succesor->left;
        }

        if (s_parent->left == succesor)
            s_parent->left = succesor->right;
        else
            s_parent->right = succesor->right;

        memcpy(temp->data, succesor->data, data_size);
        temp = succesor;
    }

    bst->count--;
    free(temp);
}

void *find_data_in_bst(bst_t *bst, const void *key, int (*cmp_node)(const void *, const void *))
{
    node_t *cur_node = bst->root;
    int diff = 0;

    while (cur_node) {
        diff = cmp_node(cur_node->data, key);

        if (diff == 0)
            return cur_node->data;
        else if (diff > 0)
            cur_node = cur_node->left;
        else
            cur_node = cur_node->right;
    }

    return NULL;
}

static void search_node(node_t *, void (*)(const void *));
void list_bst(bst_t *bst, void (*print_data)(const void *))
{
    printf("cur_nodes : %d\n", bst->count);

    if (bst->root == NULL)
        return;

    search_node(bst->root, print_data);
}

/* Private functions */
static node_t *init_node(const void *data, int data_size)
{
    node_t *node= (node_t *)malloc(sizeof(node_t) + data_size);

    if (node == NULL) {
        // error logging.
        return NULL;
    }

    node->left = node->right = NULL;
    memcpy(node->data, data, data_size);

    return node;
}

static void free_node(node_t *node)
{
    if (node != NULL) {
        free_node(node->left);
        free_node(node->right);
        free(node);
    }
}

static void search_node(node_t *node, void (*print_data)(const void *))
{
    if (node != NULL) {
        search_node(node->left, print_data);
        print_data(node->data);
        search_node(node->right, print_data);
    }
}

 

ν…ŒμŠ€νŠΈ

#include "bst.h"
#include <string.h>
#include <stdio.h>

typedef struct {
    char name[32];
}info;

void init_info(info *t, const char *name)
{
    memset(t, 0, sizeof(info));
    memcpy(t->name, name, 32);
}

int cmp_name(const void *a, const void *b)
{
    return strcmp(((info *)a)->name, ((char *)b));
}

void print_data(const void *a)
{
    printf("%s\n", (char *)a);
}
int main()
{
    info temp;
    init_info(&temp, "TEST1");
    bst_t *bst = init_bst();
    ins_bst(bst, &temp, "TEST1", sizeof(info), cmp_name);

    init_info(&temp, "TEST2");
    ins_bst(bst, &temp, "TEST2", sizeof(info), cmp_name);
    list_bst(bst, print_data);
    printf("-----------\n");
    info *test = (info *)find_data_in_bst(bst, "TEST2", cmp_name);
    printf("%s\n", test->name);
    printf("-----------\n");
    del_bst(bst, "TEST2", sizeof(info), cmp_name);

    list_bst(bst, print_data);
    init_info(&temp, "TEST5");
    ins_bst(bst, &temp, "TEST5", sizeof(info), cmp_name);
    del_bst(bst, "TEST2", sizeof(info), cmp_name);
    del_bst(bst, "TEST5", sizeof(info), cmp_name);
    del_bst(bst, "TEST1", sizeof(info), cmp_name);

    list_bst(bst, print_data);

    free_bst(bst);
}

 

valgrind ν…ŒμŠ€νŠΈ 및 μ‹€ν–‰ κ²°κ³Ό

 μœ„와 같은 main 예제 μ½”λ“œλ₯Ό 톡해, κ΅¬ν˜„ν•œ `BST`의 init, insert, delete, find, search, freeκΉŒμ§€ λͺ¨λ“  κΈ°λŠ₯듀이 정상 μž‘λ™ν•œλ‹€λŠ” 것을 μ•Œ 수 μžˆλ‹€. μž¬κ·€λ₯Ό μ‚¬μš©ν•΄, 보닀 κ°„λ‹¨ν•˜κ²Œ κΈ°λŠ₯듀을 μž‘μ„±ν•  수 μžˆλ‹€. ν•˜μ§€λ§Œ λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•¨μœΌλ‘œμ¨ `BST` κ΅¬ν˜„κ³Ό 원리에 λŒ€ν•΄ 보닀 λͺ…ν™•ν•˜κ³ , μ§κ΄€μ μœΌλ‘œ 이해할 수 μžˆμ—ˆλ‹€.

 

728x90
λ°˜μ‘ν˜•
λŒ“κΈ€
κΈ€ 보관함
μ΅œκ·Όμ— 올라온 κΈ€
μ΅œκ·Όμ— 달린 λŒ“κΈ€