Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

Manhattan Distance

Data Structures : 탐색 트리 본문

Computer Science/Data Structures

Data Structures : 탐색 트리

timotheekim10 2023. 2. 18. 21:02

탐색 트리란?

  • 탐색을 위한 트리 기반의 자료구조
  • 이진 탐색 트리
    • 정의
      • 모든 노드는 유일한 키를 가짐
      • 왼쪽 서브트리의 키들은 루트의 키보다 작음
      • 오른쪽 서브트리의 키들은 루트의 키보다 큼
      • 왼쪽과 오른쪽 서브트리도 이진 탐색 트리임
    • 효율적인 탐색을 위한 이진 트리 기반의 자료구조
    • 시간 복잡도(삽입/삭제/탐색): O(logn)

 

이진 탐색 트리 구현

class BSTNode:  # 이진탐색트리를 위한 노드 클래스
    def __init__(self, key, value):  # 생성자
        self.key = key  # 키
        self.value = value  # 값
        self.left = None  # 왼쪽 자식에 대한 링크
        self.right = None  # 오른쪽 자식에 대한 링크


def search_bst(n, key):  # 이진탐색트리 탐색연산 (재귀)
    if n == None:
        return None
    elif key == n.key:
        return n
    elif key < n.key:
        return search_bst(n.left, key)
    else:
        return search_bst(n.right, key)


def search_max_bst(n):  # 최대 값의 노드 탐색
    while n != None and n.right != None:
        n = n.right
    return n


def search_min_bst(n):  # 최소 값의 노드 탐색
    while n != None and n.left != None:
        n = n.left
    return n


def insert_bst(r, n):  # 이진탐색트리 삽입연산 (재귀)
    if n.key < r.key:  # 삽입할 노드의 키가 루트보다 작으면
        if r.left is None:  # 루트의 왼쪽 자식이 없으면
            r.left = n  # n은 루트의 왼쪽 자식이 됨
            return True
        else:  # 루트의 왼쪽 자식이 있으면
            return insert_bst(r.left, n)  # 왼쪽 자식에게 삽입하도록 함
    elif n.key > r.key:  # 삽입할 노드의 키가 루트보다 크면
        if r.right is None:  # 루트의 오른쪽 자식이 없으면
            r.right = n  # n은 루트의 오른쪽 자식이 됨
            return True
        else:  # 루트의 오른쪽 자식이 있으면
            return insert_bst(r.right, n)  # 오른쪽 자식에게 삽입하도록 함
    else:  # 키가 중복되면
        return False  # 삽입 X


def delete_bst_case1(parent, node, root):  # 단말노드 삭제
    if parent is None:  # 삭제할 단말노드가 루트이면
        root = None  # 공백트리가 됨
    else:
        if parent.left == node:  # 삭제할 노드가 부모의 왼쪽 자식이면
            parent.left = None  # 부모의 왼쪽 링크를 None
        else:  # 삭제할 노드가 부모의 오른쪽 자식이면
            parent.right = None  # 부모의 오른쪽 링크를 None
    return root


def delete_bst_case2(parent, node, root):  # 자식이 하나인 노드 삭제
    if node.left is not None:  # 왼쪽 자식만 있을 때
        child = node.left
    else:  # 오른쪽 자식만 있을 때
        child = node. right

    if node == root:  # 삭제할 노드가 루트이면
        root = child
    else:
        if node is parent.left:
            parent.left = child  # 부모와 왼쪽 자식을 연결
        else:
            parent.right = child  # 부모와 오른쪽 자식을 연결
    return root


def delete_bst_case3(parent, node, root):  # 자식이 둘인 노드 삭제
    succp = node  # 후계자의 부모노드
    succ = node.right  # 후계자노드
    while succ.left != None:  # 후계자와 부모노드 탐색
        succp = succ
        succ = succ.left

    if succp.left == succ:  # 후계자가 왼쪽 자식이면
        succp.left = succ.right  # 후계자의 오른쪽 자식과 연결
    else:  # 후계자가 오른쪽 자식이면
        succp.right = succ.right  # 후계자의 오른쪽 자식과 연결
    node.key = succ.key  # 후계자의 키를 삭제할 노드에 복사
    node.value = succ.value  # 후계자의 값을 삭제할 노드에 복사
    return root


