// insertionSortOrdered sorts data[a:b] using insertion sort. func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) { … } // siftDownOrdered implements the heap property on data[lo:hi]. // first is an offset into the array where the root of the heap lies. func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) { … } func heapSortOrdered[E constraints.Ordered](data []E, a, b int) { … } // pdqsortOrdered 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 pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) { … } // partitionOrdered 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 partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) { … } // partitionEqualOrdered 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 partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) { … } // partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end. func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool { … } // breakPatternsOrdered scatters some elements around in an attempt to break some patterns // that might cause imbalanced partitions in quicksort. func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) { … } // choosePivotOrdered 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 choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) { … } // order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a. func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) { … } // medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c. func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int { … } // medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a. func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int { … } func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) { … } func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) { … } func stableOrdered[E constraints.Ordered](data []E, n int) { … } // symMergeOrdered 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 symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) { … } // rotateOrdered 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 rotateOrdered[E constraints.Ordered](data []E, a, m, b int) { … }