06. 이진 탐색 트리 (Binary Search Tree)
BST 속성 을 만족하는 이진 탐색 트리를 구현하세요.
모든 노드에서 왼쪽 서브트리의 값 < 현재 노드의 값 < 오른쪽 서브트리의 값을 만족하는 트리입니다.
BST 속성 이해
재귀적 트리 순회 (전위, 중위, 후위, 레벨)
삽입, 삭제, 검색 알고리즘
균형 트리의 필요성 이해
트리 기반 집합/맵 구현
메서드
설명
평균 시간복잡도
최악 시간복잡도
insert(value)
값 삽입
O(log n)
O(n)
search(value)
값 검색
O(log n)
O(n)
delete(value)
값 삭제
O(log n)
O(n)
contains(value)
존재 여부 확인
O(log n)
O(n)
min()
최솟값 반환
O(log n)
O(n)
max()
최댓값 반환
O(log n)
O(n)
size()
노드 개수
O(1)
O(1)
isEmpty()
비어있는지 확인
O(1)
O(1)
clear()
모든 노드 삭제
O(1)
O(1)
메서드
순서
용도
inorder()
왼쪽 → 루트 → 오른쪽
정렬된 순서 출력
preorder()
루트 → 왼쪽 → 오른쪽
트리 복사, 직렬화
postorder()
왼쪽 → 오른쪽 → 루트
트리 삭제, 후위 표기법
levelorder()
레벨 순서 (BFS)
레벨별 처리
메서드
설명
height()
트리 높이
floor(value)
value 이하의 최댓값
ceiling(value)
value 이상의 최솟값
rank(value)
value보다 작은 키 개수
select(k)
k번째로 작은 값
predecessor(value)
바로 이전 값 (중위 순회 기준)
successor(value)
바로 다음 값 (중위 순회 기준)
BST <Integer > bst = new BST <>();
bst .insert (5 );
bst .insert (3 );
bst .insert (7 );
bst .insert (1 );
bst .insert (9 );
// 5
// / \
// 3 7
// / \
// 1 9
System .out .println (bst .search (3 )); // true
System .out .println (bst .search (6 )); // false
System .out .println (bst .min ()); // 1
System .out .println (bst .max ()); // 9
BST <Integer > bst = new BST <>();
// 삽입: 5, 3, 7, 1, 4, 6, 9
bst .inorder (); // [1, 3, 4, 5, 6, 7, 9] - 정렬된 순서!
bst .preorder (); // [5, 3, 1, 4, 7, 6, 9]
bst .postorder (); // [1, 4, 3, 6, 9, 7, 5]
bst .levelorder (); // [5, 3, 7, 1, 4, 6, 9]
BST <Integer > bst = new BST <>();
bst .insert (5 );
bst .insert (3 );
bst .insert (7 );
// Case 1: 리프 노드 삭제
bst .delete (3 ); // 3 제거
// Case 2: 자식 하나인 노드 삭제
bst .delete (7 ); // 7 제거, 자식이 있으면 승계
// Case 3: 자식 둘인 노드 삭제
bst .delete (5 ); // 후계자(successor)로 대체
BST <Integer > bst = new BST <>();
// 삽입: 10, 20, 30, 40, 50
bst .floor (25 ); // 20 (25 이하 최대)
bst .ceiling (25 ); // 30 (25 이상 최소)
bst .floor (10 ); // 10
bst .ceiling (50 ); // 50
bst .floor (5 ); // null (없음)
중복 값 허용하지 않음 (Set 시맨틱)
null 값 허용하지 않음
Comparable 구현 또는 Comparator 제공 필요
최악의 경우 (편향 트리) O(n) 성능
class Node <T > {
T value ;
Node <T > left ;
Node <T > right ;
// 선택: Node<T> parent, int size, int height
}
// Case 1: 리프 노드 → 그냥 삭제
// Case 2: 자식 하나 → 자식으로 대체
// Case 3: 자식 둘 → 후계자(오른쪽 서브트리의 최솟값)로 대체
// 재귀 (간결)
Node <T > insert (Node <T > node , T value ) {
if (node == null ) return new Node <>(value );
if (value < node .value )
node .left = insert (node .left , value );
else
node .right = insert (node .right , value );
return node ;
}
// 반복 (스택 오버플로우 방지)
void insert (T value ) {
if (root == null ) { root = new Node <>(value ); return ; }
Node <T > curr = root ;
while (true ) {
if (value < curr .value ) {
if (curr .left == null ) { curr .left = new Node <>(value ); return ; }
curr = curr .left ;
} else {
if (curr .right == null ) { curr .right = new Node <>(value ); return ; }
curr = curr .right ;
}
}
}