언어/기타
2006.12.29 22:15

[자료구조] Binary Search Tree

조회 수 1218 추천 수 3 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄
?

단축키

Prev이전 문서

Next다음 문서

크게 작게 위로 아래로 댓글로 가기 인쇄

 


오늘은 그동안 강의했던 객체 지향 프로그래밍에서 약간 벗어나, 자료 구조에 대해 설명을 드리려고 합니다.


 


매일 똑같은 것만 보면 질리기 마련이니까요 ^^; (말하는 사람도 지쳐요 ~)


 


 


 


- 자료구조는 무엇인가?


 : 우리가 프로그램을 만들면서 사용하는 데이터는 너무나 다양합니다. 정수, 실수, 문자, 문자열, 객체...


 


이런 자료들을 어떻게 하면 효율적으로 컴퓨터에서 다룰 수 있을 것인가에 대한 분야입니다.


 


가장 기초적인 자료구조는 '배열', '구조체' 등이 있고, 약간 발전한 '클래스(객체)' 도 자료구조로 칠 수 있습니다.


 


하지만 이런 것은 그냥 '덩어리'를 통채로 만들어 내는 것이라 융통성이 없지요.


 


예를 들어 배열을 10개 잡는다면 그 이후에는 크기를 변경할 수 없잖아요?


 


그래서 처음 등장한 것이 Linked List, 연결 리스트형태입니다. 이부분은 아래쪽에 잘 설명해주신분이 계시기에 넘어가기로 했습니다.


 


 


저 연결리스트를 사람들이 많이 사용하다가 느낀점은, '자료를 찾는데 너무 오래걸린다!' 라는 것입니다.


 


크기도 융통성 있게 변하고, 데이터도 모두 다룰 수 있는 점에서는 합격이었지만, 연결 리스트이기에 처음부터 마지막까지 쭉 훑어봐야하는 과정이 필요했던 것이죠.


 


그래서 등장한 것이 지금 설명드리는 Binary Search Tree입니다.


 


 


                                   [10]


                               ┌─┴─┐


                             [5]         [15]


                          ┌┴┐     ┌┴─┐


                        [2]    [7]  [12]  [17]


 


                         [예.이진 탐색트리]


 


위 그림에서 제일 꼭대기에 있는 [10]을 Root라고 부릅니다.


 


왼쪽에 연결된 칸에는 10보다 작은 데이터.


 


오늘쪽에 연결된 칸에는 10보다 큰 데이터를 넣어 놓는 방식입니다.


 


 


여기서 12를 찾고자 한다면, [10]에서 시작해서, 목표인 12가 현재칸의 수보다 크면 오른쪽 칸으로, 작으면 왼쪽칸으로 이동하면서 비교를 하면 됩니다.


 


단순히 보면, [10]->[15]->[12] 순으로 찾아나가게 되는 것이지요.


 


단순한 연결리스트였다면, [2]->[5]->[7]->[10]->[12] 이런 순서로 검색을 하게 될 것입니다.


 


 


 


이 규칙을 이용해서, 삽입 역시 쉽게 할 수 있습니다.


 


13을 삽입한다고 예를 들면, 13을 검색하면서 따라가다가 '공백'을 만나면 새로 칸을 만들어서 저장하면 됩니다.


 


규칙대로 [12]의 오른쪽 칸에 삽입이 될 것입니다.


 


 


 


하지만 BST(Binary Search Tree)에서 중요한 것은 '삭제'입니다.


 


만약 [10]을 삭제한다고 하면, 어떻게 해야 할까요?


 


이 때의 방법은 약간 생각을 해야합니다. 10에서 연결된 양쪽 데이터들 역시 작은 BST라고 할 수 있지요?


 


                             [5]         [15]


                          ┌┴┐     ┌┴─┐


                        [2]    [7]  [12]  [17]


 


이 양쪽의 작은 트리중에 가장 가운데에 가까운 숫자를 뽑아냅시다.


 


7 또는 12가 선택되어야 합니다.


 


이를 선택하는 방법은, 양쪽 트리를 기준으로 공백이 나올때까지 왼쪽 또는 오른쪽으로 이동하면 한쪽 트리의 끝 데이터를 만날 수 있습니다.


 


이때의 데이터를 삭제할 [10]의 위치에 넣는 것입니다.


 


 


[7] 노드를 선택하였다고 합시다.


 


                                    [7]


                               ┌─┴─┐


                             [5]         [15]


                          ┌┘        ┌┴─┐


                        [2]          [12]  [17]


 


대충 어떤 방식인지 이해가 가시겠죠?


 


몇개의 발생할 수 있는 상황을 예측해서 그에따른 BST를 유지해주는 것이 관건입니다.


 


 


 


 


