빠른 정렬
빠른 정렬은 분할 및 정복 알고리즘의 원리를 기반으로하는 매우 효율적인 정렬 알고리즘입니다. 빠른 정렬은 선택한 피벗 요소를 중심으로 배열을 두 부분으로 분할하여 작동합니다. 작은 요소는 피벗의 왼쪽으로 이동하고 큰 요소는 오른쪽으로 이동합니다. 그런 다음 왼쪽 및 오른쪽 하위 부분이 재귀 적으로 정렬되어 전체 배열을 정렬합니다. 일반적인 정렬 알고리즘보다 약 2
또는 3
배 빠르기 때문에 빠른 정렬이라고합니다. 빠른 정렬은 데이터 구조 내부의 정보 검색 및 수치 계산에 널리 사용됩니다.
빠른 정렬 알고리즘
n
요소를 포함하는 정렬되지 않은 배열A[]
가 있다고 가정 해 보겠습니다. 두 개의 변수beg
와end
를 취한 다음 시작 및 끝 요소의 색인을 저장합니다.
파티션()
-
피벗 요소로 마지막 요소 (구현에 따라 임의 일 수 있음)를 선택합니다.
-
포인터
i
의 값을 ‘beg-1’로 초기화하여 피벗보다 작은 요소를 배열의 시작으로 이동할 수 있도록합니다. -
배열을 반복적으로 탐색하고 각 요소에 대해 다음을 수행합니다.
-
요소
A[i]
<pivot
이i
를 증가시키고A[i]
를A[j]
로 바꿉니다. -
A[i]
를 ‘A[end]‘로 바꾸어 피벗 요소를 올바른 위치에 놓습니다. -
피벗 요소의 인덱스를 반환합니다.
QuickSort()
-
피벗 인덱스
pi
를 선택합니다. -
피벗 인덱스를 중심으로 배열을 분할합니다.
-
피벗 요소의 왼쪽
arr[beg, ..., pi]
에서 요소를 재귀 적으로 정렬합니다. -
피벗 요소의 오른쪽
arr[pi + 1, ..., end]
에서 요소를 재귀 적으로 정렬합니다.
빠른 정렬 예
배열이(6,5,1,4,2,3)
이라고 가정합니다. 빠른 정렬 알고리즘을 사용하여 정렬합니다.
-
첫 번째
3
이 피벗 요소로 선택되고 배열은 두 개의 하위 부분(1,2)
-작은 요소 및(6,5,4)
-큰 요소로 분할됩니다. 그리고3
이 정렬 된 위치에 놓입니다. 형성된 두 개의 하위 배열은 재귀 적으로 정렬됩니다. -
하위 배열의 경우
(1,2)
의 경우,2
가 pivot 요소로 선택되고 올바른 위치에 놓이고 이미 정렬 된 subarray(1)
이 형성됩니다. -
하위 배열의 경우
(6,5,4)
의 경우4
가 정렬 된 위치에 놓이고 하위 배열의 경우(6,5)
가 생성 된 후 재귀 적으로 정렬됩니다. -
하위 배열
(6,5)
의 경우5
를 피벗으로 선택하고 올바른 위치에 놓으면(6)
이 새 하위 배열로 제공됩니다. 단일 요소 하위 배열(6)
이 이미 정렬되었습니다. -
마지막으로 정렬 된 배열을
(1, 2, 3, 4, 5, 6)
로 얻습니다.
빠른 정렬 알고리즘 구현
#include <bits/stdc++.h>
using namespace std;
int partition(int arr[], int beg, int end) {
// Select the last element as pivot element
int pivot = arr[end];
int i = (beg - 1);
// Move smaller elements to left side and larger on right side
for (int j = beg; j < end; j++) {
if (arr[j] <= pivot) {
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1],
arr[end]); // Move pivot element to its right position in array
return (i + 1);
}
void quickSort(int arr[], int beg, int end) {
if (beg < end) {
int pi = partition(arr, beg, end);
quickSort(arr, beg,
pi - 1); // Recursive Sort element on left side of partition
quickSort(arr, pi + 1,
end); // Recursive Sort element on right side of partition
}
}
int main() {
int n = 6;
int arr[6] = {5, 3, 4, 2, 1, 6};
cout << "Input array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << "\n";
quickSort(arr, 0, n - 1); // Sort elements in ascending order
cout << "Output array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << "\n";
}
빠른 정렬 알고리즘 복잡성
시간 복잡성
- 평균 사례
빠른 정렬에 걸리는 시간은 다음과 같은 반복 관계로 지정됩니다.
T(n) = T(k) + T(n-k-1) + θ(n)
여기서 k
는 피벗 요소보다 작거나 큰 요소의 수를 나타냅니다.
이 반복 관계의 결과는T(n) = nLogn
을 제공합니다. 평균 케이스는 무작위로 균형이 맞지 않는 파티션을 얻을 때 발생합니다. 시간 복잡도는 [Big Theta] :O(nLogn)
의 순서입니다.
- 최악의 경우
T(n) = T(n-1) + θ(n)
최악의 경우는 피벗 요소가 항상 배열의 가장 큰 요소이거나 가장 작은 요소 일 때 발생합니다. 이 경우 모든 요소가 하나의 하위 배열에 속하고 최대 n
호출이 이루어져야합니다. 최악의 경우 시간 복잡도는 [Big O] : O(n2)입니다.
- 베스트 케이스
T(n) = 2T(n/2) + θ(n)
가장 좋은 경우는 선택한 피벗 요소가 항상 중간 요소이거나 두 파티션이 균등하게 균형을 이루는 경우 (예 : 크기 차이가 1
이하인 경우)입니다. 최적의 시간 복잡도는 [Big Omega] :O(nLogn)
입니다.
공간 복잡성
빠른 정렬 알고리즘의 평균 케이스 공간 복잡도는 O(Logn)
입니다. 재귀 스택에 필요한 공간입니다. 그러나 배열을 정렬하는 데 n
재귀가 필요한 최악의 경우 공간 복잡성은 O(n)
입니다.
Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.
LinkedIn