Worst-Case Efficient Sorting with Quickmergesort
Total Page:16
File Type:pdf, Size:1020Kb
Worst-Case Efficient Sorting with QuickMergesort Stefan Edelkamp1 and Armin Weiß2 1King's College London, UK 2FMI, Universit¨atStuttgart, Germany San Diego, January 7, 2019 25 20 [ns] n log 15 n 10 time per 5 Right: random with2 large10 elements215 in220 the middle225 and end. number of elements n 25 20 [ns] n log 15 n 10 time per 5 210 215 220 225 number of elements n std::sort (Quicksort/Introsort) std::partial sort (Heapsort) std::stable sort (Mergesort) Running times (divided by n log n) for sorting integers. Left: random inputs. Comparison-based sorting: Quicksort, Heapsort, Mergesort 25 20 [ns] n log 15 n 10 time per 5 Right: random with2 large10 elements215 in220 the middle225 and end. number of elements n Comparison-based sorting: Quicksort, Heapsort, Mergesort 25 20 [ns] n log 15 n 10 time per 5 210 215 220 225 number of elements n std::sort (Quicksort/Introsort) std::partial sort (Heapsort) std::stable sort (Mergesort) Running times (divided by n log n) for sorting integers. Left: random inputs. Comparison-based sorting: Quicksort, Heapsort, Mergesort 25 25 20 20 [ns] [ns] n n log log 15 15 n n 10 10 time per time per 5 5 210 215 220 225 210 215 220 225 number of elements n number of elements n std::sort (Quicksort/Introsort) std::partial sort (Heapsort) std::stable sort (Mergesort) Running times (divided by n log n) for sorting integers. Left: random inputs. Right: random with large elements in the middle and end. Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) Quicksort, Heapsort, Mergesort Algorithm Fast on average \in place" O(n log n) worst case Quicksort 3 3 7 Heapsort 7 3 3 Mergesort 3 7 3 Wish to have three times 3: Make Quicksort worst-case efficient: Introsort, median-of-medians pivot selection Make Heapsort fast: Bottom-up Heapsort (not very fast) Make Mergesort in-place: block based merging (stable implementations: Grailsort, Wikisort) rotation based merging (stable, but O(n log2 n)) use one half as buffer to sort the other half (In-situ Mergesort [Elmasry, Katajainen, Stenmark 2012], unstable) Outline Outline: QuickMergesort Our improvements and theoretical bounds Experiments After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with Quicksort Quicksort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with Quicksort Quicksort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 5: After line 6: both parts sorted recursively with Quicksort Quicksort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 6: both parts sorted recursively with Quicksort Quicksort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: Quicksort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with Quicksort After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with QuickMergesort QuickMergesort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with QuickMergesort QuickMergesort 1: procedure Quicksort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) Mergesort 5: Quicksort(A[`; : : : ; cut − 1]) 6: Quicksort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with QuickMergesort QuickMergesort 1: procedure QuickMergesort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Mergesort(A[`; : : : ; cut − 1]) 6: QuickMergesort(A[cut;:::; r]) 7: end if 8: end procedure QuickMergesort 1: procedure QuickMergesort(A[`; : : : ; r]) 2: if r > ` then 3: pivot choosePivot(A[`; : : : ; r]) 4: cut partition(A[`; : : : ; r], pivot) 5: Mergesort(A[`; : : : ; cut − 1]) 6: QuickMergesort(A[cut;:::; r]) 7: end if 8: end procedure After line 4: ≤ pivot ≥ pivot After line 5: After line 6: both parts sorted recursively with QuickMergesort 3 2 4 11 9 10 8 7 0 1 5 6 | {z } sort recursively with Mergesort | {z } | {z } merge two parts 90 101 82 113 284 1135 486 7 09 101 115 68 | {z } sort recursively with QuickMergesort 3 2 4 5 6 0 1 7 9 10 11 8 | |{z {z } sortsort with recursively Mergesortwith Mergesort 9 10 8 11 2 3 4 7 0 1 5 6 QuickMergesort 1. Partition according to some pivot element. 2. Sort one part with Mergesort. 3. Sort the the other part recursively with QuickMergesort. 7 11 4 5 6 10 9 2 3 1 0 8 3 2 4 11 9 10 8 7 0 1 5 6 | {z } sort recursively with Mergesort | {z } | {z } merge two parts 90 101 82 113 284 1135 486 7 09 101 115 68 | {z } sort recursively with QuickMergesort 3 2 4 5 6 0 1 7 9 10 11 8 | |{z {z } sortsort with recursively Mergesortwith Mergesort 9 10 8 11 2 3 4 7 0 1 5 6 QuickMergesort 1. Partition according to some pivot element. 2. Sort one part with Mergesort. 3. Sort the the other part recursively with QuickMergesort. 7 11 4 5 6 10 9 2 3 1 0 8 3 2 4 11 9 10 8 7 0 1 5 6 | {z } sort recursively with Mergesort | {z } | {z } merge two parts 90 101 82 113 284 1135 486 7 09 101 115 68 | {z } sort recursively with QuickMergesort 7 11 4 5 6 10 9 2 3 1 0 8 | |{z {z } sortsort with recursively Mergesortwith Mergesort 9 10 8 11 2 3 4 7 0 1 5 6 QuickMergesort 1.