14. Quick Sort Algorithm
아래의 그림과 같이 피벗은 실제 정렬 후 결과에서 자신이 있게 될 위치를
확정할 수 있다
2 4 4 1 5 6 9 7
자기보다 작은 원소의 수 자기보다 큰 원소의 수
정렬 후 배열에서의 위치는 자기보다 작은 원소들의 뒤 이기 때문이다
15. Implementation Overview
Quick Sort는 재귀함수를 사용하여 구현할 수 있다
1. 정렬할 배열의 피벗 𝑝를 설정한다
2. 배열을 𝑝를 기준으로 상대적으로 작은 값과 큰 값으로 분할한다
3. 이 과정을 배열이 한 칸이 될 때 까지 반복한다
16. Implementation – Array Partitioning
분할할 영역의 양 쪽 인덱스를 변수 𝑖, 𝑗로 설정합니다
5 4 9 4 2 6 1 7
𝑖 𝑗
𝐿 𝑅
17. Implementation – Array Partitioning
배열의 𝑖번째 값이 𝑝보다 작은 동안 𝑖를 증가시킨다
배열의 𝑗번째 값이 𝑝보다 큰 동안 𝑗를 감소시킨다
5 4 9 4 2 6 1 7
𝑖 𝑗
5 4 9 4 2 6 1 7
𝑖 𝑗
𝐿 𝑅
𝐿 𝑅
18. Implementation – Array Partitioning
더 이상 𝑖와 𝑗를 움직일 수 없을 때 멈춘다
그리고 𝑖번째 값과 𝑗번째 값의 자리를 바꾼다
𝑖를 1증가 시키고, 𝑗를 1감소 시킨다
5 4 9 4 2 6 1 7
𝑖 𝑗
1 4 9 4 2 6 5 7
𝑖 𝑗
𝐿 𝑅
𝐿 𝑅
19. Implementation – Array Partitioning
앞의 단계들을 반복하면 결과적으로 피벗을 기준으로
[𝐿, 𝑗]와 [𝑖, 𝑅]의 두 영역으로 배열이 분할된다
𝑖𝑗
𝐿 𝑅
2 4 4 1 5 6 9 7
2 4 4 1 6 9 7
𝑗𝐿 𝑖 𝑅
두 영역으로 나누는 연산은 𝑂(𝑛)이 연산량을 가진다
20. Implementation – Recursive Function
다음의 코드와 같이 구현할 수 있다
𝑖𝑗
𝐿 𝑅
2 4 4 1 5 6 9 7
2 4 4 1 6 9 7
𝑗𝐿 𝑖 𝑅
5 4 9 4 2 6 1 7
𝑖 𝑗
𝐿 𝑅
21. Choosing a Pivot
퀵 정렬은 피벗 𝑝를 설정하는 다양한 방법이 존재한다
입력 배열의 형태와 피벗을 선택하는 방법에 따라 성능에 차이가 존재한다
1. 배열의 가장 왼쪽 값을 피벗으로 설정하기
2. 배열의 중간에 있는 값을 피벗으로 설정하기
3. 랜덤으로 배열의 아무 숫자나 피벗으로 설정하기
…
22. Choosing a Pivot
다음과 같은 입력 배열에 대하여
각 피벗 선정 방식에 따른 차이를 상상해보자
1. 배열의 가장 왼쪽 값을 피벗으로 설정하기
2. 배열의 중간에 있는 값을 피벗으로 설정하기
3. 랜덤으로 배열의 아무 숫자나 피벗으로 설정하기
…
8 7 6 5 4 3 2 1
23. Worst Case
아래의 배열을 가장 왼쪽 값을 피벗으로 하여 오름차순 정렬해보자
…
1 2 3 … … n-2 n-1 n
1 2 3 … … n-2 n-1 n
1 2 3 … … n-2 n-1 n
1 2 3 … … n-2 n-1 n
1 2 3 … … n-2 n-1 n
1 2 3 … … n-2 n-1 n
𝑛
𝑛 − 1
𝑛 − 2
𝑛 − 3
2
1
0
24. Worst Case
즉, 퀵 정렬은 최악의 경우 𝑂(𝑛2
)의 연산량을 가지게 된다
그럼에도 통계적으로 퀵 정렬은 매우 빠른 속도를 나타낸다
최적의 경우는 항상 피벗을 배열의 중앙값으로 선정하는 것이다
다음 번 배열의 크기가 점점 약 절반으로 줄어가기 때문이다
26. How to choose a pivot
다음의 방법이 가장 유명한 방법으로 알려져 있다
𝑝 = 𝑆𝑒𝑐𝑜𝑛𝑑( 𝑎𝑟𝑟 𝑙𝑒𝑓𝑡 , 𝑎𝑟𝑟 𝑟𝑖𝑔ℎ𝑡 , 𝑎𝑟𝑟[
𝑙𝑒𝑓𝑡+𝑟𝑖𝑔ℎ𝑡
2
])
정렬할 배열의 왼쪽 끝, 오른쪽 끝 그리고 중앙에서 고른 값들 중 중위값
5 4 9 4 2 6 1 7
4 5 7