Insertion Sort
정의
Insertion Sort (삽입 정렬) 는 한 번에 한 원소씩 이미 정렬된 부분에 올바른 위치를 찾아 삽입 하는 정렬. 카드 정리하듯이 한 장씩 적절한 자리에 끼워넣는 동작.
O(n²) 알고리즘 중 실측 가장 빠르다. 작은 입력 (n ≤ 16) 이나 거의 정렬된 입력에서 Quick Sort 같은 O(n log n) 알고리즘보다도 빠를 수 있다. 그래서 Timsort, Introsort, Pdqsort 가 부분 정렬에 모두 Insertion Sort 를 사용한다.
전체 비교는 정렬 알고리즘 참고.
시각화
알고리즘
insertionSort(arr):
for i = 1 to n-1:
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j] // 한 칸씩 오른쪽으로 밀기
j--
arr[j + 1] = key // 빈 자리에 삽입
핵심 동작
배열 앞부분이 이미 정렬된 영역, 나머지가 미처리 영역. 미처리에서 하나씩 꺼내 정렬된 영역의 올바른 위치에 삽입.
[ 정렬됨 | 미처리 ]
[ 5 | 2, 8, 1, 4 ] 초기
[ 2, 5 | 8, 1, 4 ] 2 를 5 앞에 삽입
[ 2, 5, 8 | 1, 4 ] 8 은 이미 5 보다 큼, 그 자리에
[ 1, 2, 5, 8 | 4 ] 1 을 맨 앞으로
[ 1, 2, 4, 5, 8 | ] 4 를 5 앞에 삽입
매 단계에서 정렬된 영역이 정확히 정렬 상태를 유지.
복잡도
| 항목 | 값 |
|---|---|
| 시간 (최선) | O(n) (이미 정렬됨) |
| 시간 (평균) | O(n²) |
| 시간 (최악) | O(n²) (역순 입력) |
| 공간 | O(1) |
| 안정성 | ✓ Stable |
| In-place | ✓ |
| Online | ✓ (한 번에 한 원소씩 처리 가능) |
왜 O(n²) 중 가장 빠른가
- 상수항 작음: inner loop 가 단순한 비교 + 이동 한 번
- 캐시 친화: 인접 메모리 접근만
- 거의 정렬된 입력에 O(n) 에 가깝게 동작
- 분기 예측 친화적: 조건이 단순
정렬된 부분의 활용
Insertion Sort 의 최대 장점은 입력의 부분적 정렬을 직접 활용 한다는 것.
const nearSorted = [1, 2, 3, 5, 4, 6, 7, 8, 9];
// 5, 4 만 어긋남
// insertion sort: 4 를 한 칸 이동 → 1 swap, 끝
// O(n) 실측
이 성질이 Timsort (Python sorted, Java Arrays.sort) 의 기반:
- 입력에서 자연스러운 run (정렬된 부분) 식별
- 짧은 run 은 Insertion Sort 로 길이 맞춤
- run 들을 Merge Sort 로 합침
하이브리드 알고리즘에서의 역할
| 알고리즘 | Insertion Sort 사용 시점 |
|---|---|
| Timsort | 짧은 run 정렬 (n < 64) |
Introsort (C++ std::sort) | 작은 부분 (n ≤ 16) |
| Pdqsort (Rust) | 작은 부분 |
| Dual-Pivot QS (Java) | 작은 부분 |
IMPORTANT
n 이 작을 때는 O(n²) 가 O(n log n) 보다 빠르다. 상수항이 결정적. n=20 에서 Insertion 의 비교 횟수 (~200) 가 Quick 의 함수 호출 오버헤드보다 적다.
Binary Insertion Sort
삽입 위치를 이진 탐색 으로 찾음. 비교 횟수는 O(n log n) 이지만 이동 횟수는 여전히 O(n²). 비교 비용이 비싼 경우 (예: 긴 문자열) 에 유리.
일반: O(n) 비교 × O(n) = O(n²)
이진: O(log n) 비교 × O(n) = O(n log n) 비교
O(n) 이동 × O(n) = O(n²) 이동
총 비용은 여전히 O(n²) 지만 비교 횟수가 줄어든다.
Bubble / Selection 과의 비교
| 항목 | Insertion | Bubble | Selection |
|---|---|---|---|
| 실측 속도 | 가장 빠름 | 가장 느림 | 중간 |
| 안정성 | ✓ | ✓ | ✗ |
| 거의 정렬된 입력 | O(n) | O(n) (early exit) | O(n²) |
| 비교 횟수 | O(n²) | O(n²) | O(n²) |
| 교환 횟수 | O(n²) | O(n²) | O(n) |
실무 활용 (의외로 자주)
Insertion Sort 자체로는 작은 입력에 한정되지만, 하이브리드 알고리즘의 부속품 으로 거의 모든 표준 라이브러리에 들어가 있다.
- Python
sorted(),list.sort()→ Timsort 내부 - Java
Arrays.sort()(객체) → Timsort 내부 - C++
std::sort→ Introsort 내부 (n ≤ 16 에서) - Rust
slice::sort_unstable→ Pdqsort 내부
n=8 같은 작은 배열을 정렬할 일이 있으면 Insertion Sort 가 올바른 선택.
참고
- 정렬 알고리즘
- Bubble Sort
- Selection Sort
- Merge Sort
- Quick Sort
- Knuth, TAOCP Vol. 3 §5.2.1
이 글의 용어 (5개)
- 정렬 알고리즘algorithm
- 정의 정렬 (sort) 은 원소들의 컬렉션을 어떤 전순서 (total order) 기준으로 재배열하는 것. 알고리즘 입문의 정석 주제이자, 데이터베이스·검색·통계 등 모든 시스템…
- Bubble Sortalgorithm
- 정의 Bubble Sort (버블 정렬) 는 인접한 두 원소를 비교해 잘못된 순서면 교환하는 작업을 배열을 통과하며 반복하는 정렬. 한 번의 통과 (pass) 마다 가장 큰 원소…
- Merge Sortalgorithm
- 정의 Merge Sort (병합 정렬) 는 분할 정복 (Divide & Conquer) 으로 동작하는 비교 정렬. 배열을 반으로 나눠 각각 정렬한 뒤, 두 정렬된 부분을 병합 (…
- Quick Sortalgorithm
- 정의 Quick Sort (퀵 정렬) 는 분할 정복 (Divide & Conquer) 기반 비교 정렬. 1959 년 Tony Hoare 가 고안. 배열에서 pivot 을 하나 골…
- Selection Sortalgorithm
- 정의 Selection Sort (선택 정렬) 는 매 단계에서 남은 원소 중 최솟값을 찾아 맨 앞으로 보내는 정렬. n-1 번의 단계 후 정렬 완료. 다른 O(n²) 정렬과 달리…
💬 댓글