编辑
2023-12-08
后端
00
请注意,本文编写于 519 天前,最后修改于 518 天前,其中某些信息可能已经过时。

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) } } }

参考: https://mp.weixin.qq.com/s/8qMvwQE9p1UkEYpIR4Dg8A

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!