퀵 정렬(quick sort)은 분할 정복(divide and conquer) 방법을 통해 리스트를 정렬한다.
- 리스트 가운데서 하나의 원소를 고른다. 이렇게 고른 원소를 피벗이라고 한다.
- 피벗 앞에는 피벗보다 값이 작은 모든 원소들이 오고, 피벗 뒤에는 피벗보다 값이 큰 모든 원소들이 오도록 피벗을 기준으로 리스트를 둘로 나눈다. 이렇게 리스트를 둘로 나누는 것을 분할이라고 한다. 분할을 마친 뒤에 피벗은 더 이상 움직이지 않는다.
- 분할된 두 개의 작은 리스트에 대해 재귀(Recursion)적으로 이 과정을 반복한다. 재귀는 리스트의 크기가 0이나 1이 될 때까지 반복된다.
재귀 호출이 한번 진행될 때마다 최소한 하나의 원소는 최종적으로 위치가 정해지므로, 이 알고리즘은 반드시 끝난다는 것을 보장할 수 있다.
예제
퀵정렬의 간단한 설명
퀵정렬은 임의의 pivot 값을 기준으로 pivot 의 좌측에는 pivot 보다 작은값을 두고 우측에는 pivot 보다 큰 값을 두고자 한다.
이 행위는 pivot을 기준으로 좌 우로 이분화 된 리스트를 재귀적으로 반복했을 때 결국 정렬이 완성 된다는 방법 론이다.
보다 쉽게 설명하면 pivot보다 큰 값을 pivot index 보다 왼쪽에서 찾고 ( 큰 값 이 나타날 때까지 i index를 증가시키도록 한다.)
pivot 보다 작은 값을 pivot index 보다 오른쪽에서 찾는다 ( 작은 값이 나타날 때까지 j index를 감소시키도록 한다. )
pivot을 기준으로 값 비교가 완료되었다면 index 결과 i , j를 비교 해본다.
i 값이 j 값 보다 작거나 같다면 분명 pivot 을 기준으로 교환을 해야할 값이 있다는 뜻이 된다.
교환한 뒤 i 인덱스는 증가 j 인덱스는 감소 연산을 수행한다.
i 인덱스가 j 인덱스보다 작거나 같다면 계속 반복해서 수행한다.
위 와 같은 과정은 pivot을 기준으로 왼쪽으로 정렬된 list 에서는 최초 Left 값이 감소된 j 보다 작다면 계속 재귀하면되고,
pivot을 기준으로 오른쪽으로 정렬된 list 에서는 최초 Right 값이 증가된 i 값보다 크다면 계속 재귀하면된다.
피벗은 p, 리스트 왼쪽 끝과 오른쪽 끝에서 시작한 인덱스들을 i,j라고 하자.
5 - 3 - 7 - 6 - 2 - 1 - 4 p
리스트 왼쪽에 있는 i 위치의 값이 피벗 값보다 크고, 오른쪽에 있는 j 위치의 값은 피벗 값보다 작으므로 둘을 교환한다.
5 - 3 - 7 - 6 - 2 - 1 - 4 i j p 1 - 3 - 7 - 6 - 2 - 5 - 4 i j p
j 위치의 값이 피벗 값보다 작지만, i 위치의 값도 피벗값보다 작으므로 교환하지 않는다.
1 - 3 - 7 - 6 - 2 - 5 - 4 i j p
i위치를 피벗 값보다 큰 값이 나올 때까지 진행해 j 위치의 값과 교환한다.
1 - 3 - 7 - 6 - 2 - 5 - 4 i j p 1 - 3 - 2 - 6 - 7 - 5 - 4 i j p
i위치가 j 위치보다 커지면, i 위치의 값과 피벗 값을 교환한다.
1 - 3 - 2 - 6 - 7 - 5 - 4 p 1 - 3 - 2 - 4 - 7 - 5 - 6 p
피벗 값 좌우의 리스트에 대해 각각 퀵 정렬을 재귀적으로 수행한다.
1 - 3 - 2 7 - 5 - 6 1 - 2 - 3 5 - 6 - 7
완성된 리스트는 다음과 같다.
1 - 2 - 3 - 4 - 5 - 6 - 7
소스 코드
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 | void quickSort(int list[], int i, int j) { if (i >= j) return; int pivot = list[(i + j) / 2]; int left = i; int right = j; while (left <= right) { while (list[left] < pivot) left++; while (list[right] > pivot) right––; if (left <= right) { int temp = list[left]; list[right] = list[left]; list[left] = temp; left++; right––; } } quickSort(list, i, right); quickSort(list, left, j); } | cs |
특징
퀵 정렬은 n개의 데이터를 정렬할 때, 최악의 경우에는 O(n2)번의 비교를 수행하고, 평균적으로 O(n log n)번의 비교를 수행하여 정렬 알고리즘 중에서 비교적 구현은 복잡하지만 매우 빠른 속도로 작동한다.