pdqsort排序|青训营笔记

104 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第11篇笔记

1. 为什么要学数据结构和算法

image-20220525124912709

image-20220525130001591

image-20220525130018739

image-20220525130028991

2. 经典排序算法

2.1 插入排序

image-20220525130052558

image-20220525130121617

2.2 快排

image-20220525130133755

image-20220525130143032

2.3 堆排序

image-20220525130157628

image-20220525130207013

image-20220525130217710

image-20220525130228167

image-20220525130241432

image-20220525130249994

image-20220525130259557

image-20220525130310083

3. 从零开始打造pdqsort

3.1 pdqsort

image-20220525130412513

3.2 pdqsort-version1

结合三种排序方法的优点

  • 对于短序列(小于一定长度)我们使用插入排序
  • 其他情况,使用快速排序来保证整体性能
  • 当快速排序表现不佳时,使用堆排序来保证最坏情况下时间复杂度仍然为O(n*logn)

\

image-20220525130433118

image-20220525130443907

image-20220525130453762

3.3 pdqsort-version2

思考关于pivot的选择

  • 使用首个元素作为pivot(最简单的方案)
  • 实现简单,但是往往效果不好,例如在sorted情况下性能很差
  • 遍历数组,寻找真正的中位数
  • 遍历比对代价很高,性能不好

image-20220525130503983

image-20220525130520670

image-20220525130531525

image-20220525130541128

image-20220525130552002
还有什么场景我们没有优化?

  • 短序列情况

    • 使用插入排序(v1)
  • 极端情况

    • 使用堆排序保证算法的可行性(v1)
  • 完全随机的情况(random)

    • 更好的pivot 选择策略(v2)
  • 有序/逆序的情况(sorted/reverse)

    • 根据序列状态翻转或者插入排序(v2)
  • 元素重复度较高的情况(mod8) -> ?

3.4 pdqsort-final version

如何优化重复元素很多的情况?

  • 采样pivot的时候检测重复度? 不是很好,因为采样数量有限,不一定能采样到相同元素
  • 解决方案: 如果两次partition 生成的pivot相同,即partition 进行了无效分割,此时认为pivot的值为重复元素(相比上一种方法有更高的采样率)

image-20220525130603130

优化-重复元素较多的情况(partitionEqual)

  • 当检测到此时的pivot和上次相同时(发生在leftSubArray)使用partitionEqual将重复元素排列在一起,减少重复元素对于pivot选择的干扰

优化-当pivot选择策略表现不佳时,随机交换元素

  • 避免一些极端情况使得QuickSort总是表现不佳,以及一 些黑客攻击情况

image-20220525130631878

image-20220525130647135

image-20220525130659013

image-20220525130718142

\