ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자료구조] 이진 탐색 트리(Binary Search Tree)
    개발/자료구조와 알고리즘 2022. 1. 31. 01:50

    이진 탐색 트리

     

    앞으로 글을 쓰겠지만 선형 자료 구조에서는 원하는 값을 탖는 방법이 여러가지가 있다.

    가장 먼저 생각할 수 있는 것은 앞 혹은 뒤에서부터 하나씩 살펴보는 선형탐색이다.

    그렇다면 트리형 자료구조에서는 원하는 값을 어떻게 찾을 수 있을까? 

    가장 기초적인 방법이 바로 이진탐색 트리이다. (물론 모두 살펴볼 수도 있을 것이다.)

     

    먼저 그림부터 보자.

    루트 노드에 값 K가 담겨있다고 생각하자.

    그렇다면 이 루트 노드의 왼쪽에 있는 서브 트리에는 K보다 작은 값이, 

    오른쪽에는 K보다 큰 값만이 들어있는 트리를 생각할 수 있고,

    이 모든 서브트리에도 같은 생각이 적용된다면 원하는 값을 찾기가 쉬울 것이다. 

    이를 이진 탐색 트리라 한다. 실제 값을 넣어서 확인해보자

    위 트리에서 13을 찾고 싶다고 생각해보자.

    13은 17보다는 작고, 10보다는 크며, 15보다는 작다.

    이렇게 트리를 만들어놓고 값을 찾으면 전체를 다 확인해보는 것보다 훨씬 빠르다.

    따라서, 선형 자료 구조에서도 값을 빨리 찾기 위해 비슷한 방식의 이진탐색을 사용한다.

     

    그렇다면 이진 탐색트리가 올바르게 동작하기 위해서는

    트리에 값을 넣거나 뺄 때 노드가 적절한 위치를 찾아가야 한다.

     

    먼저 값을 삽입하는 경우는 쉽다. 알맞은 자리에 간선으로 연결해주기만 하면 된다.

    예를 들어 위 그래프에서 7을 넣고 싶은 경우, 1의 노드까지 찾아간 다음에 7은 1보다 크므로 7의 오른쪽에 연결해주면 된다.

     

    어려운 것은 값을 삭제할 때이다.

    위 그림에서 10노드를 삭제할 경우 밑에서 값이 땡겨 올라와야하는데, 값이 알맞게 처리된 후에도 이진탐색트리의 구조는 유지되어야 한다.

     

    이를 유지하는 방법은 두 가지가 있다.

    첫째로, 제거할 노드(10)의 오른쪽 트리의 가장 왼쪽 리프노드(13)를 땡겨와서 대체,

    13은 10보다 작은 값보다는 크고, 10보다 큰 값들 중에서는 가장 작은 값이므로 10의 자리를 대체할 수 있다.

     

    두번째로는, 제거할노드(10)의 왼쪽 서브트리의 가장 오른쪽 리프노드(1)을 땡겨와서 대체,

    이는 위와 마찬가지로 10의 오른쪽 서브트리의 모든 값보다는 작고, 왼쪽 서브트리의 모든 값보다 큰 값이므로 10의 자리를 대체할 수 있게 된다.

     

    자식 노드의 상황을 고려하여 위 두 가지 경우를 모두 사용해야 한다.

     

    이진 탐색 트리를 코드로 구현하면 다음과 같다.

    class Node:
        def __init__(self, item):
            self.left = None
            self.right = None
            self.data = item
    
    class BST:
        def __init__(self,item):
            self.root = Node(item)
    
        def insert(self, item):
            if self.root is None:
                self.root = Node(item)
            else:
                cur = self.root
                while 1:
                    if item < cur.data:
                        if cur.left is not None:
                            cur = cur.left
                        else:
                            cur.left = Node(item)
                            break
                    else:
                        if cur.right is not None:
                            cur = cur.right
                        else:
                            cur.right = Node(item)
                            break
    
        def search(self, item):
            cur = self.root
            while cur:
                if cur.data == item:
                    return True
                elif cur.data < item:
                    cur = cur.right
                else:
                    cur = cur.left
            return False
    
        def delete(self, item):
            if not self.search(item):
                return False
            
            cur = self.root
            parent = self.root
            while cur:
                if cur.data == item:
                    temp = parent
                    if cur.left is None and cur.right is None:
                        if temp.left.data == item:
                            temp.left = None
                            break
                        else:
                            parent.right = None
                            break
                        
                    elif cur.right is None:
                        temp = cur
                        parent_tmp = cur
                        cur = cur.right
                        
                        while cur.right is not None:
                            parent_tmp = cur
                            cur = cur.right
                        
                        temp.left = cur.left
                        temp.right = cur.right
                        parent_tmp.right = None
                        break
    
                    else:
                        temp = cur
                        parent_tmp = cur
                        cur = cur.right
                        
                        while cur.left is not None:
                            parent_tmp = cur
                            cur = cur.left
                        
                        temp.left = cur.left
                        temp.right = cur.right
                        parent_tmp.left = None
                        break
                        
                            
                elif cur.data < item:
                    parent = cur
                    cur = cur.right
                else:
                    parent = cur
                    cur = cur.left
                    
        def inorder(self, n):
            if n:
                self.inorder(n.left)
                print(n.data, end=' ')
                self.inorder(n.right)

     

    '개발 > 자료구조와 알고리즘' 카테고리의 다른 글

    [자료구조] 그래프  (0) 2022.02.16
    [자료구조] 힙(Heap)  (0) 2022.02.05
    [자료구조] 트리  (0) 2022.01.26
    [자료구조] LinkedList  (0) 2022.01.24
    [자료구조] Queue & Stack  (0) 2022.01.21

    댓글

Designed by Tistory.