Sorting (2)
1. Merge Sort (병합 정렬)
:분할 정복(Divide & Conquer)알고리즘
배열을 반으로 계속 나누어 길이가 1인 배열들로 쪼갠 뒤, 두 정렬된 부분을 병합(merge) 하여 정렬된 전체를 만든다.
과정 (예: [5,2,4,1,3])
- 분할:
[5,2,4,1,3] → [5,2], [4,1,3]
[5,2] → [5], [2]
[4,1,3] → [4], [1,3] → [1], [3] - 정복(병합):
[5] + [2] → [2,5]
[1] + [3] → [1,3]
[4] + [1,3] → [1,3,4] (병합 시 비교로 정렬 유지)
[2,5] + [1,3,4] → [1,2,3,4,5]
각 단계에서 항상 두 부분배열의 첫 원소를 비교해 작은 값을 새 배열에 담으므로,
같은 값이 나오면 앞쪽 배열의 값이 먼저 들어가 안정성(stability) 이 유지된다.
코드
MergeSort(A, l, r):
if l >= r: return
m = (l + r) / 2
MergeSort(A, l, m)
MergeSort(A, m+1, r)
Merge(A, l, m, r)
Merge(A, l, m, r):
create temp array T
i = l, j = m+1, k = 0
while i <= m and j <= r:
if A[i] <= A[j]: T[k++] = A[i++]
else: T[k++] = A[j++]
copy remaining elements from left or right into T
copy T back to A[l..r]
시간·공간 복잡도
| 최선 | O(n log n) |
| 평균 | O(n log n) |
| 최악 | O(n log n) |
| 공간 | O(n) (보조 배열 필요) |
| 안정성 | 안정 (stable) |
장단점
- 장점: 성능 예측 가능, 안정성, 외부정렬(디스크 기반) 적합, 대규모 데이터에서도 예측 가능 성능
- 단점: 추가 메모리 필요(O(n)), 재귀 오버헤드(스택 깊이 O(log n)), 작은 배열에서는 삽입 정렬보다 느림
2. Heap Sort (힙 정렬)
완전 이진 트리(Heap)를 배열로 표현하고 힙 속성(max-heap 또는 min-heap) 을 이용해 정렬.
보통 max-heap을 만든 뒤 루트(최대값)를 맨 끝으로 보내고, 힙 크기를 줄이며 다시 heapify 하는 방식으로 오름차순 정렬을 구현
== 가장 큰 값을 계속 꺼내 뒤에 쌓아 가는 방식
과정 (예: [5,2,4,1,3], max-heap 사용)
- Build-Max-Heap: 배열을 재배치하여 max-heap으로 만듦.
- 결과(힙 배열): 예 [5,3,4,1,2] (구체는 힙화 방식에 따라 다름)
- 반복:
- 루트(최댓값)와 마지막 원소를 swap. (최댓값을 정렬 영역 끝에 고정)
- 힙 크기 감소(마지막 원소를 힙에서 제거한 것처럼 처리).
- 루트에서부터 heapify-down 하여 다시 max-heap 복원.
- 이 과정을 모든 원소가 제자리로 갈 때까지 반복. 모든 원소가 정렬 영역으로 이동하면 완료.
코드
heapSort(A):
n = length(A)
// build max heap
for i = floor(n/2)-1 down to 0:
heapify(A, n, i)
// extract elements
for i = n-1 down to 1:
swap(A[0], A[i])
heapify(A, i, 0) // heap size reduced by 1
시간·공간 복잡도
| Build Heap | O(n) |
| 추출 단계 | O(n log n) |
| 전체 | O(n log n) |
| 공간 | O(1) (in-place) |
| 안정성 | 불안정 (unstable) |
장단점
- 장점: 추가 메모리 거의 없음(in-place), 최악시간 보장 O(n log n)
- 단점: 불안정, 캐시 효율이 좋지 않아 실제 성능이 퀵 정렬보다 떨어질 수 있음, 구현이 병렬화에 덜 유리
정리하자면,
| 알고리즘 | 평균 | 최악 | 최선 | 안정성 | 특징 |
| Bubble | O(n²) | O(n²) | O(1) | 안정 | 교육용, 거의 정렬된 경우 유리 |
| Selection | O(n²) | O(n²) | O(1) | 불안정 | swap 횟수 적음 |
| Insertion | O(n²) | O(n²) | O(1) | 안정 | 거의 정렬됨에서 매우 빠름 |
| Quick (일반 최적화) | O(n log n) | O(n²) | O(log n) avg | 불안정 | 평균 최강, 캐시 친화적 |
| Merge | O(n log n) | O(n log n) | O(n) | 안정 | 외부 정렬에 적합, 안정성 필요 시 선택 |
| Heap | O(n log n) | O(n log n) | O(1) | 불안정 | in-place, 메모리 제한 시 유리 |
- 큰 일반적 데이터: 최적화된 Quicksort 가 보통 가장 빠름(캐시, 상수요인 우수). 다만 최악 케이스 대비 안전성이 필요하면 Merge Sort 또는 Introsort(퀵+힙 혼합) 사용.
- 안정성 필요: Merge Sort 사용. (예: 레코드 정렬에서 동일 키의 상대 순서 유지 필요할 때)
- 메모리 제한: Heap Sort가 추가 공간 거의 없음으로 유리.
- 거의 정렬된 데이터: Insertion Sort가 매우 빠름(실무에서는 작은 블록에 삽입 정렬을 적용).
- 외부 정렬(데이터가 디스크에 크고 메모리에 안 들어갈 때): Merge Sort 기반의 외부 병합 정렬을 사용.
'이론공부 > 자료구조, 알고리즘' 카테고리의 다른 글
| 8. Hashing (0) | 2025.11.13 |
|---|---|
| 7. Sorting (3) (0) | 2025.11.12 |
| 7. Sorting (1) (0) | 2025.11.11 |
| 6. Graph (3) - Shortest Path (0) | 2025.11.11 |
| 6. Graph (2) (0) | 2025.11.10 |