[C] C언어로 이진트리를 구현하기 2

학원에서 배운 C로 이진트리를 구현하는 과정을 이 포스트에다가 저장한다.

파이썬에서는 클래스와 무한루프를 이용해서 이진트리를 구현하였는데, C언어에서는 무한루프를 사용하기 힘들어서

재귀함수로 구현하였다.

그리고 재귀함수를 이용하니 전위순회, 중위순회, 후위순회까지 잘 구현할 수 있었다.

그래도 근본적인 내용은 C와 파이썬 둘 다 같은 것 같다.

구현 코드


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

#pragma warning (disable : 4996)

enum treeMenu {
    TERMINATE, ADD, REMOVE, SEARCH, PRINT, MIN, MAX
};

typedef struct treeNode {
    int value;
    struct treeNode* left;
    struct treeNode* right;
}treeNode;

treeNode* addNode(treeNode* t, int data);
void _print(treeNode* t);
void terminate(treeNode* t);
treeNode* findMin(treeNode* t);
treeNode* findMax(treeNode* t);
treeNode* removeNode(treeNode* t, int data);
treeNode* searchNode(treeNode* t, int data);

int main() {
    int select, data;

    treeNode* root = NULL; // 첫 노드의 주소를 저장한다.
    treeNode* find;

    while (1) {
        system("clear");
        printf("1. add\n");
        printf("2. remove\n");
        printf("3. search\n");
        printf("4. print\n");
        printf("5. min\n");
        printf("6. max\n");
        printf("0. terminate\n");
        printf("\nselect : [ ]\b\b");
        scanf("%d", &select);
        getchar();
        switch(select) {
            case ADD:
            {   
                printf("\n정수를 입력하세요 : "); // 밖에서 받아서 입력처리하는 것이 좋음.
                scanf("%d", &data);
                root = addNode(root, data); // 최종적으로 루트의 주소를 돌려주는 형식으로 진행.
                break;
            }
            case REMOVE:
            {   
                printf("삭제할 정수 입력 : ");
                scanf("%d", &data);
                root = removeNode(root, data);
                break;
            }
            case SEARCH:
            {   
                printf("검색할 정수 입력 : ");
                scanf("%d", &data);
                getchar();
                find = searchNode(root, data);
                if (find == NULL) {
                    printf("해당한 값이 존재하지 않습니다.\n");
                    getchar();
                }
                else {
                    printf("%d값이 있습니다.\n", find->value);
                    getchar();
                }
                break;
            }
            case PRINT:
            {   
                _print(root);
                puts("");
                getchar();
                break;
            }
            case MIN:
            {   
                find = findMin(root);

                if (find == NULL) {
                    printf("tree가 구성되지 않았습니다.\n"); // tree가 구성되지 않았을 경우 NULL이 반환되므로.
                }
                else {
                    printf("\n최솟값은 %d입니다.\n", find->value);
                }

                getchar();
                break;
            }
            case MAX:
            {
                find = findMax(root);

                if (find == NULL) {
                    printf("tree가 구성되지 않았습니다.\n"); // tree가 구성되지 않았을 경우 NULL이 반환되므로.
                }
                else {
                    printf("\n최댓값은 %d입니다.\n", find->value);
                }

                getchar();
                break;
            }
            case TERMINATE:
            {   
                terminate(root);
                exit(0);
                break;
            }
        }

    }
    return 0;
}

treeNode* addNode(treeNode* t, int data) {

    if (t == NULL) {
        t = (treeNode*)malloc(sizeof(treeNode));
        t->value = data;
        t->left = NULL;
        t->right = NULL;
    }

    else if (t->value == data) {
        printf("\n\n\t\t이미 등록된 data입니다.\n");
    }

    else if (t->value < data) {
        t->right = addNode(t->right, data); // data값이 현재 노드의 값보다 큰 경우
    }

    else if (t->value > data) {
        t->left = addNode(t->left, data); // data값이 현재 노드의 값보다 작은 경우
    }

    return t;
}

void _print(treeNode* t) { // 중위순회로 보이기
    if (t != NULL) {
        _print(t->left);
        printf("%d ", t->value);
        _print(t->right);
    }
    return;
}

void terminate(treeNode* t) { // 후위순회로 제거하기
    if (t != NULL) {
        terminate(t->left);
        terminate(t->right);
        printf("%d를 삭제합니다.\n", t->value);
        free(t);
        }
    return;
}

treeNode* findMin(treeNode* t) {
    if (t->left != NULL) {
        while(t->left != NULL) {
            t = t->left;
        }
    }
    return t;
}

treeNode* findMax(treeNode* t) {
    if (t->right != NULL) {
        while(t->right != NULL) {
            t = t->right;
        }
    }
    return t;
}

treeNode* removeNode(treeNode* t, int data) {

    treeNode* temp;

    if (t != NULL) {
        if (data == t->value) {
            // 삭제 
            // case 1. 자식이 없는 경우
            if (t->left == NULL && t->right == NULL) {
                free(t);
                return NULL;
            }


            else { // 자식이 있는 경우

                // case 2. 자식이 1개인 경우
                
                if (t->right == NULL) { // case 2-1. 자식이 왼쪽만 있는 경우
                    temp = t->left; // 왼쪽 자식의 주소 저장
                    free(t); //삭제
                    return temp; // 왼쪽 자식 값 리턴. -> 이 과정에서 부모노드의 왼쪽 자식으로 자동으로 연결 됨.
                }

                if (t->left == NULL) { // case 2-1. 자식이 오른쪽만 있는 경우
                    temp = t->right; // 오른쪽 자식의 주소 저장
                    free(t); //삭제
                    return temp; // 오른쪽 자식 값 리턴. -> 이 과정에서 부모노드의 오른쪽 자식으로 자동으로 연결 됨.
                }

                // case 3. 자식이 둘다 있는 경우
                if (t->left != NULL && t->right != NULL) {

                    temp = findMax(t->left); // left 중에서 최댓값으로 값을 정렬이 완료됨.
                    // 혹은 right 중에서 최댓값으로 지정해주어도 된다.

                    t->value = temp->value;
                    // 왼쪽 자식 중 최댓값을 가진 노드의 value 값을 지금 자리에 넣어준다.

                    t->left = removeNode(t->left, temp->value);
                    // 그리고 temp를 삭제 시키면 된다. 이때, 재귀호출 방식을 이용한다.
                    // 출발지점은 t->left, 타겟은 temp->value
                    // 원래 자리에 temp Node를 넣었으니 원래 temp Node 자리에 있던 Node는 삭제시켜야한다.

                }
            }

        }
        else {
            // 왼쪽, 오른쪽으로 재귀호출
            if(t->value > data) {
                t->left = removeNode(t->left, data); // 왼쪽으로 이동
            }

            else {
                t->right = removeNode(t->right, data); // 오른쪽으로 이동
            }
            
        }
    }
    return t;
}

treeNode* searchNode(treeNode* t, int data) {
    if (t != NULL) {
        if (t->value == data) {
            // 일치한 값을 발견하면 반환
            return t;
        }
        else {
            if (t->value < data) {
                // 찾으려는 값이 현재 값보다 더 크면 오른쪽 자식으로 순회
                return searchNode(t->right, data);
            }
            else { // 찾으려는 값이 현재 값보다 더 작으면 왼쪽 자식으로 순회
                return searchNode(t->left, data);
            }
            
        }
    }
}

© 2022.07. by Wookey_Kim

Powered by Hydejack v7.5.2