그리고 또 한가지 알려드릴 것은 In Order Traversal 입니다. 이것은 Tree를 하나의 리스트로 바꿔줄 수 있는 방법입니다.


 


List를 가지고 트리를 구성할 수도 있습니다.


 


 


In Order Traversal은 어떤 노드에서 시작하여, '왼쪽 데이터뭉치', 자신, '오른쪽 데이터뭉치' 순서로 출력하는 것을 기준으로 계속 아래쪽으로 시켜나가는 방식입니다.


 


그림으로 설명드리는게 가장 편하겠군요.


 


1 : 왼쪽 - [7] - 오른쪽


2 : 왼쪽-[5]-오른쪽-[7]-왼쪽-[15]-오른쪽


3 : [2]-[5]-[7]-[12]-[15]-[17]


 


이런식으로 시켜나가면 왼쪽부터 오른쪽 데이터까지 순서대로 가져올 수 있습니다.


 


이번에 알려드린 BST는 가장 기본적인 검색트리로써, 데이터를 [간단하고] 빠르게 찾아낼 수 있는 유명한 방식입니다.


 


 


 


오늘은 말로만 설명을 드리면 이해가 안되실 분들이 많을 것 같아서 예제를 통채로 드리니 참고하세요.


 


 


 


삽입, 삭제, 검색, In Order Traversal을 확인하기 쉽도록 메뉴를 만들어 두었습니다.


 


코드를 그대로 가져다 컴파일 하셔도 동작하니 한번쯤 테스트하고, 자료구조가 어떤 것인가에 대해 생각해보시는 것도 좋을 것 같습니다.


===============================================================================


#include <iostream>
#include <string>
using namespace std;


class BST
{
public:
    typedef struct BST_Node
    {
        struct BST_Node* l_child;
        struct BST_Node* r_child;
        int Key;
    } BST_NODE;


    BST_NODE* root;
   
    BST();
    ~BST();


    BST_NODE*    Insert_BST(int Key);
    BST_NODE*    Insert_BST(int Key, BST_NODE* srt);
    int            Search_BST(int Key);
    int            Search_BST(int Key, BST_NODE* srt);
    int            Delete_BST(int Key);
    int            Delete_BST(int Key, BST_NODE* srt, bool display);


    BST_NODE*    Get_MAX(BST_NODE* srt);
    BST_NODE*    Get_MIN(BST_NODE* srt);


    void InOrderTraversal();
    void InOrderTraversal(BST_NODE* srt);
   
    int    Clear(BST_NODE** Key);
    int Clear_All();
};


BST::BST()
{
    root = 0;
}


BST::~BST()
{
    Clear_All();
}


BST::BST_NODE* BST::Get_MAX(BST_NODE* srt)
{
    if (srt->r_child == 0) return srt;
    else return Get_MAX(srt->r_child);
}


BST::BST_NODE* BST::Get_MIN(BST_NODE* srt)
{
    if (srt->l_child == 0) return srt;
    else return Get_MIN(srt->l_child);
}


BST::BST_NODE* BST::Insert_BST(int Key)
{
    return Insert_BST(Key, root);
}


BST::BST_NODE* BST::Insert_BST(int Key, BST_NODE* srt)
{
    if (root == 0)
    {
        root = new BST_NODE();
        root->Key = Key;
        root->l_child = 0;
        root->r_child = 0;


        cout << " * 정상적으로 입력되었습니다. " << endl;
        return root;
    }
    else
    {
        if (srt == 0)
        {
            srt = new BST_NODE();
            srt->Key = Key;
            srt->l_child = 0;
            srt->r_child = 0;


            cout << " * 정상적으로 입력되었습니다. " << endl;
            return srt;
        }
        else
        {
            if (srt->Key > Key)
            {
                BST_NODE* temp = Insert_BST(Key, srt->l_child);
                if (temp != 0)
                    srt->l_child = temp;
                return 0;
            }
            else if (srt->Key == Key)
            {
                cout << " * 이미 노드가 존재합니다. " << endl;
                return 0;
            }
            else
            {
                BST_NODE* temp = Insert_BST(Key, srt->r_child);
                if (temp != 0)
                    srt->r_child = temp;
                return 0;
            }
        }
    }
}


int BST::Search_BST(int Key)
{
    return Search_BST(Key, root);
}


int BST::Search_BST(int Key, BST_NODE* srt)
{
    if (srt == 0)
    {
        cout << " * 노드가 존재하지 않습니다." << endl;
        return -1;
    }
    else
    {
        if (srt->Key > Key)
            return Search_BST(Key, srt->l_child);
        else if (srt->Key == Key)
        {
            cout << " * 노드를 찾았습니다. [" << srt->Key <<"]" << endl;
            return srt->Key;
        }
        else
            return Search_BST(Key, srt->r_child);
    }


    return 0;
}


