강의노트 23. [정렬] 자료구조 - quick sort (퀵소트)
20 Apr 2017 |패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.
quick sort (퀵소트)
- 참고글
- 수업자료
- 현업에서 많이 사용되는 빠른 정렬 기법
- 분할정복기법 (Divide and conquer)을 활용한다. (문제를 분할하여 해결, 재귀 함수를 이용)
- 기준값을 하나 택하고 순회를 돌면서 기준값보다 작은 데이터는 좌측에, 기준값보다 큰 데이터는 우측으로 분할하고 다시 퀵 정렬을 적용한다.
quick sort 성능
- 시간 복잡도에 대한 자료 - 추천!
- 퀵 정렬의 평균 복잡도 : O(N log N)
- 퀵 정렬의 최악의 경우 복잡도 : O(N^2)
- 퀵 정렬의 복잡도는 다른 알고리즘 Heap Sort 또는 Merge Sort보다 뛰어난 것은 아니다.
- 하지만 실제로 수행했을 때 다른 정렬 알고리즘보다도 빨라서 가장 많이 쓰이는 알고리즘이 되었다.
- Quick sort는 정렬 알고리즘 중 성능이 좋다고 알려져 있고, worst case로 Big-O를 따지는 다른 경우와 다르게 average case로 계산한다.
- (Quick sort의 BigO 를 구하는 방법은 상기 수업자료에도 자세히 설명되어 있음)
구현예시 1
# 파티션 (pivot)
def partition(data, start, end):
pivot = data[start]
idx_low = start + 1
idx_high = end
# low와 high가 교차해야한다. (중요)
while idx_low <= idx_high:
# low가 end보다 같거나 작고, low index에 해당하는 값이 pivot값 보다 작거나 같으면 low는 오른쪽으로 계속 이동
while idx_low <= end and data[idx_low] <= pivot:
idx_low += 1
# high가 start+1 보다 같거나 크고, higt index에 해당하는 값이 pivot값 보다 크거나 같으면 high는 왼쪽으로 계속 이동
while idx_high >= (start + 1) and data[idx_high] >= pivot:
idx_high -= 1
# low 값과 high 값을 교환
if idx_low <= idx_high:
data[idx_low], data[idx_high] = data[idx_high], data[idx_low]
# low와 high가 교차하면 pivot과 high의 값을 교환
data[start], data[idx_high] = data[idx_high], data[start]
return idx_high
def quick_sort(data, start, end):
if start >= end:
return
idx_pivot = partition(data, start, end)
quick_sort(data, start, idx_pivot - 1)
quick_sort(data, idx_pivot + 1, end)
if __name__ == '__main__':
li = [2, 5, 4, 1, 8, 10, 5, 3, 6, 6, 5, 7, 9, 12, 11] # [1, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 9, 10, 11, 12]
quick_sort(li, 0, len(li) -1)
print(li)
구현예시 2
- 퀵소트의 성능 향상을 위해 pivot 값을 결정할 때, 맨 왼쪽, 가운데, 오른쪽 값을 비교해 중간 값을 pivot 으로 만든다.
#성능 비교를 위한 변수
call_of_partition = 0
#정렬된 리스트에서 맨 앞 값을 pivot으로 지정한다면
#예를 들어 1
#성능이 매우 안 좋을 수 있다
#그러므로 pivot 값을 정하는 함수를 따로 만들어
#pivot 값이 가장 작은 값이 되지 않도록 한다
def get_pivot(li, start, end):
mid = (start + end)//2
list_idx = [start, mid, end]
#버블 정렬로 리스트에서의 값을 비교해
#[가장 작은 값의 index, 가운데 값의 index, 가장 큰 값의 index]
#순으로 정렬한다
if li[list_idx[0]] > li[list_idx[1]]:
list_idx[0], list_idx[1] = list_idx[1], list_idx[0]
if li[list_idx[1]] > li[list_idx[2]]:
list_idx[1], list_idx[2] = list_idx[2], list_idx[1]
if li[list_idx[0]] > li[list_idx[1]]:
list_idx[0], list_idx[1] = list_idx[1], list_idx[0]
#정렬이 완료되면 가운데 idx의 값이 중간 값이므로 이를 반환해
#pivot으로 정하도록 한다
return list_idx[1]
def partition(li, start, end):
#partition 함수가 몇 번 호출되었는가를 계산
global call_of_partition
call_of_partition += 1
#pivot 값을 정한다
idx_pivot = get_pivot(li, start, end)
#pivot을 리스트의 start index에 두기 위해
#리스트의 start 값과 pivot idx의 값을 교환한다
li[start], li[idx_pivot] = li[idx_pivot], li[start]
#pivot 여기서는 start index의 값을 의미한다
pivot = li[start]
#pivot 값을 기준으로 왼쪽에 낮은 값들이 존재할 수 있도록
#low idx는 검색 도중 pivot보다 큰 값이 있으면
#그 값을 가리킨다
low = start + 1
#pivot 값을 기준으로 오른쪽에 높은 값들이 존재할 수 있도록
#high idx는 pivot 값보다 작은 값이 있으면
#그 값을 기리킨다
high = end
#반드시 low와 high idx가 교차하게 만든다
#그 전까지는 교환 규칙에 따라 계속 루프가 돌도록 한다
while low <= high:
#low idx는 pivot보다 큰 값을 가진 idx를 만나기 전까지
#오른쪽으로 이동한다
#대신 low가 end를 벗어나면 안된다
while low <= end and li[low] <= pivot:
low+=1
#high idx는 pivot보다 작은 값을 가진 idx를 만나기 전까지
#왼쪽으로 이동한다
#대신 high가 start + 1을 벗어나면 안된다
while high >= (start + 1) and li[high] >= pivot:
high-=1
#low와 high가 교차 전이라면 두 idx가 가리키는 값을 서로 바꾼다
if low <= high:
li[low], li[high] = li[high], li[low]
#교차했다면 pivot의 idx와 high idx의 값을 서로 교환한다
#high가 가리키는 idx가 정렬되었을 때의 pivot 값의 위치이기 때문
li[start], li[high] = li[high], li[start]
#최종적으로 pivot 값의 최종 idx를 반환
return high
def quicksort(li, start, end):
#재귀함수 이므로 탈출 조건이 필요하다
if start >=end:
return;
#정렬된 pivot값의 idx를 가져온다
idx_pivot = partition(li, start, end)
#idx_pivot은 정렬이 된 상태 이므로 이를 기준으로
#앞 부분과 뒷 부분을 quicksort를 통해(재귀함수) 계속 정렬해주면 된다
quicksort(li, start, idx_pivot - 1)
quicksort(li, idx_pivot + 1, end)
if __name__ == "__main__":
# li = [2, 5, 4, 1, 8, 10, 5, 3, 6, 6, 5, 7, 9, 12, 11]
#정렬된 리스트에서의 성능 평가를 위한 리스트
li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
quicksort(li, 0, len(li)-1)
print(li)
print("call_of_partition : %d \n" % call_of_partition)