힙 (Heap)
한눈에 보기
부모가 자식보다 작거나 크도록 유지되는 완전 이진 트리인 힙을 다룬다. 배열 표현, 상향과 하향 조정, O(n) heapify의 원리, 우선순위 큐와 상위 K개 추출 등 활용까지 정리했다.
최종 업데이트 2026.09.17
힙(Heap)은 부모 노드가 항상 자식 노드보다 크거나(최대 힙) 작도록(최소 힙) 유지되는 완전 이진 트리(complete binary tree) 기반 자료구조다. 힙은 전체를 정렬하지 않고도 최댓값이나 최솟값을 O(1)에 확인하고 O(log n)에 꺼낼 수 있어, 우선순위 큐(priority queue)의 표준 구현체로 쓰인다. 다익스트라(Dijkstra) 최단 경로, 작업 스케줄링, 힙 정렬(heap sort), 상위 K개 추출 문제 등이 모두 힙 위에서 동작한다.
힙 속성과 구조
최소 힙(min heap)은 모든 부모가 자식보다 작거나 같고, 따라서 루트가 전체 최솟값이다. 최대 힙(max heap)은 그 반대다. 주의할 점은 힙이 요구하는 것은 부모 자식 간의 대소 관계뿐이라는 것이다. 형제끼리는 순서가 없고, 왼쪽 부분 트리 전체가 오른쪽보다 작아야 하는 이진 탐색 트리(Binary Search Tree)의 규칙과는 전혀 다르다. 그래서 힙은 "느슨하게 정렬된" 구조라고 불리며, 루트 이외의 특정 값을 찾는 데는 O(n)이 걸린다.
힙은 완전 이진 트리이므로 포인터 없이 배열로 표현한다. 루트를 인덱스 0에 두면 i번 노드의 자식은 2i+1과 2i+2, 부모는 (i-1)/2다. 빈틈없는 배열이라 메모리 효율과 캐시 지역성이 모두 좋다.
핵심 연산의 동작
삽입은 배열 끝, 즉 트리의 마지막 자리에 새 값을 붙인 뒤 부모와 비교해 힙 속성을 어길 때마다 위로 교환하는 상향 조정(sift up)으로 마무리한다. 이동 거리는 최대 트리 높이이므로 O(log n)이다.
최솟값 삭제(최소 힙 기준)는 루트를 꺼내고 마지막 요소를 루트 자리에 올린 뒤, 두 자식 중 더 작은 쪽과 비교해 아래로 내려보내는 하향 조정(sift down)을 반복한다. 역시 O(log n)이다.
정렬되지 않은 배열 전체를 힙으로 만드는 힙 구성(heapify)은 요소를 하나씩 삽입하면 O(n log n)이지만, 마지막 내부 노드부터 거꾸로 하향 조정을 적용하면 O(n)에 끝난다. 아래쪽 노드일수록 이동 거리가 짧아 전체 비용이 선형으로 수렴하기 때문이다.
| 연산 | 시간 복잡도 |
|---|---|
| 최솟값/최댓값 조회(peek) | O(1) |
| 삽입 | O(log n) |
| 루트 삭제(poll) | O(log n) |
| 배열에서 힙 구성(heapify) | O(n) |
| 임의 값 탐색 | O(n) |
코드 예시
다음은 배열 기반 최소 힙의 삽입과 상향 조정을 구현한 자바(Java) 예시다.
class MinHeap {
int[] data = new int[64];
int size = 0;
void push(int x) {
data[size] = x;
int i = size++;
while (i > 0) {
int parent = (i - 1) / 2;
if (data[parent] <= data[i]) break;
int tmp = data[parent];
data[parent] = data[i];
data[i] = tmp;
i = parent;
}
}
int peek() { return data[0]; } // 최솟값, O(1)
}
실무에서는 직접 구현하기보다 자바의 PriorityQueue(기본 최소 힙), 파이썬(Python)의 heapq 모듈처럼 언어가 제공하는 구현을 쓴다.
활용과 비교
힙의 대표 활용은 우선순위 큐다. 운영체제의 작업 스케줄러, 이벤트 시뮬레이션, 다익스트라 알고리즘에서 다음에 처리할 최소 비용 정점을 고르는 데 쓰인다. 상위 K개 추출 문제에서는 크기 K짜리 최소 힙을 유지하면 전체 정렬 O(n log n) 대신 O(n log K)로 해결된다. 두 힙을 함께 쓰면 스트림 데이터의 중앙값을 실시간으로 추적할 수도 있다.
정렬된 배열과 비교하면 선택 기준이 분명해진다. 정렬된 배열은 조회는 빠르지만 삽입이 O(n)이고, 힙은 삽입과 최솟값 삭제가 모두 O(log n)이다. 즉 데이터가 계속 흘러 들어오면서 "가장 우선순위 높은 것"만 반복해서 꺼내야 하는 상황이 힙의 자리다. 반면 전체 정렬 순회나 임의 검색이 필요하면 힙은 적합하지 않다. 힙 정렬은 최대 힙을 구성한 뒤 루트를 배열 끝과 교환하며 줄여 가는 방식으로 O(n log n)을 보장하고 추가 메모리가 필요 없지만, 캐시 효율이 낮아 실무 기본 정렬로는 퀵 정렬 계열이나 팀 정렬(Timsort)이 선호된다.
면접에서 이렇게 물어본다
- 힙과 이진 탐색 트리의 규칙 차이를 설명하고, 힙에서 임의 값 탐색이 느린 이유를 말해 보라.
- 힙을 배열로 표현할 때 부모와 자식의 인덱스 관계를 설명해 보라.
- 힙의 삽입과 삭제 과정을 상향 조정과 하향 조정으로 설명해 보라.
- 배열 전체를 힙으로 만드는 heapify가 O(n)인 이유를 설명해 보라.
- 데이터 스트림에서 상위 K개를 유지하는 방법을 힙으로 설계해 보라.
자료구조에서 같이 읽기
- 배열 (Array)같은 타입의 데이터를 연속 메모리에 저장하는 기본 선형 자료구조인 배열을 다룬다. O(1) 인덱스 접근의 원리, 연산별 시간 복잡도, 동적 배열의 확장과 분할 상환 분석, 캐시 지역성까지 정리했다.
- Array vs ArrayList vs LinkedList배열, ArrayList, LinkedList의 내부 저장 방식과 연산별 시간 복잡도를 비교한다. 캐시 지역성 때문에 실무에서 ArrayList가 유리한 이유와 상황별 선택 기준을 정리했다.
- AVL 트리와 레드 블랙 트리 (AVL Tree & Red-Black Tree)자가 균형 이진 탐색 트리인 AVL 트리와 레드 블랙 트리를 비교한다. 균형 인수와 회전, 탐색과 삽입 비용, TreeMap이 레드 블랙 트리를 쓰는 이유를 정리했다.
- B 트리와 B+ 트리 (B-Tree & B+ Tree)한 노드에 여러 키를 담아 높이를 낮춘 B 트리와 리프에 데이터를 모아 연결한 B+ 트리를 다룬다. 디스크 I/O 최소화 원리와 데이터베이스 인덱스가 B+ 트리를 쓰는 이유를 정리했다.
이 개념, 내 코드에서는 어떻게 물어볼까요
데브핏(DevFit)에 채용공고 URL을 붙여 넣고 레포지토리를 연결하면, 내가 쓴 커밋에서 예상 질문과 어필 포인트를 만듭니다. 하루 10회까지 무료입니다. 합불 판정이나 지원자 랭킹은 만들지 않고, 최종 판단은 사람이 합니다.
공고 넣고 시작하기