int BST::Delete_BST(int Key)
{
    int temp = Delete_BST(Key, root, true);
    if (temp == 1)
    {
        cout << " * 트리가 공백입니다." << endl;
        root = 0;
        return 1;
    }
    else return temp;
}



int BST::Delete_BST(int Key, BST_NODE* srt, bool display)
{
    if (srt != 0)
    {
        if (srt->l_child == 0 && srt->r_child == 0)
        {
            if (srt->Key == Key)
            {
                if (display)
                    cout << " * 성공적으로 삭제하였습니다." << endl;
                delete(srt);
                return 1;
            }
            else
            {
                if (display)
                    cout << " * 노드를 찾을 수 없습니다." << endl;
                return 0;
            }
        }
        else
        {


            if (srt->Key == Key)
            {
                int temp = 0;
               
                if (srt->l_child != 0) temp = Get_MAX(srt->l_child)->Key;
                else temp = Get_MIN(srt->r_child)->Key;
               
                Delete_BST(temp, root, false);
                if (display)
                    cout << " * 성공적으로 삭제하였습니다." << endl;
           
                srt->Key = temp;
                return 0;
            }


            if (srt->l_child != 0)
            {
                int temp = Delete_BST(Key, srt->l_child, display);
                if (temp == 1) srt->l_child = 0;
            }
            if (srt->r_child != 0)
            {
                int temp = Delete_BST(Key, srt->r_child, display);
                if (temp == 1) srt->r_child = 0;
            }
            else return 0;


            return 0;
        }
    }
    else return 0;
}


int BST::Clear(BST_NODE** Key)
{
    if ((*Key) != 0)
    {
        if ((*Key)->l_child != 0)
            Clear(&((*Key)->l_child));
        if ((*Key)->r_child != 0)
            Clear(&((*Key)->r_child));
       
        delete(*Key);
        (*Key) = 0;
    }
   
    return 0;
}


int BST::Clear_All()
{
    return Clear(&root);
}


 


void BST::InOrderTraversal()
{
    InOrderTraversal(root);
}



void BST::InOrderTraversal(BST_NODE *srt)
{
    if (srt == 0) return;
    else
    {
        if ((srt->l_child))
            InOrderTraversal(srt->l_child);


        cout << "[" << srt->Key << "] ";


        if ((srt->r_child))
            InOrderTraversal(srt->r_child);
    }
}


void main()
{
    string command = "0";


    BST bst;


    for(;;)
    {
        system("cls");


        cout << "====================================" << endl;
        cout << "         Binary Search Tree         " << endl;
        cout << "------------------------------------" << endl;
        cout << " 1. Insert                          " << endl;
        cout << " 2. Search                          " << endl;
        cout << " 3. Delete                          " << endl;
        cout << " 4. Clear                           " << endl;
        cout << " 5. In Order Traversal              " << endl;
        cout << " 6. Exit                            " << endl;
       
        switch(command[0])
        {
            case '1':
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 삽입 되었습니다.      " << endl;
                break;
            case '2':
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 검색 되었습니다.      " << endl;
                break;
            case '3':
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 삭제 되었습니다.      " << endl;
                break;
            case '4':
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 반환 되었습니다.      " << endl;
                break;
            case '5':
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 출력 되었습니다.      " << endl;
                break;
        }
       
        cout << "====================================" << endl;
       
        cout << ">";
        cin  >> command;


        if (command[0] == '6') break;


        int icommand = 0;
        BST::BST_Node* ncommand = 0;
        switch(command[0])
        {
            case '1':
                system("cls");
                cout << "====================================" << endl;
                cout << "         Binary Search Tree         " << endl;
                cout << "------------------------------------" << endl;
                cout << " * 삽입할 노드의 키를 입력하세요.   " << endl;
                cout << "------------------------------------" << endl;
                cout << ">"; cin  >> icommand;
                cout << "====================================" << endl;
               
                ncommand = bst.Insert_BST(icommand);
                system("pause");
                break;
            case '2':
                system("cls");
                cout << "====================================" << endl;
                cout << "         Binary Search Tree         " << endl;
                cout << "------------------------------------" << endl;
                cout << " * 검색할 노드의 키를 입력하세요.   " << endl;
                cout << "------------------------------------" << endl;
                cout << ">"; cin  >> icommand;
                cout << "====================================" << endl;
               
                icommand = bst.Search_BST(icommand);
                system("pause");
                break;
            case '3':
                system("cls");
                cout << "====================================" << endl;
                cout << "         Binary Search Tree         " << endl;
                cout << "------------------------------------" << endl;
                cout << " * 삭제할 노드의 키를 입력하세요.   " << endl;
                cout << "------------------------------------" << endl;
                cout << ">"; cin  >> icommand;
                cout << "====================================" << endl;
               
                icommand = bst.Delete_BST(icommand);
                system("pause");
                break;
            case '4':
                system("cls");
                cout << "====================================" << endl;
                cout << "         Binary Search Tree         " << endl;
                cout << "------------------------------------" << endl;
                cout << " * 정상적으로 반환하였습니다.       " << endl;
                cout << "====================================" << endl;


                bst.Clear_All();
                system("pause");
                break;
            case '5':
                system("cls");
                cout << "====================================" << endl;
                cout << "         Binary Search Tree         " << endl;
                cout << "------------------------------------" << endl;
                cout << " * In Oder Traversal 결과           " << endl;
                cout << " : "; bst.InOrderTraversal(); cout << endl;
                cout << "====================================" << endl;


                system("pause");
                break;
            default:
                break;
        }
    }
}
=================================================

