퀵정렬(quick_sort)
퀵정렬(quick_sort)
퀵정렬
- 분할 정복 알고리즘의 하나로 평균적으로 매우 빠른 속도를 가진다.
- 퀵정렬은 데이터를 메모리상에서 이동시키면서 정렬하기 때문에 CPU 캐시의 효율을 높일 수 있다.
작동원리
1. 분할(divide)
배열 안에서 pivot이라 불리는 기준 원소를 하나 선택한다. 이 pivot을 기준으로 두 개의 부분 배열로 나눈다.
pivot보다 작은 부분, pivot보다 큰 부분
2. 정복(conquer)
분할된 두 개의 부분 배열에 대해 재귀적으로 퀵정렬을 호출한다. 부분 배열의 크기가 0 또는 1이 될 때까지 수행한다.
3. 결합(combine)
퀵정렬은 정렬 과정 중에 자동으로 결합이 이루어진다. 각 부분 배열이 정렬되면 전체 배열 또한 정렬이 완성된다.
pivot을 어떻게 정하냐에 따라 성능 차이가 발생할 수 있다.
맨 처음 원소 사용 or 맨 마지막 원소 사용 or 중간 원소 사용 or 3개의 중앙값
장단점
장점
빠른 평균 속도: 대부분의 경우 $O(N \log N)$의 시간복잡도를 보이며 매우 빠르게 동작한다.
추가 메모리 공간 불필요(In-place): 데이터를 정렬할 때 거의 추가적인 메모리 공간을 사용하지 않아 공간 효율성이 뛰어나다. (재귀 호출을 위한 스택 공간은 필요하다.)
단점
최악의 경우 성능 저하: 이미 정렬된 배열이나 역으로 정렬된 배열을 정렬할 경우, 피벗 선택이 항상 가장 크거나 작은 값으로 이루어져 $O(N^2)$의 시간 복잡도를 가질 수 있다.
불안정 정렬(Unstable Sort): 동일한 값을 가진 원소들의 상대적인 순서가 정렬 후에도 유지되지 않을 수 있다.
예시 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <algorithm>
using namespace std;
int arr[6] = {1, 3, 2, 5, 6, 4};
void partition(int low, int high, int pivot) {
int j = low;
for (int i = low; i <= high; i++) {
if (arr[i] < arr[pivot]) {
j++;
swap(arr[i], arr[j]);
}
}
swap(arr[low], arr[j]);
}
void quickSort(int low, int high) {
int pivot = low;
if (low < high) {
partition(low, high, pivot);
quickSort(low, pivot - 1);
quickSort(pivot + 1, high);
}
}
int main() {
quickSort(0, 5);
for (int i = 0; i < 6; i++) {
cout << arr[i] << " ";
}
return 0;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
