오늘은 퀵정렬에 대해서 알아보려고 합니다.
선택, 삽입, 퀵 정렬 중에서 퀵 정렬이 가장 많이 사용되는 알고리즘입니다.
'기준 데이터를 설정하고 그 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸면 어떨까?'
퀵 정렬은 기준을 설정한 다음 큰 수와 작은 수를 교환한 후 리스트를 반으로 나누는 방식으로 동작합니다.
쿽 정렬에서는 피벗이 사용되는데, 큰 숫자와 작은 숫자를 교환할 때, 교환하기 위한 '기준'을 바로 피펏이라고 표현합니다.
퀵 정렬을 수행하기 전에는 피벗을 어떻게 설정할 것인지 미리 명시해야 합니다.
퀵 정렬 분할 방식 중에서 호어 분할 방식(Hoare Partition Scheme)을 사용하면서 리스트를 두 부분으로 나누고, 각 부분을 재귀적으로 정렬합니다.
아래는 주어진 리스트를 사용하여 퀵 정렬을 진행하는 과정을 표로 나타낸 것입니다.
원래 리스트: [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]
단계 | 현재 리스트 | 피벗 | 왼쪽 부분 | 오른쪽 부분 |
초기 | [7, 5, 9, 0, 3, 1, 6, 2, 4, 8] | 피벗: 7 | [] | [] |
1단계 | [7, 5, 9, 0, 3, 1, 6, 2, 4, 8] | [5, 0, 3, 1, 6, 2, 4] | [9, 8] | |
2단계 | [5, 0, 3, 1, 6, 2, 4, 7, 8] | 피벗: 5 | [0, 3, 1, 2, 4] | [6, 7, 9, 8] |
3단계 | [5, 0, 3, 1, 2, 4, 7, 6, 8, 9] | [0, 3, 1, 2, 4] | [6, 7, 8, 9] | |
4단계 | [0, 3, 1, 2, 4, 5, 7, 6, 8, 9] | 피벗: 0 | [1, 2, 4] | [3, 5, 7, 6, 8, 9] |
5단계 | [0, 1, 2, 4, 3, 5, 7, 6, 8, 9] | [1, 2, 4] | [3, 5, 7, 6, 8, 9] | |
6단계 | [1, 2, 4, 3, 0, 5, 7, 6, 8, 9] | 피벗: 1 | [0] | [2, 4, 3, 5, 7, 6, 8, 9] |
7단계 | [1, 0, 2, 4, 3, 5, 7, 6, 8, 9] | [0] | [2, 4, 3, 5, 7, 6, 8, 9] | |
8단계 | [0, 1, 2, 4, 3, 5, 7, 6, 8, 9] | 피벗: 2 | [] | [4, 3, 5, 7, 6, 8, 9] |
9단계 | [0, 1, 2, 4, 3, 5, 7, 6, 8, 9] | [] | [4, 3, 5, 7, 6, 8, 9] | |
10단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | 피벗: 3 | [] | [4, 5, 7, 6, 8, 9] |
11단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | [] | [4, 5, 7, 6, 8, 9] | |
12단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | 피벗: 4 | [] | [5, 7, 6, 8, 9] |
13단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | [] | [5, 7, 6, 8, 9] | |
14단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | 피벗: 5 | [] | [7, 6, 8, 9] |
15단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | [] | [7, 6, 8, 9] | |
16단계 | [0, 1, 2, 3, 4, 5, 7, 6, 8, 9] | 피벗: 6 | [] | [7, 8, 9] |
17단계 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | [] | [7, 8, 9] | |
18단계 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | 피벗: 7 | [] | [8] |
19단계 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | [] | [8] | |
20단계 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | [] | [] |
퀵 정렬은 리스트를 분할하고 재귀적으로 정렬하는 과정을 반복하여 정렬을 수행합니다.
위의 표에서 굵게 표시된 원소는 각 단계에서 선택된 피벗(pivot)을 나타냅니다.
리스트는 피벗을 기준으로 두 부분으로 나누어지며, 각 부분은 재귀적으로 정렬됩니다.
이러한 과정을 통해 리스트가 정렬됩니다.
소스 코드
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]
# 퀵 정렬 함수 정의: 배열, 시작 인덱스(start), 끝 인덱스(end)를 매개변수로 받습니다.
def quick_sort(array, start, end):
# 종료 조건: 시작 인덱스가 끝 인덱스보다 크거나 같으면 함수를 종료합니다.
if start >= end:
return
# 피벗을 첫 번째 원소로 선택합니다.
pivot = start
left = start + 1
right = end
# left 포인터가 right 포인터보다 작거나 같을 때까지 반복합니다.
while left <= right:
# left 포인터를 오른쪽으로 이동하며 피벗보다 작거나 같은 원소를 찾습니다.
while left <= end and array[left] <= array[pivot]:
left += 1
# right 포인터를 왼쪽으로 이동하며 피벗보다 큰 원소를 찾습니다.
while right > start and array[right] >= array[pivot]:
right -= 1
# 만약 left 포인터가 right 포인터를 지나쳤다면 피벗과 right 위치의 원소를 교환합니다.
if left > right:
array[right], array[pivot] = array[pivot], array[right]
else:
# 그렇지 않으면 left 위치의 원소와 right 위치의 원소를 교환합니다.
array[left], array[right] = array[right], array[left]
# 피벗을 기준으로 분할된 왼쪽 부분과 오른쪽 부분을 각각 재귀적으로 정렬합니다.
quick_sort(array, start, right - 1)
quick_sort(array, right + 1, end)
# 퀵 정렬 함수를 호출하여 배열을 정렬합니다. 시작 인덱스는 0, 끝 인덱스는 배열 길이 - 1로 지정합니다.
quick_sort(array, 0, len(array) - 1)
# 정렬된 배열을 출력합니다.
print(array)
파이썬의 장점을 살핀 퀵 정렬 소스코드
def quick_sort(array):
if len(array) <= 1:
return array
pivot = array[0]
tail = array[1:]
left_side = [x for x in tail if x <= pivot]
right_side = [x for x in tail if x > pivot]
return quick_sort(left_side) + [pivot] + quick_sort(right_side)
array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8, 11, 15, 13, 10, 12, 14, 19, 16, 18, 17]
result = quick_sort(array)
print(result)
'개발 > CodingTest' 카테고리의 다른 글
[백준] 1780번 - 종이의 개수 - 이해까지 도와주는 풀이 (2) | 2024.01.27 |
---|---|
[백준] 2630번 - 색종이 만들기 - 이해까지 도와주는 풀이 (2) | 2024.01.27 |
[자료구조] 삽입정렬이란? (0) | 2024.01.24 |
[자료구조] 선택정렬이란? (0) | 2024.01.24 |
[자료구조] DFS와 BFS의 비교 (1) | 2024.01.23 |