코테에서 “트리”로 꼭 알아야 하는 것
1) 트리 기본 성질
- 간선 수 = 노드 수 – 1
- 사이클 없음
- 연결 그래프
- 부모/자식, 루트, 깊이(depth)
CBT(Complete Binary Tree, 완전 이진 트리)
- 왼쪽부터 빈틈없이 채워진 이진 트리
- 높이가 같으면 왼→오른쪽 순으로 채움
- CBT 전체 노드 = 2^(h+1) - 1
왜 중요?
- 배열로 자연스럽게 표현 가능 → parent = i, left = 2i, right = 2i+1
- 힙/세그트리 모두 이 원리로 저장됨.
힙(Heap)
세그먼트 트리
“배열의 특정 구간(L~R)의 값을 빠르게 계산(합/최대/최소 등)하기 위해 배열을 트리 형태로 쪼개서 저장한 자료구조.”
[1~8]
/ \
[1~4] [5~8]
/ \ / \
[1~2] [3~4] [5~6] [7~8]
/ \ / \ ...
[1] [2] [3] [4]
세그먼트 트리 구간 합 찾기
세그먼트 트리가 구간 합을 찾는 방법은 아래 3가지 규칙을 DFS 방식으로 적용하는 것
- 규칙 1 — 완전 불일치 (No Overlap)
- 현재 노드 구간이 query_l ~ query_r와 전혀 겹치지 않으면 → 0 반환
- 규칙 2 — 완전 일치 (Total Overlap)
- 현재 노드 구간 (l, r)이 질문 구간에 완전히 포함되면 → 이 노드의 value 바로 사용
- 규칙 3 — 부분 겹침 (Partial Overlap)
- 완전 불일치도 아니고, 완전 포함도 아니면 → 구간을 절반으로 분할하여 양쪽 값을 더함
구간 합 예시
예: query(2, 8) 구하는 과정은 다음과 같은 판단의 반복이다:
- root(1~8): 완전 포함 → 내려감
- 왼쪽(1~4): 부분 겹침 → 분할
- 오른쪽(5~8): 완전 포함 → 바로 값 사용
- 다시 왼쪽(1~2): 부분 겹침 → 분할
- (1): 완전 불일치 → 0
- (2): 완전 포함 → 8 사용
- (3~4): 완전 포함 → 9 사용
세그먼트 트리 구현
public class SegmentTree {
private int n; // 배열 크기
private long[] tree; // 세그먼트 트리 배열
private long[] arr; // 원본 데이터
public SegmentTree(long[] input) {
this.n = input.length;
this.arr = input.clone();
// 트리 크기는 대략 4배면 충분
tree = new long[n * 4];
build(1, 0, n - 1);
}
/**
* 트리 초기 생성 (Build)
* node: 현재 트리 노드 번호
* start, end: 담당 구간 [start, end]
*/
private void build(int node, int start, int end) {
if (start == end) {
// leaf node → 단일 값 저장
tree[node] = arr[start];
} else {
int mid = (start + end) / 2;
build(node * 2, start, mid); // 왼쪽 자식
build(node * 2 + 1, mid + 1, end); // 오른쪽 자식
// ★ 원하는 연산(sum/min/max)으로 변경
tree[node] = tree[node * 2] + tree[node * 2 + 1]; // SUM
}
}
/**
* 단일 값 업데이트 (point update)
* idx 위치를 val로 변경
*/
public void update(int idx, long val) {
update(1, 0, n - 1, idx, val);
}
private void update(int node, int start, int end, int idx, long val) {
if (start == end) {
// leaf node 갱신
arr[idx] = val;
tree[node] = val;
} else {
int mid = (start + end) / 2;
if (idx <= mid)
update(node * 2, start, mid, idx, val);
else
update(node * 2 + 1, mid + 1, end, idx, val);
// ★ 원하는 연산(sum/min/max)으로 변경
tree[node] = tree[node * 2] + tree[node * 2 + 1]; // SUM
}
}
/**
* 구간 질의 (range query)
* [left, right] 구간의 합/최솟값/최댓값 등 조회
*/
public long query(int left, int right) {
return query(1, 0, n - 1, left, right);
}
private long query(int node, int start, int end, int left, int right) {
// 1) 전혀 겹치지 않는 경우 → identity 반환
// ★ sum = 0, min = INF, max = -INF
if (right < start || end < left)
return 0; // SUM 기준 identity
// 2) 완전히 포함되는 경우
if (left <= start && end <= right)
return tree[node];
// 3) 부분적으로 겹치는 경우 → 두 자식에게 질의 분할
int mid = (start + end) / 2;
long q1 = query(node * 2, start, mid, left, right);
long q2 = query(node * 2 + 1, mid + 1, end, left, right);
// ★ 원하는 연산(sum/min/max)으로 변경
return q1 + q2; // SUM
}
}
Fenwick Tree(BIT)란?
refix Sum(누적합)을 O(log N)으로 빠르게 업데이트하는 데이터 구조.
'개발기술 > 알고리즘, 자료구조, PS' 카테고리의 다른 글
| 코테빈출 SQL 함수정리 (2) | 2025.08.21 |
|---|---|
| 코딩테스트 탐색문제 (DFS,BFS,DP, 그래프) (2) | 2025.01.12 |
| 그래프이론 알고리즘, 자료구조 정리 (2) | 2024.09.18 |
| 정렬 알고리즘 (1) | 2024.08.10 |
| 코딩테스트 빈출유형 풀이법 (0) | 2024.01.21 |