Sorting
: 데이터를 특정 기준에 따라 순서대로 배치하는 과정
검색 효율을 높이거나 데이터 분석 전 처리 과정에서 자주 사용됨.
1. Bubble Sort (버블 정렬)
인접한 두 원소를 비교해 큰 값을 뒤로(또는 작은 값을 앞으로) 반복적으로 이동시켜서 정렬함. 한 번의 전체 패스(pass)를 돌면 가장 큰(또는 작은) 값이 끝으로 확정됨 → “거품이 올라오는” 모습에서 이름 유래.
과정 (예: [5, 2, 4, 1])
| [5, 2, 4, 1] 패스1: |
비교(5,2) | swap | [2,5,4,1] |
| 비교(5,4) | swap | [2,4,5,1] | |
| 비교(5,1) | swap | [2,4,1,5] (가장 큰 5가 끝에 위치) | |
| [2,4,1,5] 패스2: |
비교(2,4) | no swap | [2,4,1,5] |
| 비교(4,1) | swap | [2,1,4,5] | |
| 패스3: | 비교(2,1) | swap | [1,2,4,5] |
| 패스4: | [1,2,4,5] | 이미 정렬됨, 종료 | |
특징
- 한 번의 순회가 끝날 때마다 가장 큰 값이 맨 끝에 고정됨
- 총 n-1번 반복
- 최적화: 더 이상 교환이 없을 경우 반복 종료 가능
- 안정성 높으나 데이터가 클 경우 비효율적임.
시간복잡도
- 최악: O(n²)
- 평균: O(n²)
- 최선: O(n) (이미 정렬된 경우)
비교 및 교환 횟수
- 비교: n(n-1)/2
- 교환: 많음 (효율 낮음)
코드)
for i = 0 to n-2:
for j = 0 to n-2-i:
if A[j] > A[j+1]: swap(A[j], A[j+1])
최적화 (Early exit)
한 패스에서 swap이 없으면 이미 정렬된 상태이므로 종료하도록 설정하기
void bubbleSort(int a[], int n) {
int i, j, temp;
int swapped; // 교환 여부 플래그
for (i = 0; i < n - 1; i++) {
swapped = 0; // 이번 패스에서 교환이 있었는지 체크
for (j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
swapped = 1;
}
}
if (swapped == 0) break; // 교환이 없으면 종료
}
}
2. Selection Sort (선택 정렬)
: 매 단계에서 남은 원소들 중 최소(또는 최대)를 찾아서 정해진 위치로 옮김.
선택 과정은 전체 남은 부분을 스캔해야 함.
과정 (예: [5, 2, 4, 1])
| 단계 | 최소 숫자 | 동작 |
| i = 0 | 1 | swap A[0], A[index(1)] → [1,2,4,5] |
| i = 1 | 2 | 이미 제자리에 있음 |
| i = 2 | 4 | 이미 제자리에 있음 |
특징
- 한 번의 순회가 끝날 때마다 가장 큰 값이 맨 끝에 고정됨
- 총 n-1번 반복
- 최적화: 더 이상 교환이 없을 경우 반복 종료 가능
- 안정성 높으나 데이터가 클 경우 비효율적임.
시간복잡도
- 최선, 최악 평균 모두 : O(n²)
- 평균: O(n²)
- 최선: O(n) (이미 정렬된 경우)
비교 및 교환 횟수
- 비교: n(n-1)/2
- 교환: 많음 (효율 낮음)
특징
- 정렬된 부분과 정렬되지 않은 부분으로 나뉨
- 매번 최솟값을 찾아서 왼쪽으로 보냄
- 일반적으로는 퀵/힙/병합 정렬에 비해 느림.
- 불안정(unstable) — 동일한 값이 있을 때 상대 순서가 바뀔 수 있음(최솟값을 swap할 때).
시간 ·공간 복잡도
- 최선, 최악 평균 모두 : O(n²)
- 항상 전체를 순회해야 하므로 상황에 관계없이 동일함
- 공간: O(1) (in-place)
비교 및 교환 횟수
- 교환(swap) 횟수가 O(n)으로 적음(매 단계 1번 swap)
- == 메모리 교체 비용이 높은 상황에 유리할 때 생각해볼 수 있음
코드)
for i = 0 to n-2:
minIdx = i
for j = i+1 to n-1:
if A[j] < A[minIdx]: minIdx = j
swap(A[i], A[minIdx])
3. Insertion Sort (삽입 정렬)
: 배열을 정렬된 부분과 비정렬된 부분으로 나누고, 비정렬된 원소를 하나씩 꺼내 적절한 위치에 삽입함
카드로 손의 패를 정렬하는 과정과 유사.
과정 (예: [5, 2, 4, 1])
| 단계 | key | 동작 |
| i = 1 | 2 | 비교 5>2 → shift → [_,5,4,1], insert 2 → [2,5,4,1] |
| i = 2 | 4 | 비교 5>4 → shift → [2,_,5,1], insert 4 → [2,4,5,1] |
| i = 3 | 1 | shift 5,4,2 → [_,2,4,5], insert 1 → [1,2,4,5] |
특징
- 데이터가 거의 정렬된 상태일 때 매우 빠름
- 실제로 많은 정렬 알고리즘의 내부에서 사용됨 (ex. QuickSort의 작은 구간 정렬)
- 안정적(stable) — 같은 값이 들어오면 원래 순서 유지
- Binary insertion: 삽입 위치를 이진 검색으로 찾으면 비교 횟수는 줄지만, 이동(shift)은 여전히 O(n) → 전체 O(n²) 유지.
- 작은 배열 최적화: 퀵/병합 정렬과 함께 작은 청크(예: 길이 ≤ 16)는 삽입 정렬로 처리하는 것이 빠름.
시간 ·공간 복잡도
- 시간: 최악 O(n²), 평균 O(n²), 최선 O(n) (이미 정렬된 경우, 비교만 O(n))
- 공간: O(1) (in-place)
코드)
for i = 1 to n-1:
key = A[i]
j = i-1
while j >= 0 and A[j] > key:
A[j+1] = A[j] // shift
j = j-1
A[j+1] = key
4. Quick Sort (퀵 정렬) — 개념 및 O(n²) 관련 설명
하나의 피벗(pivot) 을 선택하고, 배열을 피벗보다 작거나 같은 것 왼쪽, 큰 것 오른쪽으로 분할(partition) 한다. 그런 다음 좌우 부분 배열을 재귀적으로 정렬함. 분할이 균형 잡히면 O(n log n), 매우 치우치면 O(n²).
- 기준이 되는 pivot 값을 선택함
- pivot보다 작은 값은 왼쪽, 큰 값은 오른쪽으로 분할
- 분할된 부분 배열에 대해 재귀적으로 동일 과정 수행
과정 (예: [5, 2, 4, 1])
pivot = 2
왼쪽 [1], 오른쪽 [4, 5]
[1] + [2] + [4, 5]
특징
- 비교적 빠른 정렬 알고리즘
- 분할 정복(Divide and Conquer) 기반
- 재귀적 접근
- 피벗 선택이 성능에 큰 영향을 줌
- 일반 구현은 불안정(unstable)
피벗 선택 전략(성능에 큰 영향)
- 항상 첫/마지막 원소: 이미 정렬된 데이터에서 최악(편향) 발생 → O(n²)
- 중앙값(median-of-three): 세 요소(첫, 중간, 마지막)의 중앙값 선택 → 편향 완화
- 랜덤 피벗: 무작위 선택 → 평균적으로 O(n log n), 최악 확률 낮춤
- median of medians: 이론상 좋은 중간값 선택(복잡도 높음)
시간 ·공간 복잡도
- 평균: O(n log n)
- 최악: O(n²) (이미 정렬되었거나 편향된 피벗 선택)
- 공간: 평균 O(log n) 재귀 깊이(스택), 최악 O(n) (편향시)
코드)
quickSort(a, left, right) {
if (left < right) {
pivot = a[left];
i = left; j = right + 1;
do {
do i++; while (a[i] < pivot);
do j--; while (a[j] > pivot);
if (i < j) swap(a[i], a[j]);
} while (i < j);
swap(a[left], a[j]);
quickSort(a, left, j-1);
quickSort(a, j+1, right);
}
}
정리하자면
| 알고리즘 | 최선 | 평균 | 최악 | 특징 |
| Bubble Sort | O(n) | O(n²) | O(n²) | 구현 쉬움, 교환 많음 |
| Selection Sort | O(n²) | O(n²) | O(n²) | 교환 적음, 느림 |
| Insertion Sort | O(n) | O(n²) | O(n²) | 거의 정렬된 데이터에 빠름 |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | 평균적으로 가장 빠름 |
'이론공부 > 자료구조, 알고리즘' 카테고리의 다른 글
| 7. Sorting (3) (0) | 2025.11.12 |
|---|---|
| 7. Sorting (2) (0) | 2025.11.12 |
| 6. Graph (3) - Shortest Path (0) | 2025.11.11 |
| 6. Graph (2) (0) | 2025.11.10 |
| 6. Graph (1) (0) | 2025.11.10 |