// insertionSort_func sorts data[a:b] using insertion sort. func insertionSort_func(data lessSwap, a, b int) { … } // siftDown_func implements the heap property on data[lo:hi]. // first is an offset into the array where the root of the heap lies. func siftDown_func(data lessSwap, lo, hi, first int) { … } func heapSort_func(data lessSwap, a, b int) { … } // pdqsort_func sorts data[a:b]. // The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort. // pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf // C++ implementation: https://github.com/orlp/pdqsort // Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/ // limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort. func pdqsort_func(data lessSwap, a, b, limit int) { … } // partition_func does one quicksort partition. // Let p = data[pivot] // Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot. // On return, data[newpivot] = p func partition_func(data lessSwap, a, b, pivot int) (newpivot int, alreadyPartitioned bool) { … } // partitionEqual_func partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot]. // It assumed that data[a:b] does not contain elements smaller than the data[pivot]. func partitionEqual_func(data lessSwap, a, b, pivot int) (newpivot int) { … } // partialInsertionSort_func partially sorts a slice, returns true if the slice is sorted at the end. func partialInsertionSort_func(data lessSwap, a, b int) bool { … } // breakPatterns_func scatters some elements around in an attempt to break some patterns // that might cause imbalanced partitions in quicksort. func breakPatterns_func(data lessSwap, a, b int) { … } // choosePivot_func chooses a pivot in data[a:b]. // // [0,8): chooses a static pivot. // [8,shortestNinther): uses the simple median-of-three method. // [shortestNinther,∞): uses the Tukey ninther method. func choosePivot_func(data lessSwap, a, b int) (pivot int, hint sortedHint) { … } // order2_func returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. func order2_func(data lessSwap, a, b int, swaps *int) (int, int) { … } // median_func returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. func median_func(data lessSwap, a, b, c int, swaps *int) int { … } // medianAdjacent_func finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. func medianAdjacent_func(data lessSwap, a int, swaps *int) int { … } func reverseRange_func(data lessSwap, a, b int) { … } func swapRange_func(data lessSwap, a, b, n int) { … } func stable_func(data lessSwap, n int) { … } // symMerge_func merges the two sorted subsequences data[a:m] and data[m:b] using // the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum // Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz // Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in // Computer Science, pages 714-723. Springer, 2004. // // Let M = m-a and N = b-n. Wolog M < N. // The recursion depth is bound by ceil(log(N+M)). // The algorithm needs O(M*log(N/M + 1)) calls to data.Less. // The algorithm needs O((M+N)*log(M)) calls to data.Swap. // // The paper gives O((M+N)*log(M)) as the number of assignments assuming a // rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation // in the paper carries through for Swap operations, especially as the block // swapping rotate uses only O(M+N) Swaps. // // symMerge assumes non-degenerate arguments: a < m && m < b. // Having the caller check this condition eliminates many leaf recursion calls, // which improves performance. func symMerge_func(data lessSwap, a, m, b int) { … } // rotate_func rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data: // Data of the form 'x u v y' is changed to 'x v u y'. // rotate performs at most b-a many calls to data.Swap, // and it assumes non-degenerate arguments: a < m && m < b. func rotate_func(data lessSwap, a, m, b int) { … }