-
파이썬 Introspective Sort (내성 정렬) 알고리즘컴퓨터/파이썬 2020. 7. 17. 15:31728x90반응형
Introspective Sort
IntroSort (Introspective Sort) 인트로 정렬은, Quick Sort의 장점을 유지하면서,
최악 시나리오 O(n^2)를 해결하려 만들어진 (Quick Sort + Heap Sort + Insertion Sort) 하이브리드 알고리즘이다.
(C++ 기본 정렬 알고리즘, std::sort)
모든 상황에서 시간 복잡도 : O(nlogn), 공간 복잡도는 O(logn)이며, inplace, not stable한 알고리즘이다.
(in-place란, 보조 데이터 구조를 사용하지 않고, 작동하는 알고리즘)
Quick Sort로 시작해서, Recursion max-depth (log(len(array)) 에 도달하면 Heap Sort로 정렬하고,
그리고, 파티션 크기가 보통 16보다 작으면 Insertion Sort로 정렬한다.
Pseudo Code
# Intro Sort 주요 특징 /* 1. 3개의 요소들에게서 중간값(median) 구하기 2. 크기가 작은 (보통 16) 파티션들은 Insertion Sort 3. Quick Sort 하다가 max recursion depth 도달하면 Heap Sort */ procedure sort(A : array): let maxdepth = ⌊log(length(A))⌋ × 2 introsort(A, maxdepth) procedure introsort(A, maxdepth): n ← length(A) size ← endIdx - startIdx if n ≤ 1: return // base case else if maxdepth = 0: heapsort(A) else if size < 16: insertsort(A) else: // pivot, p p ← partition(A) introsort(A[0:p-1], maxdepth - 1) introsort(A[p+1:n], maxdepth - 1)
0. Insertion Sort 구현
# Time Complexity O(n),O(n^2),O(n^2) | Space Complexity O(1) | stable def insertSort(array, begin=0, end=None): if end == None: end = len(array) for i in range(begin, end): j = i toChange = array[i] while (j != begin and array[j - 1] > toChange): array[j] = array[j - 1] j -= 1 array[j] = toChange return array
1. Heap Sort 구현
# Time Complexity O(nlogn) | Space Complexity O(1) | not stable def heapify(arr, n, i): # Max Heap largest = i # 트리에서 가장 큰 값 찾기 l = 2 * i + 1 # Left Node r = 2 * i + 2 # Right Node if l < n and arr[i] < arr[l]: largest = l if r < n and arr[largest] < arr[r]: largest = r # root가 최대가 아니면 # 최대 값과 바꾸고, 계속 heapify if largest != i: arr[i], arr[largest] = arr[largest], arr[i] heapify(arr, n, largest) def heapSort(arr): n = len(arr) for i in range(n // 2, -1, -1): heapify(arr, n, i) for i in range(n - 1, 0, -1): arr[i], arr[0] = arr[0], arr[i] # Heapify root element heapify(arr, i, 0) return arr
2. pivot 값을 위한 median of 3 killer (배열의 시작, 중간, 끝), 함수 두개 중 맘에 드는 것을 선택
문자열을 정렬하게 못하게 됨.
# comparison보다 XOR을 속도면에서 선택함 def medianOf3(array, lowIdx, midIdx, highIdx): if ((array[lowIdx] > array[midIdx]) != (array[lowIdx] > array[highIdx])): return array[lowIdx] elif ((array[midIdx] > array[lowIdx]) != (array[midIdx] > array[highIdx])): return array[midIdx] else: return array[highIdx] # 비교 줄이기 def medianOf3(array, lowIdx, midIdx, highIdx): if (array[lowIdx] - array[midIdx]) * (array[highIdx] - array[lowIdx]) >= 0: return array[lowIdx] elif (array[midIdx] - array[lowIdx]) * (array[highIdx] - array[midIdx]) >= 0: return array[midIdx] else: return array[highIdx]
3. 파티션을 나누기 위한 getPartition 함수
def getPartition(array, low, high, pivot): i = low j = high while True: while (array[i] < pivot): i += 1 j -= 1 while (pivot < array[j]): j -= 1 if i >= j: return i array[i], array[j] = array[j], array[i] i += 1
2. IntroSort(array)
# Time Complexity O(nlogn) | Space Complexity O(logn) | not stable def introSort(array): maxDepth = 2 * (len(array).bit_length() - 1) # 2* (log2(length) - 1) sizeThreshold = 16 return introSortHelper(array, 0, len(array), sizeThreshold, maxDepth) def introSortHelper(array, start, end, sizeThreshold, depthLimit): # size가 16보다 크면 heap sort or quick sort while(end - start > sizeThreshold): if (depthLimit == 0): return heapSort(array) depthLimit -= 1 median = medianOf3(array, start, start + ((end - start) // 2) + 1, end - 1) p = getPartition(array, start, end, median) introSortHelper(array, p, end, sizeThreshold, depthLimit) end = p # insert Sort로 종료 return insertSort(array, start, end)
3. 얼마나 빠른가?
테스트 배열을 3번 실행해서, 평균 정렬 시간을 출력하도록 했다.
크기 백만: 랜덤, 내림차순, 오름차순, 부분 정렬, k정렬
1. 랜덤한 숫자 1,000,000개 (Random) ( 3위 )
2. 거꾸로 정렬된 크기 1,000,000의 배열 (Descending) ( 3위 )
3. 정렬된 크기 1,000,000 배열 (Ascending) ( 3위 )
4. 크기 1,000,000의 부분 정렬된 랜덤 배열 ( 5위 )
5. 크기 1,000,000의 K정렬 ( 3위 )
정렬 알고리즘 시간 복잡도 계산기: choiseokwon.tistory.com/231
풀 소스 확인 : https://gist.github.com/Alfex4936/62f81e9cde7719d4762f596068bfb001
Count Sort (https://choiseokwon.tistory.com/206)
TimSort (https://choiseokwon.tistory.com/208)
참고 : https://www.wikiwand.com/en/Introsort
참고 : https://www.geeksforgeeks.org/introsort-or-introspective-sort/
728x90'컴퓨터 > 파이썬' 카테고리의 다른 글
파이썬 A* (A-star) 최단 경로 찾기 알고리즘 (10) 2020.07.20 파이썬 array.sort(), TimSort 알고리즘 (1) 2020.07.16 Python BFS(너비 탐색) 및 Iterative Deepening Depth-first Search (0) 2020.07.11