?

  1. 물체 밀어서 움직이는 이벤트 조금 더 쉽게 하는 법

    Date2018.01.02 CategoryRPG Maker Byzero? Views644
    Read More
  2. [마지막 3명 모집] [취업연계무료교육] VR/AR 게임 콘텐츠 전문가 양성 과정 교육생 모집

    Date2017.07.14 Category언어/기타 By황금상자 Views702
    Read More
  3. rpg vxa 로 겜만들때 데미지 설정 공식[링크]

    Date2017.06.08 CategoryRPG Maker By준E Views740
    Read More
  4. [꿀팁] 간단하게 만들 수 있는 실시간 전투 시스템

    Date2017.03.31 CategoryRPG Maker By준E Views2019
    Read More
  5. JSON parser 변환데이터 저장시 생기는 Object Too Deep 해결하기

    Date2016.12.24 Category언어/기타 Bytitle: 댓글러lklslel Views851
    Read More
  6. 앙뜨프리너십에서 해커톤 부트캠프 모집중이네요

    Date2016.11.08 Category언어/기타 By마나님이 Views908
    Read More
  7. RPG MV에서 플러그인 오류의 원인에 대하여

    Date2016.07.08 CategoryRPG Maker Bytitle: 댓글러lklslel Views2359
    Read More
  8. RPG MV 게임 도중에 윈도우 스킨 파일 자체를 통째로 바꿔버리는 방법 (출처: HIME)

    Date2016.07.08 CategoryRPG Maker By최저 Views1627
    Read More
  9. 게임의 버전을 짜 보자! - 유의적 버전 2.0.0

    Date2016.06.07 Category언어/기타 ByYanggaeng Views1123
    Read More
  10. 텍스트 대화 도중 메뉴 여는 방법을 알아냈습니다!

    Date2016.03.12 CategoryRPG Maker By정궈니 Views2938
    Read More
  11. rpgmv 마우스 지원과 터치 지원이 되니.

    Date2015.10.25 CategoryRPG Maker By팡소리 Views1011
    Read More
  12. RPG Maker MV 와 AJAX를 이용한 웹통신 관련 영상.

    Date2015.10.25 CategoryRPG Maker ByHT9MAN Views2246
    Read More
  13. RPG게임 뻔한요소들.

    Date2015.10.05 Category언어/기타 Bytitle: 천무천무 Views1644
    Read More
  14. 자바스크립트와 관련해서 참고할 만한 사이트들

    Date2015.10.04 Category언어/기타 ByMARCO Views921
    Read More
  15. 꿀잼이군요!

    Date2015.05.20 Category언어/기타 By사람님[대회참가] Views873
    Read More
  16. [RPG2000/3 팁] 간편한 이벤트 단축키

    Date2015.04.06 CategoryRPG Maker Bytitle: 자게이하앵 Views1833
    Read More
  17. [RPG2000/3 팁] 간편한 이벤트 단축키

    Date2015.04.05 CategoryRPG Maker Bytitle: 자게이하앵 Views748
    Read More
  18. [강의링크] 대비법칙-색상대비-밀당의 재미 약한 반대색 설계

    Date2015.04.02 Category언어/기타 Bytitle: 천무천무 Views636
    Read More
  19. 오다 주웠습니다.

    Date2015.03.30 Category언어/기타 By사람님[대회참가] Views917
    Read More
  20. 무료 이미지 사이트 Pixabay!

    Date2015.03.28 Category언어/기타 By나작소 Views909
    Read More
Board Pagination Prev 1 2 3 4 5 6 7 8 9 10 ... 51 Next
/ 51


[개인정보취급방침] | [이용약관] | [제휴문의] | [후원창구] | [인디사이드연혁]

Copyright © 1999 - 2016 INdiSide.com/(주)씨엘쓰리디 All Rights Reserved.
인디사이드 운영자 : 천무(이지선) | kernys(김원배) | 사신지(김병국)