ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자료구조 트리2
    자료구조와 알고리즘 2020. 10. 26. 17:42

    5.4. 이진 탐색 트리 삭제

    • 매우 복잡함. 경우를 나누어서 이해하는 것이 좋음

    5.4.1. Leaf Node 삭제

    • Leaf Node: Child Node 가 없는 Node
    • 삭제할 Node의 Parent Node가 삭제할 Node를 가리키지 않도록 한다.

       

    5.4.2. Child Node 가 하나인 Node 삭제

    • 삭제할 Node의 Parent Node가 삭제할 Node의 Child Node를 가리키도록 한다.

    5.4.3. Child Node 가 두 개인 Node 삭제

    1. 삭제할 Node의 오른쪽 자식 중, 가장 작은 값(맨~왼쪽 값)을 삭제할 Node의 Parent Node가 가리키도록 한다.
    2. 삭제할 Node의 왼쪽 자식 중, 가장 큰 값(맨~오른쪽 값)을 삭제할 Node의 Parent Node가 가리키도록 한다.

    5.4.3.1. 삭제할 Node의 오른쪽 자식중, 가장 작은 값을 삭제할 Node의 Parent Node가 가리키게 할 경우

    • 삭제할 Node의 오른쪽 자식 선택
    • 오른쪽 자식의 가장 왼쪽에 있는 Node를 선택
    • 해당 Node를 삭제할 Node의 Parent Node의 왼쪽 Branch가 가리키게 함
    • 해당 Node의 왼쪽 Branch가 삭제할 Node의 왼쪽 Child Node를 가리키게 함
    • 해당 Node의 오른쪽 Branch가 삭제할 Node의 오른쪽 Child Node를 가리키게 함
    • 만약 해당 Node가 오른쪽 Child Node를 가지고 있었을 경우에는, 해당 Node의 본래 Parent Node의 왼쪽 Branch가 해당 오른쪽 Child Node를 가리키게 함

    5.5. 이진 탐색 트리 삭제 코드 구현과 분석

    5.5.1 삭제할 Node 탐색

    • 삭제할 Node가 없는 경우도 처리해야 함
      • 이를 위해 삭제할 Node가 없는 경우는 False를 리턴하고, 함수를 종료 시킴
    def delete(self, value):
        searched = False
        self.current_node = self.head
        self.parent = self.head #삭제할 노드의 페런트
        while self.current_node: #삭제할 노드
            if self.current_node.value == value:
                searched = True
                break
            elif value < self.current_node.value:
                self.parent = self.current_node
                self.current_node = self.current_node.left
            else:
                self.parent = self.current_node
                self.current_node = self.current_node.right
        
        if searched == False:
            return False
        
        ### 이후부터 Case들을 분리해서, 코드 작성

    5.5.2. Case1: 삭제할 Node가 Leaf Node인 경우

    # self.current_node 가 삭제할 Node, self.parent는 삭제할 Node의 Parent Node인 상태
        if  self.current_node.left == None and self.current_node.right == None:
            if value < self.parent.value:
                self.parent.left = None
            else:
                self.parent.right = None
            del self.current_node

    5.5.2. Case2: 삭제할 Node가 Child Node를 한 개 가지고 있을 경우

    if self.current_node.left != None and self.current_node.right == None:
            if value < self.parent.value:
                self.parent.left = self.current_node.left
            else:
                self.parent.right = self.current_node.left
        elif self.current_node.left == None and self.current_node.right != None:
            if value < self.parent.value:
                self.parent.left = self.current_node.right
            else:
                self.parent.right = self.current_node.right

    5.5.3. Case3-1: 삭제할 Node가 Child Node를 두 개 가지고 있을 경우 (삭제할 Node가 Parent Node 왼쪽에 있을 때)

    • 기본 사용 가능 전략
      1. 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 삭제할 Node의 Parent Node가 가리키도록 한다.
      2. 삭제할 Node의 왼쪽 자식 중, 가장 큰 값을 삭제할 Node의 Parent Node가 가리키도록 한다.
    • 기본 사용 가능 전략 중, 1번 전략을 사용하여 코드를 구현하기로 함
      • 경우의 수가 또다시 두가지가 있음
        • Case3-1-1: 삭제할 Node가 Parent Node의 왼쪽에 있고, 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 가진 Node의 Child Node가 없을 때
        • Case3-1-2: 삭제할 Node가 Parent Node의 왼쪽에 있고, 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 가진 Node의 오른쪽에 Child Node가 있을 때
          • 가장 작은 값을 가진 Node의 Child Node가 왼쪽에 있을 경우는 없음, 왜냐하면 왼쪽 Node가 있다는 것은 해당 Node보다 더 작은 값을 가진 Node가 있다는 뜻이기 때문임

    if self.current_node.left != None and self.current_node.right != None: # case3
            if value < self.parent.value: # case3-1
                self.change_node = self.current_node.right
                self.change_node_parent = self.current_node.right
                while self.change_node.left != None:
                    self.change_node_parent = self.change_node
                    self.change_node = self.change_node.left
                if self.change_node.right != None:
                    self.change_node_parent.left = self.change_node.right
                else:
                    self.change_node_parent.left = None
                self.parent.left = self.change_node
                self.change_node.right = self.current_node.right
                self.change_node.left = self.current_node.left

    5.5.4. Case3-2: 삭제할 Node가 Child Node를 두 개 가지고 있을 경우 (삭제할 Node가 Parent Node 오른쪽에 있을 때)

    • 기본 사용 가능 전략
      1. 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 삭제할 Node의 Parent Node가 가리키도록 한다.
      2. 삭제할 Node의 왼쪽 자식 중, 가장 큰 값을 삭제할 Node의 Parent Node가 가리키도록 한다.
    • 기본 사용 가능 전략 중, 1번 전략을 사용하여 코드를 구현하기로 함
      • 경우의 수가 또다시 두가지가 있음
        • Case3-2-1: 삭제할 Node가 Parent Node의 오른쪽에 있고, 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 가진 Node의 Child Node가 없을 때
        • Case3-2-2: 삭제할 Node가 Parent Node의 오른쪽에 있고, 삭제할 Node의 오른쪽 자식 중, 가장 작은 값을 가진 Node의 오른쪽에 Child Node가 있을 때
          • 가장 작은 값을 가진 Node의 Child Node가 왼쪽에 있을 경우는 없음, 왜냐하면 왼쪽 Node가 있다는 것은 해당 Node보다 더 작은 값을 가진 Node가 있다는 뜻이기 때문임

    else:
                self.change_node = self.current_node.right
                self.change_node_parent = self.current_node.right
                while self.change_node.left != None:
                    self.change_node_parent = self.change_node
                    self.change_node = self.change_node.left
                if self.change_node.right != None:
                    self.change_node_parent.left = self.change_node.right
                else:
                    self.change_node_parent.left = None
                self.parent.right = self.change_node
                self.change_node.left = self.current_node.left
                self.change_node.right = self.current_node.right

    5.5.5. 파이썬 전체 코드 구현

    class Node:
        def __init__(self, value):
            self.value = value
            self.left = None
            self.right = None
    
            
    class NodeMgmt:
        def __init__(self, head):
            self.head = head
        
        def insert(self, value):
            self.current_node = self.head
            while True:
                if value < self.current_node.value:
                    if self.current_node.left != None:
                        self.current_node = self.current_node.left
                    else:
                        self.current_node.left = Node(value)
                        break
                else:
                    if self.current_node.right != None:
                        self.current_node = self.current_node.right
                    else:
                        self.current_node.right = Node(value)
                        break
        
        def search(self, value):
            self.current_node = self.head
            while self.current_node:
                if self.current_node.value == value:
                    return True
                elif value < self.current_node.value:
                    self.current_node = self.current_node.left
                else:
                    self.current_node = self.current_node.right
            return False        
        
        def delete(self, value):
            # 삭제할 노드 탐색
            searched = False
            self.current_node = self.head
            self.parent = self.head
            while self.current_node:
                if self.current_node.value == value:
                    searched = True
                    break
                elif value < self.current_node.value:
                    self.parent = self.current_node
                    self.current_node = self.current_node.left
                else:
                    self.parent = self.current_node
                    self.current_node = self.current_node.right
    
            if searched == False:
                return False    
    
            # case1
            if  self.current_node.left == None and self.current_node.right == None:
                if value < self.parent.value:
                    self.parent.left = None
                else:
                    self.parent.right = None
            
            # case2
            elif self.current_node.left != None and self.current_node.right == None:
                if value < self.parent.value:
                    self.parent.left = self.current_node.left
                else:
                    self.parent.right = self.current_node.left
            elif self.current_node.left == None and self.current_node.right != None:
                if value < self.parent.value:
                    self.parent.left = self.current_node.right
                else:
                    self.parent.right = self.current_node.right        
            
            # case 3
            elif self.current_node.left != None and self.current_node.right != None:
                # case3-1
                if value < self.parent.value:
                    self.change_node = self.current_node.right
                    self.change_node_parent = self.current_node.right
                    while self.change_node.left != None:
                        self.change_node_parent = self.change_node
                        self.change_node = self.change_node.left
                    if self.change_node.right != None:
                        self.change_node_parent.left = self.change_node.right
                    else:
                        self.change_node_parent.left = None
                    self.parent.left = self.change_node
                    self.change_node.right = self.current_node.right
                    self.change_node.left = self.current_node.left
                # case 3-2
                else:
                    self.change_node = self.current_node.right
                    self.change_node_parent = self.current_node.right
                    while self.change_node.left != None:
                        self.change_node_parent = self.change_node
                        self.change_node = self.change_node.left
                    if self.change_node.right != None:
                        self.change_node_parent.left = self.change_node.right
                    else:
                        self.change_node_parent.left = None
                    self.parent.right = self.change_node
                    self.change_node.right = self.current_node.right
                    self.change_node.left = self.current_node.left
    
            return True

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

    자료구조 힙  (0) 2020.10.27
    자료구조 트리3  (0) 2020.10.27
    자료구조 트리  (0) 2020.10.26
    자료구조 해쉬 테이블3  (0) 2020.10.25
    자료구조 해쉬 테이블2  (0) 2020.10.25
전설의 개발자