이전까지의 알고리즘들은 시간 복잡도가 O(n^2)을 가지기 때문에 실제로 사용하기가 어려운 알고리즘이다. 그렇기 때문에 매우 빠른 알고리즘이 필요하다. 그래서 우리는 실제로 가장 많이 사용되는 알고리즘인 Quick 정렬을 배워볼 것이다.
퀵 정렬은 하나의 큰 문제를 두 개의 문제로 분할하는 식으로 빠르게 정렬한다. 쉽게 말하자면 특정한 값을 기준으로 큰 숫자와 작은 숫자를 서로 교환한 뒤에 배열을 반으로 나눈다.
피벗을 기준으로 작거나 같은 데이터는 앞으로 가도록하고, 피벗보다 큰 데이터는 뒤로 가도록하여 작은 값을 갖는 데이터와 큰 값을 갖는 데이터로 분리해가며 정렬하는 방법
원래의 문제를 더 작은 크기의 하위 문제로 쪼개어 해결하는 ‘분할 정복 알고리즘’에 해당
피벗 선택 방법
아무 원소나 피벗으로 삼아도 상관없으나 다음과 같은 방법이 존재
위의 움직이는 사진을 보고 천천히 생각을 해보자!
가운데 지점을 피벗으로 잡고 , 피벗 앞으로 피벗보다 큰 숫자, 뒤는 작은 찾아 두 숫자를 바꾼다.
만약 앞과 뒤를 탐색하던 포인터가 같은 지점에 만났을 경우!
def partition(arr, start, end):
pivot = arr[end]
index = start
for i in range(start, end):
if arr[i] <= pivot:
arr[i], arr[index] = arr[index], arr[i]
index += 1
arr[index], arr[end] = arr[end], arr[index]
return index
def quickSort(arr, left=0, right=None):
if right is None:
right = len(arr) - 1
if left >= right:
return
pivot_index = partition(arr, left, right)
quickSort(arr, left, pivot_index - 1)
quickSort(arr, pivot_index + 1, right)
return arr
# 테스트
if __name__ == "__main__":
unsorted_list = [4, 3, 10, 6, 8, 7, 9, 1, 2, 5]
print("Original array:")
print(unsorted_list)
sorted_list = quickSort(unsorted_list)
print("Sorted array:")
print(sorted_list)
자료구조 힙을 사용해서 정렬을 하는 알고리즘
heap
힙 정렬
정렬할 데이터들을 먼저 힙으로 삽입해야 한다.
그런 다음 루트 노드를 하나씩 삭제하여 꺼내면 힙에 있는 데이터들이 순서대로 나오는데 이 순서대로 나열한 것이 힙 정렬의 결과
최악의 경우에도 O(N * logN)의 시간 복잡도를 갖는다.
def heapify(unsorted, index, heap_size):
largest = index
left = 2 * index + 1
right = 2 * index + 2
if left < heap_size and unsorted[right] > unsorted[largest]:
largest = left
if right < heap_size and unsorted[right] > unsorted[largest]:
largest = right
if largest != index:
unsorted[largest], unsorted[index] = unsorted[index], unsorted[largest]
heapify(unsorted, largest, heap_size)
def heap_sort(unsorted):
n = len(unsorted)
for i in range(n // 2 - 1, -1, -1):
heapify(unsorted, i, n)
for i in range(n - 1, 0, -1):
unsorted[0], unsorted[i] = unsorted[i], unsorted[0]
heapify(unsorted, 0, i)
return unsorted