// insertionSortCmpFunc sorts data[a:b] using insertion sort. func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { … } // siftDownCmpFunc implements the heap property on data[lo:hi]. // first is an offset into the array where the root of the heap lies. func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) { … } func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { … } // pdqsortCmpFunc 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 pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) { … } // partitionCmpFunc 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 partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) { … } // partitionEqualCmpFunc 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 partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) { … } // partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end. func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool { … } // breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns // that might cause imbalanced partitions in quicksort. func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { … } // choosePivotCmpFunc 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 choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) { … } // order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) { … } // medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int { … } // medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int { … } func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) { … } func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) { … } func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) { … } // symMergeCmpFunc 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 symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) { … } // rotateCmpFunc 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 rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) { … }