def delete_bst(root, key):  # 이진탐색트리 삭제연산
    if root == None:  # 공백트리
        return None

    parent = None  # 삭제할 노드의 부모
    node = root  # 삭제할 노드
    while node != None and node.key != key:  # 부모 탐색
        parent = node
        if key < node.key:
            node = node.left
        else:
            node = node.right

    if node == None:  # 삭제할 노드가 없음
        return None
    # 삭제할 노드가 단말노드인 경우
    if node.left == None and node.right == None:
        root = delete_bst_case1(parent, node, root)
    # 삭제할 노드의 자식이 하나인 경우
    elif node.left == None or node.right == None:
        root = delete_bst_case2(parent, node, root)
    # 삭제할 노드의 자식이 둘인 경우
    else:
        root = delete_bst_case3(parent, node, root)
    return root


def count_node(n):  # 재귀를 이용해 트리의 노드 수를 계산
    if n is None:
        return 0
    else:
        return 1 + count_node(n.left) + count_node(n.right)


def count_leaf(n):  # 단말노드의 수 계산
    if n is None:
        return 0
    elif n.left == None and n.right == None:
        return 1
    else:
        return count_leaf(n.left) + count_leaf(n.right)


def inorder(n):  # 중위 순회
    if n is not None:
        inorder(n.left)
        print(n.key, end=' ')
        inorder(n.right)


class BSTMap():  # 이진탐색트리를 이용한 맵
    def __init__(self):  # 생성자
        self.root = None

    def isEmpty(self):  # 맵 공백 검사
        return self.root == None

    def clear(self):  # 맵 공백상태로 초기화
        self.root = None

    def size(self):  # 노드 수 계산
        return count_node(self.root)

    def search(self, key):  # 노드 탐색
        return search_bst(self.root, key)

    def findMax(self):  # 최대노드 탐색
        return search_max_bst(self.root)

    def findMin(self):  # 최소노드 탐색
        return search_min_bst(self.root)

    def insert(self, key, value=None):  # 삽입
        n = BSTNode(key, value)
        if self.isEmpty():
            self.root = n
        else:
            insert_bst(self.root, n)

    def delete(self, key):  # 삭제
        self.root = delete_bst(self.root, key)

    def display(self, msg='BSTMap: '):  # 맵 출력 (중위 순회)
        print(msg, end='')
        inorder(self.root)
        print()


if __name__ == '__main__':
    map = BSTMap()
    data = [35, 18, 7, 26, 12, 3, 68, 22, 30, 99]

    print('[삽입 연산]:', data)
    # [삽입 연산]: [35, 18, 7, 26, 12, 3, 68, 22, 30, 99]
    for key in data:
        map.insert(key)
    map.display('[중위 순회]: ')
    # [중위 순회]: 3 7 12 18 22 26 30 35 68 99

    if map.search(26) != None:
        print('[탐색 26]: 성공')
    else:
        print('[탐색 26]: 실패')
    # [탐색 26]: 성공

    if map.search(25) != None:
        print('[탐색 25]: 성공')
    else:
        print('[탐색 25]: 실패')
    # [탐색 25]: 실패

    map.delete(3)
    map.display('[3 삭제]: ')
    # [3 삭제]: 7 12 18 22 26 30 35 68 99
    map.delete(68)
    map.display('[68 삭제]: ')
    # [68 삭제]: 7 12 18 22 26 30 35 99
    map.delete(18)
    map.display('[18 삭제]: ')
    # [18 삭제]: 7 12 22 26 30 35 99
    map.delete(35)
    map.display('[35 삭제]: ')
    # [35 삭제]: 7 12 22 26 30 99

'Computer Science > Data Structures' 카테고리의 다른 글

Data Structures : 트리  (0) 2023.02.16
Data Structures : 정렬, 탐색  (0) 2023.02.13
Data Structures : 연결된 구조  (0) 2023.02.10
Data Structures : 큐, 덱  (0) 2023.02.10
Data Structures : 스택  (0) 2023.02.09