목차
퀵 정렬이란?
퀵 정렬은 분할 정복 (Divide and Conquer)과 재귀 방식을 이용한 정렬 알고리즘이다. 분할 정복이란 문제를 작은 2개의 문제로 분리하고 각각을 해결한 다음, 결과를 모아서 원래의 문제를 해결하는 방식이다.
퀵 정렬에서는 pivot이라는 기준을 하나 정하고, 왼쪽은 기준보다 작은 값, 그리고 더 큰 값은 기준 오른쪽으로 옮기면서 배열을 둘로 분할한 후 정렬한다. 보통 pivot은 맨 앞이나 맨 뒤, 혹은 중간에 위치한 값을 선택한다.
퀵 정렬 과정
- 배열 맨 앞에 있는 수를 pivot으로 설정한다. 그리고 배열의 길이가 n일 때, 배열의 시작점은 0이 되고 도착점은 n - 1이 된다.
 - pivot 값을 기준으로 시작점에서부터 검사해서 큰 값을, 도착점에서부터 작은 값을 찾는다.
 - 두 값을 바꾸고, 같은 과정을 수행한다
 - 큰 값의 index와 작은 값의 index가 교차하는 경우, 작은 값과 pivot 값을 바꾼다. 이렇게 하면 pivot 값을 기준으로 왼쪽은 pivot보다 작은 값들, 오른쪽은 큰 값들로 분할된다
 - 분할된 영역에서 맨 앞에 있는 수를 pivot으로 설정하고 같은 과정을 수행한다
 
이제 퀵 정렬 예시를 한번 살펴보겠다.



소스 코드
import java.io.*;
import java.util.*;
public class Main {
   static int number = 10;  //데이터의 개수
   static int[] arr = {1, 10, 5, 8, 7, 6, 4, 3, 2, 9};  //정렬할 배열
   public static void main(String[] args) throws IOException {
       quickSort(arr, 0, number - 1);
   }
   static void quickSort(int[] arr, int start, int end) {
       if (start >= end) {
           return;  //원소가 1개인 경우
       }
       int pivot = start;  //pivot값은 첫번째 원소
       int i = start + 1;  //시작점 - 왼쪽부터 큰 값을 찾을 때 시작하는 인덱스
       int j = end;  //도착점 - 오른쪽부터 작은 값을 찾을 때 시작하는 인덱스
       int temp;  //수를 바꿀 때 사용하는 임시 변수
       while (i <= j) { // 엇갈릴 때까지 반복
           while (arr[i] <= arr[pivot]) { //pivot보다 더 큰 값을 만날 때까지
               i++;
           }
           while (arr[j] >= arr[pivot] && j > start) { //pivot보다 더 작은 값을 만날 때까지
               j--;
           }
           if (i > j) { //현재 엇갈린 상태면 pivot값과 교체
               temp = arr[j];
               arr[j] = arr[pivot];
               arr[pivot] = temp;
           } else { //엇갈리지 않았다면 i와 j를 교체
               temp = arr[i];
               arr[i] = arr[j];
               arr[j] = temp;
           }
      }
       //분할된 왼쪽과 오른쪽 둘다 퀵 정렬 수행
       quickSort(arr, start, j - 1);
       quickSort(arr, j + 1, end);
   }
}
만약에 내림차순으로 정렬을 한다고 할 때는 다음만 바꿔주기만 하면 된다.
while (arr[i] >= arr[pivot]) { //pivot보다 더 큰 값을 만날 때까지
    i++;
}
while (arr[j] <= arr[pivot] && j > start) { //pivot보다 더 작은 값을 만날 때까지
    j--;
}
퀵 정렬 (내림차순)
import java.io.*;
import java.util.*;
public class Main {
    static int number = 10;  //데이터의 개수
    static int[] arr = {1, 10, 5, 8, 7, 6, 4, 3, 2, 9};  //정렬할 배열
    public static void main(String[] args) throws IOException {
        quickSort(arr, 0, number - 1);
    }
    static void quickSort(int[] arr, int start, int end) {
        if (start >= end) {
            return;  //원소가 1개인 경우
        }
        int pivot = start;  //pivot값은 첫번째 원소
        int i = start + 1;  //시작점 - 왼쪽부터 큰 값을 찾을 때 시작하는 인덱스
        int j = end;  //도착점 - 오른쪽부터 작은 값을 찾을 때 시작하는 인덱스
        int temp;  //수를 바꿀 때 임시 변수
        while (i <= j) { // 엇갈릴 때까지 반복
            while (arr[i] >= arr[pivot]) { //pivot보다 더 큰 값을 만날 때까지
                i++;
            }
            while (arr[j] <= arr[pivot] && j > start) { //pivot보다 더 작은 값을 만날 때까지
                j--;
            }
            if (i > j) { //현재 엇갈린 상태면 pivot값과 교체
                temp = arr[j];
                arr[j] = arr[pivot];
                arr[pivot] = temp;
            } else { //엇갈리지 않았다면 i와 j를 교체
                temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
       }
        //분할된 왼쪽과 오른쪽 둘다 퀵 정렬 수행
        quickSort(arr, start, j - 1);
        quickSort(arr, j + 1, end);
    }
}
퀵 정렬 시간 복잡도
퀵 정렬의 성능은 어떻게 pivot 값을 선택하느냐에 따라 크게 달라질 수 있다. pivot 값을 기준으로 동일한 개수의 작은 값들과 큰 값들이 분할되면 O(NlogN)의 시간 복잡도를 가지게 된다.
하지만, pivot 값을 기준으로 분할했을 때 값들이 한 편으로 크게 치우치게 되면, 퀵 정렬의 성능은 저하되고, 한편으로만 모든 값이 몰리면 O(N^2)의 시간 복잡도를 가지게 된다. 추가로 이미 배열이 정렬되어 있고 pivot이 항상 그 배열의 최솟값 혹은 최댓값인 경우에는 최악의 시간 복잡도를 가진다. 이때, 분할이 N만큼 진행되다 보니 최악의 시간 복잡도는 O(N^2)이 된다.

이 그래프에서 볼 수 있듯이 자료의 개수 N이 많아질수록 O(N log N)의 시간 복잡도를 가지고 있는 퀵 정렬은 다른 정렬 알고리즘보다 훨씬 더 효율적이다.
퀵 정렬의 장단점
장점
- O(NlogN)의 시간 복잡도를 가지므로 다른 정렬 알고리즘보다 빠르다
 - 정렬하고자 하는 배열 안에서 교환하는 방식(in-place)이므로, 다른 메모리 공간을 필요로 하지 않는다
 
단점
- 불안정 정렬(Unstable Sort)이다
 - 정렬된 배열에 대해서는 Quick sort의 불균형 분할에 의해 오히려 수행 시간이 더 많이 걸린다
 
'알고리즘' 카테고리의 다른 글
| [알고리즘] 계수 정렬 (Counting Sort) (0) | 2022.07.29 | 
|---|---|
| [알고리즘] 병합 정렬 (Merge Sort) (0) | 2022.07.28 | 
| [알고리즘] 삽입 정렬 (Insertion Sort) (0) | 2022.07.21 | 
| [알고리즘] 버블 정렬 (Bubble Sort) (0) | 2022.07.16 | 
| [알고리즘] 에라토스테네스의 체 (Sieve of Eratosthenes) (0) | 2022.07.15 | 
										
									
										
									
										
									
										
									
댓글