✔ 퀵 정렬(Quick Sort)
퀵 정렬은 분할 정복(divide and conquer) 방법을 통해 정렬하는 알고리즘이다.
간단히 얘기하면, 하나의 원소를 기준으로 기준 앞은 작은 모든 원소들이 오고, 뒤에는 큰 모든 원소들이 오도록
리스트를 둘로 분할하여 정렬하는 방법이다.
정렬하려는 리스트 가운데서 하나의 원소를 고른다. 고른 원소를 Pivot(피벗)이라 부른다.
피벗 기준 앞에서 큰 값을 찾고, 기준 뒤에는 작은 값을 찾아 교환하면서
피벗 앞에는 작은 원소들이 오게 하고 뒤에는 큰 원소들이 오도록 정렬을 진행한다.
분할 정복(divide and conquer)
그대로 해결할 수 없는 문제를 작은 문제로 분할하여 문제를 해결하는 방법
✔ 퀵 정렬 동작 과정
왼쪽 → 오른쪽 순으로 봐주시기 바랍니다.
- 리스트의 중간 값을 Pivot(피벗)으로 선정하고 피벗 기준으로 왼쪽과 오른쪽으로 나뉜다
피벗 기준 왼쪽은 피벗 값보다 작은 값, 오른쪽 피벗 값보다 큰 값이 오도록 진행한다 - left는 첫 번째 원소부터 피벗 값보다 큰 값을 찾을 때까지 증가시켜주며 찾고,
right는 마지막 원소부터 피벗 값보다 작은 값을 찾을 때까지 감소시켜주며 찾는다
찾은 큰 값과 작은 값을 교환해준다 - left, right가 교차하면 새로운 피벗을 선정하고 왼쪽과 오른쪽으로 나뉜다.
- 2번부터 다시 반복하며 정렬을 반복
※ 피벗 값을 선정하는 기준은 첫 번째, 중간, 마지막 원소를 선택할 수 있다. 이 글에서는 중간 값으로 선택했다.
✔ 퀵 정렬 구현(C++)
#include <iostream>
using namespace std;
const int LEN = 7;
int arr[LEN] = {2, 9, 5, 6, 4, 1, 7};
void QuickSort(int *arr, int left, int right) {
int i = left, j = right;
int pivot = arr[(left+right) / 2];
int temp;
while(i <= j) { // 엇갈릴 때까지 반복
while(arr[i] < pivot) i++; // 피벗보다 큰 값을 만날 때까지
while(arr[j] > pivot) j--; // 피벗보다 작은 값을 만날 때까지
if(i <= j) { // 큰 값이 작은 값보다 왼쪽에 있으면
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
// 재귀(recursion)
if(left < j) QuickSort(arr, left, j);
if(i < right) QuickSort(arr, i, right);
}
int main() {
QuickSort(arr, 0, LEN-1);
for(int i : arr)
cout << i << " ";
return 0;
}
✔ 퀵 정렬 시간 복잡도
퀵 정렬의 시간 복잡도는 아래와 같다.
$$ O(NlogN) $$
퀵 정렬의 최악 시간 복잡도는 아래와 같다.
$$ O(N^2) $$
최악의 경우는 정렬하고자 하는 배열이 오름차순, 내림차순으로 정렬된 상태라면 분할이 되지 않아
O(N^2) 시간 복잡도를 가지는데 이를 개선하는 방법으로 중위법을 이용해 분할하는 방법입니다.
위에서 피벗 값을 첫 번째, 중간, 마지막 원소를 선정한다고 했는데 중간을 선택하는 중위법을 이용하여 분할한다.
이 방법을 사용하면 중앙에서 분할될 가능성이 높아 전체적으로 정렬의 성능이 좋아진다.
하지만 반드시, 100%인 보장은 아니다.
시간 복잡도에 대한 좀 더 자세한 내용은 아래의 내용에서 확인하세요.
시간 복잡도
🔗 Reference
'algorithm' 카테고리의 다른 글
스택(Stack) (0) | 2023.04.15 |
---|---|
합병 정렬 알고리즘(Merge Sort) (0) | 2023.01.10 |
삽입 정렬 알고리즘(Insertion Sort) (0) | 2022.11.30 |
버블 정렬 알고리즘(Bubble Sort) (0) | 2022.11.21 |
선택 정렬 알고리즘(Selection Sort) (0) | 2022.11.09 |