일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- fetch
- 데코레이터
- 백트래킹
- execute
- 이진탐색
- 연관관계
- 비관적락
- 일대다
- FetchType
- 동적sql
- 다대다
- 다대일
- SQL프로그래밍
- 힙
- 지연로딩
- 연결리스트
- 즉시로딩
- BOJ
- 유니크제약조건
- eager
- querydsl
- dfs
- 낙관적락
- shared lock
- PS
- 스프링 폼
- exclusive lock
- 스토어드 프로시저
- CHECK OPTION
- JPQL
- Today
- Total
흰 스타렉스에서 내가 내리지
[자료 구조] 이진 탐색 트리 (Binary Search Tree) 본문
이진 탐색 트리의 정의
- 모든 키는 유일하다.
- 어떤 노드를 특정했을 때 이 노드의 키 값은 왼쪽 서브트리의 그 어떤 키보다 크다.
- 어떤 노드를 특정했을 때 이 노드의 키 값은 오른쪽 서브트리의 그 어떤 키 값보다 작다.
- (재귀적 정의) 노드의 서브트리도 이진탐색트리이다.
더 자세한 내용은 여기
Binary search tree - Wikipedia
From Wikipedia, the free encyclopedia Jump to navigation Jump to search Data structure in tree form sorted for fast lookup Binary search treeTypetreeInvented1960Invented byP.F. Windley, A.D. Booth, A.J.T. Colin, and T.N. HibbardAlgorithm Average Worst case
en.wikipedia.org
이진 탐색 트리의 ADT
BinarySearchTree
- Object
: 유일한 키 값을 가진 노드 집합
- Operation
1. BST.insert(key)
: 새로운 키 삽입
2. BST.search(target) → node
: target을 키로 가지는 노드를 찾아 반환
3. BST.delete(target)
: target을 키로 가지는 노드를 삭제
4. BST.min(node) → node
: 매개변수 node를 루트로 하는 이진 탐색 트리에서 가장 작은 key를 가진 노드를 반환
5. BST.max(node) → node
: 매개변수 node를 루트로 하는 이진 탐색 트리에서 가장 큰 key를 가진 노드를 반환
6. BST.prev(cur) → node
: 정렬된 상태에서 cur노드의 바로 이전 노드를 찾아 반환
7. BST.next(cur) → node
: 정렬된 상태에서 cur노드의 바로 다음 노드를 찾아 반환
class TreeNode:
def __init__(self, key):
self.__key = key
self.__left = None
self.__right = None
self.__parent = None
def __del__(self):
print(f'key {self.__key} is deleted.')
@property
def key(self):
return self.__key
@key.setter
def key(self, key):
self.__key = key
@property
def left(self):
return self.__left
@left.setter
def left(self, left):
self.__left = left
@property
def right(self):
return self.__right
@right.setter
def right(self, right):
self.__right = right
@property
def parent(self):
return self.__parent
@parent.setter
def parent(self, p):
self.__parent = p
class BST:
def __init__(self):
self.root = None
def get_root(self):
return self.root
def preorder_traverse(self, cur, func):
if not cur:
return
func(cur)
self.preorder_traverse(cur.left, func)
self.preorder_traverse(cur.right, func)
def inorder_traverse(self, cur, func):
if not cur:
return
self.inorder_traverse(cur.left, func)
func(cur)
self.inorder_traverse(cur.right, func)
def __make_left(self, cur, left):
cur.left = left
if left:
left.parent = cur
def __make_right(self, cur, right):
cur.right = right
if right:
right.parent = cur
def insert(self, key):
new_node = TreeNode(key)
cur = self.root
if not cur:
self.root = new_node
return
while True:
parent = cur
if key < cur.key:
cur = cur.left
if not cur:
self.__make_left(parent, new_node)
return
else:
cur = cur.right
if not cur:
self.__make_right(parent, new_node)
return
def search(self, target):
cur = self.root
while cur:
if cur.key == target:
return cur
elif cur.key > target:
cur = cur.left
elif cur.key < target:
cur = cur.right
return cur
def min(self, cur):
while cur.left != None:
cur = cur.left
return cur
def max(self, cur):
while cur.right != None:
cur = cur.right
return cur
def __delete_recursion(self, cur, target):
if not cur:
return None
elif target < cur.key:
new_left = self.__delete_recursion(self, cur.left, target)
self.__make_left(cur, new_left)
elif target > cur.key:
new_right = self.__delete_recursion(self, cur.right, target)
self.__make_right(cur, new_right)
else:
# 리프 노드일 때
if not cur.left and not cur.right:
cur = None
# 왼쪽 자식만 있을 때
elif not cur.right:
cur = cur.left
elif not cur.left:
cur = cur.right
# 자식이 둘일 때
else:
replace = cur.left
replace = self.max(replace)
cur.key, replace.key = replace.key, cur.key
new_left = self.__delete_recursion(cur.left, replace.key)
self.__make_left(cur, new_left)
return cur
def delete(self, target):
new_root = self.__delete_recursion(self.root, target)
selt.root = new_root
def prev(self, cur):
# 왼쪽 자식이 있다면 왼쪽 자식에서 가장 큰 노드
if cur.left:
return self.max(cur.left)
parent = cur.parent
while parent and cur == parent.left:
cur = parent
parent = parent.parent
return parent
def next(self, cur):
if cur.right:
return self.min(cur.right)
parent = cur.parent
while parent and cur == parent.right:
cur = parent
parent = parent.parent
return parent
bst = BST()
bst.insert(6)
bst.insert(3)
bst.insert(2)
bst.insert(4)
bst.insert(5)
bst.insert(8)
bst.insert(10)
bst.insert(9)
bst.insert(11)
f = lambda x : print(x.key, end = ' ')
bst.inorder_traverse(bst.get_root(), f)
BST의 삭제 : 삭제하려는 노드가 리프 노드인지, 자식이 하나만 있는 노드인지, 자식이 둘인지 나누어서 삭제해야 한다.
이진 탐색 트리의 시간 복잡도
트리의 높이가 h일 때, 삽입 삭제, 조회 모두 O(h)이다. (h ≒ logN)
그런데, 이진 탐색 트리에 데이터가 정렬된 채로 삽입되어 각 레벨마다 노드가 하나씩만 있는 편향 이진 트리일 경우 삽입, 삭제, 조회 모두 O(n)이 된다.
이런 이유 때문에 생겨난게 레드 블랙 트리 (Red Black Tree) 이다.
'Data Structure' 카테고리의 다른 글
[자료구조] 힙 (Heap) (0) | 2022.01.04 |
---|---|
자료구조에 대하여 (0) | 2022.01.02 |
[자료구조] 트리에서의 4가지 순회 방법 (0) | 2022.01.02 |
[자료구조] 큐와 원형 큐 (Queue, Circular Queue) (0) | 2022.01.02 |
[자료구조] 더미 이중 연결 리스트 (Dummy Double Linked List) (0) | 2022.01.01 |