728x90
반응형
일단 트리는 노드를 이용해서 사이클 없이 데이터를 적재하는 구조입니다.
이때 자식수가 2개인 트리를 이진 트리(Binary Tree)
자식수가 2개이면서 특별한 규칙에 의해 바로 정렬까지 되는 트리를 Binary Search Tree(BST) 라고 합니다.
특별한 규칙이란, 현재 노드를 기준으로 현재 노드보다 작은 값은 왼쪽에, 더 큰 값은 오른쪽에 배치되는 것입니다.
그래서 왼쪽 서브트리는 기준 노드보다 다 작고, 오른쪽 서브트리는 기준 노드 보다 더 큽니다.
BST를 구현할때는 링크드 리스트와 비슷하게 노드로 구현을 합니다.
다른 것은 다 괜찮은데, BST에서 삭제를 하는 경우가 약간 복잡합니다. 경우의 수가 많기 때문인데요,
아래의 경우들로 나뉘게 됩니다.
- 삭제할 노드의 자식 노드가 없는 경우
- 삭제할 노드가 부모 노드의 오른쪽에 있는 경우 : 부모 노드의 오른쪽을 None으로
- 삭제할 노드가 부모 노드의 왼쪽에 있는 경우 : 부모 노드의 왼쪽을 None으로
- 삭제할 노드의 자식노드가 하나 있는 경우
- 삭제할 노드가 부모의 왼쪽에 위치한 경우 : 부모노드이 왼쪽을 삭제할 노드의 자식노드로 해줌
- 삭제할 노드가 부모의 오른쪽에 위치한 경우 : 부모노드의 오른쪽을 삭제할 노드의 자식노드로 해줌
- 삭제할 노드의 자식노드가 있는 경우,
- 삭제할 노드가 부모의 왼쪽에 위치할 경우 : 가장 중앙 값이 맨 위에 오게 해야 함 → 노드의 오른쪽 자식 중 가장 작은 값을 선택 or 노드의 왼쪽 자식 중 가장 큰 값을 선택해서 부모의 왼쪽 자식으로 넣어줌 & 삭제할 노드의 왼쪽과 오른쪽 자식 노드를 대체할 노드의 왼쪽과 오른쪽 자식 노드로 넣어줘야 함
- 삭제할 노드가 부모의 오른쪽에 위치할 경우 : 가장 중앙 값이 맨 위에 오게 해야 함 → 노드의 오른쪽 자식 중 가장 작은 값을 선택 or 노드의 왼쪽 자식 중 가장 큰 값을 선택해서 부모의 오른쪽 자식으로 넣어줌 & 삭제할 노드의 왼쪽과 오른쪽 자식 노드를 대체할 노드의 왼쪽과 오른쪽 자식 노드로 넣어줘야 함
그래서 구현은 다음과 같습니다.
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
if self.change_node.left == None: # 삭제한 노드의 오른쪽 자식노드의 왼쪽 자식이 없다면
self.parent.left = self.change_node # 그냥 바로 붙이기
self.change_node.left = self.current_node.left
else :
while self.change_node.left != None: # 삭제할 노드의 오른쪽 자식의 가장 작은 것을 선택하는 과정
self.change_node_parent = self.change_node
self.change_node = self.change_node.left
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
if self.change_node.left == None: # 삭제한 노드의 오른쪽 자식노드의 왼쪽 자식이 없다면
self.parent.right = self.change_node # 그냥 바로 붙이기
self.change_node.left = self.current_node.left
else :
while self.change_node.left != None:
self.change_node_parent = self.change_node
self.change_node = self.change_node.left
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
이런 BST는 노드가 균등하게 위치해 있을때 탐색, 삽입, 삭제에 O(logN)일 정도로 굉장히 빠릅니다.
하지만 노드가 균등하게 위치하지 않을경우에는 linked list와 다를바가 없어 탐색과 삭제에서 O(n)이 걸리죠
그래서 노드를 균등하게 맞추기 위한 알고리즘 결로 자가 균형 BST(Self-Balancing BST)가 있습니다.
자가균형 BST란 알고리즘을 통해 노드가 균형있게 배치되도록 해서 높이를 낮추는 방법입니다.
자가 균형 BST에는 크게 AVL 트리와 RED-BLACK 트리가 있습니다.
다음번에는 자가 균형 BST를 알아볼게요
728x90
반응형
'CS > 알고리즘 지식' 카테고리의 다른 글
자료구조)Heap & Priority Queue (0) | 2023.05.28 |
---|---|
자료구조) BST(2/3) - 자가 균형 BST : AVL 트리 (0) | 2023.05.28 |
자료구조) 해쉬테이블(2/2)-Collision (0) | 2023.05.28 |
자료구조) 해쉬 테이블(1/2) - 해쉬테이블이 무엇인가? (2) | 2023.05.27 |
자료구조) Queue와 Stack (0) | 2023.05.27 |