-
정렬 알고리즘 (4): 퀵 정렬 (Quick Sort)알고리즘 2025. 2. 13. 16:00
1. 퀵 정렬이란?
퀵 정렬(Quick Sort)은 "분할 정복(Divide and Conquer)" 기법을 활용하여 리스트를 정렬하는 효율적인 알고리즘이다. 평균적으로 O(n log n)의 성능을 가지며, 대부분의 경우 매우 빠르게 동작하기 때문에 실무에서 널리 사용된다.
2. 퀵 정렬의 동작 원리
퀵 정렬은 피벗(Pivot) 요소를 선택하고, 피벗보다 작은 요소는 왼쪽으로, 큰 요소는 오른쪽으로 이동시키는 분할 과정을 반복하여 정렬을 수행한다.
2.1 정렬 과정
- 배열에서 피벗(Pivot)을 선택한다.
- 피벗을 기준으로 작은 값과 큰 값을 좌우로 분할(Partitioning)한다.
- 분할된 두 개의 하위 배열을 재귀적으로 정렬한다.
- 모든 하위 배열이 정렬되면 최종적으로 정렬이 완료된다.
2.2 Partition 함수 설명
Partition 함수는 배열을 피벗을 기준으로 나누는 핵심 기능을 담당한다. 이 과정에서 피벗보다 작은 값은 왼쪽, 큰 값은 오른쪽으로 이동하여 피벗이 올바른 위치에 놓이도록 한다.
Partition 함수는 다음과 같은 방식으로 동작한다:
- 피벗을 배열의 마지막 요소로 선택한다.
- i 변수를 low - 1로 설정하여, 피벗보다 작은 요소들이 위치할 곳을 추적한다.
- j 변수를 low부터 high - 1까지 반복하면서 피벗보다 작은 요소를 찾으면 i를 증가시키고 해당 요소와 교환한다.
- 반복이 끝난 후, 피벗을 i+1 위치와 교환하여 피벗이 최종적으로 올바른 위치에 오도록 한다.
- 피벗의 최종 위치를 반환하여 재귀적으로 퀵 정렬을 수행할 수 있도록 한다.
2.3 예제 코드 (Java)
public class QuickSort { // 퀵 정렬 메서드 public static void quickSort(int[] arr, int low, int high) { if (low < high) { int pivotIndex = partition(arr, low, high); quickSort(arr, low, pivotIndex - 1); // 왼쪽 부분 정렬 quickSort(arr, pivotIndex + 1, high); // 오른쪽 부분 정렬 } } // 피벗을 기준으로 배열을 분할하는 메서드 private static int partition(int[] arr, int low, int high) { int pivot = arr[high]; // 마지막 요소를 피벗으로 선택 int i = low - 1; for (int j = low; j < high; j++) { if (arr[j] < pivot) { // 피벗보다 작은 값이면 i++; swap(arr, i, j); } } swap(arr, i + 1, high); // 피벗을 최종 위치로 이동 return i + 1; } // 두 요소를 교환하는 메서드 private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } // 퀵 정렬 실행 및 결과 출력 public static void main(String[] args) { int[] data = {64, 34, 25, 12, 22, 11, 90}; System.out.println("정렬 전: "); for (int num : data) { System.out.print(num + " "); } quickSort(data, 0, data.length - 1); System.out.println("\n정렬 후: "); for (int num : data) { System.out.print(num + " "); } } }
3. 퀵 정렬의 성능 분석
퀵 정렬의 시간 및 공간 복잡도를 분석하면 다음과 같다.
3.1 시간 복잡도
- 최선의 경우 (Best Case): O(n log n) → 균형 잡힌 분할이 이루어진 경우
- 평균의 경우 (Average Case): O(n log n)
- 최악의 경우 (Worst Case): O(n²) → 이미 정렬된 배열에서 피벗을 가장 작은 또는 큰 값으로 선택할 경우
퀵 정렬의 평균 성능은 O(n log n)이지만, 피벗 선택 방식에 따라 성능이 좌우된다.
3.2 공간 복잡도
- 공간 복잡도: O(log n) → 재귀 호출로 인해 스택 메모리를 사용
4. 퀵 정렬의 장점과 단점
4.1 장점
- 평균적으로 매우 빠른 성능 (O(n log n))
- 비교적 적은 메모리 사용 (In-place 정렬)
- 다양한 피벗 선택 전략을 활용하여 최적화 가능
4.2 단점
- 최악의 경우 O(n²)로 성능이 저하될 수 있음
- 재귀 호출로 인해 스택 오버플로우 가능성 있음
- 안정 정렬(Stable Sort)이 아님 (같은 값의 순서가 바뀔 수 있음)
5. 퀵 정렬의 활용 및 개선 방법
5.1 활용 사례
- 데이터가 큰 경우 빠른 정렬이 필요할 때
- 정렬이 자주 발생하는 대규모 시스템 (데이터베이스, 검색 엔진 등)
5.2 개선 방법
- 랜덤 피벗 선택(Randomized Quick Sort): 피벗을 랜덤하게 선택하여 최악의 경우를 방지
- 중앙값 피벗 선택(Median-of-Three): 첫 번째, 중간, 마지막 요소 중 중간값을 피벗으로 선택하여 성능 개선
- 혼합 정렬(Hybrid Sort): 작은 배열에서는 삽입 정렬을 사용하여 성능 향상
6. 결론
퀵 정렬은 평균적으로 O(n log n)의 성능을 가지며, 대부분의 상황에서 효율적인 정렬 알고리즘이다. 하지만 최악의 경우 O(n²)으로 성능이 저하될 수 있어 피벗 선택 전략을 적절히 활용하는 것이 중요하다. 대규모 데이터 정렬이 필요한 경우 퀵 정렬을 최적화하여 활용하면 높은 성능을 얻을 수 있다.
'알고리즘' 카테고리의 다른 글
정렬 알고리즘 (6): 힙 정렬 (Heap Sort) (0) 2025.02.17 정렬 알고리즘 (5): 병합 정렬 (Merge Sort) (0) 2025.02.14 정렬 알고리즘 (3): 선택 정렬 (Selection Sort) (0) 2025.02.12 정렬 알고리즘 (2): 삽입 정렬 (Insertion Sort) (1) 2025.02.11 정렬 알고리즘 (1): 버블 정렬 (Bubble Sort) (1) 2025.02.10