pdqsort是基于std::sort的改进算法,当数据量小的时候用插入排序,递归深度大的时候用heapsort,其他情况用改良的quicksort
go// pdqsort 对数据 data[a:b] 进行排序。
// 该算法基于 pattern-defeating quicksort (pdqsort),但没有 BlockQuicksort 中的优化。
// pdqsort 论文:https://arxiv.org/pdf/2106.05123.pdf
// C++ 实现:https://github.com/orlp/pdqsort
// Rust 实现:https://docs.rs/pdqsort/latest/pdqsort/
// limit 是在陷入堆排序之前允许的坏(非常不平衡)枢轴的数量。
func pdqsort(data Interface, a, b, limit int) {
const maxInsertion = 12
var (
wasBalanced = true // 上次分区是否相当平衡
wasPartitioned = true // 切片是否已分区
)
for {
length := b - a
if length <= maxInsertion {
insertionSort(data, a, b)
return
}
// 如果坏选择太多,就退回到堆排序。
if limit == 0 {
heapSort(data, a, b)
return
}
// 如果上次分区不平衡,我们需要打破模式。
if !wasBalanced {
breakPatterns(data, a, b)
limit--
}
// 选择枢轴和提示。
pivot, hint := choosePivot(data, a, b)
if hint == decreasingHint {
// 反转范围,以便处理递增顺序的情况。
reverseRange(data, a, b)
// 选择的枢轴在数组开始后的 pivot-a 个元素。
// 反转后,它在数组末尾前的 pivot-a 个元素。
// 这个想法来自于 Rust 的实现。
pivot = (b - 1) - (pivot - a)
hint = increasingHint
}
// 如果切片可能已经排序,则尝试进行局部插入排序。
if wasBalanced && wasPartitioned && hint == increasingHint {
if partialInsertionSort(data, a, b) {
return
}
}
// 可能切片包含许多重复元素,将切片分为等于和大于枢轴的元素。
if a > 0 && !data.Less(a-1, pivot) {
// 如果前一个元素大于等于枢轴,则进行相等分区。
mid := partitionEqual(data, a, b, pivot)
a = mid
continue
}
// 进行普通分区。
mid, alreadyPartitioned := partition(data, a, b, pivot)
wasPartitioned = alreadyPartitioned
leftLen, rightLen := mid-a, b-mid
balanceThreshold := length / 8
if leftLen < rightLen {
wasBalanced = leftLen >= balanceThreshold
pdqsort(data, a, mid, limit)
a = mid + 1
} else {
wasBalanced = rightLen >= balanceThreshold
pdqsort(data, mid+1, b, limit)
b = mid
}
}
}
heapsort
go// siftDown implements the heap property on data[lo:hi].
// first is an offset into the array where the root of the heap lies.
func siftDown(data Interface, lo, hi, first int) {
root := lo
for {
child := 2*root + 1
if child >= hi {
break
}
if child+1 < hi && data.Less(first+child, first+child+1) {
child++
}
if !data.Less(first+root, first+child) {
return
}
data.Swap(first+root, first+child)
root = child
}
}
func heapSort(data Interface, a, b int) {
first := a
lo := 0
hi := b - a
// Build heap with greatest element at top.
for i := (hi - 1) / 2; i >= 0; i-- {
siftDown(data, i, hi, first)
}
// Pop elements, largest first, into end of data.
for i := hi - 1; i >= 0; i-- {
data.Swap(first, first+i)
siftDown(data, lo, i, first)
}
}
insertionsort
go// insertionSort sorts data[a:b] using insertion sort.
func insertionSort(data Interface, a, b int) {
for i := a + 1; i < b; i++ {
for j := i; j > a && data.Less(j, j-1); j-- {
data.Swap(j, j-1)
}
}
}
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!