这是我参与「第三届青训营 -后端场」笔记创作活动的的第四篇笔记
数据结构与算法
为什么要学习数据结构和算法
数据结构和算法几乎存在于程序开发的所有地方
经典排序算法
插入排序
将元素不断插入已经排序好的 array中 起始只有一个元素5,其本身是一个有序序列 后续元素插入有序序列中,即不断交换,直到找到第一个比其小的元素
-
缺点 平均和最坏情况的时间复杂度高达0(n^2)
-
优点 最好情况时间复杂度为o{n)
快速排序
通过选定一个pivot (轴),再从这个轴开始对序列进行分割,分成元素比pivot轴更大和元素比pivot轴更小两个序列,进而通过比较、交换,最终达到有序序列。
- 缺点 最坏情况的时间复杂度高达0(n^ 2)
- 优点 平均情况的时间复杂度为0(n*logn)
堆排序
堆排序是建立在树的基础上,利用堆的性质形成的排序算法,构造一个大根堆,再将根节点(最大元素)交换到最后一个位置,调整整个堆,如此反复
- 缺点 最好情况的时间复杂度高达0 (n*logn)
- 优点 最坏情况的时间复杂度为0 (n*logn)
Benchmark
使用规则
- 所有短序列和元素有序情况下,插入排序性能最好
- 在大部分的情况下,快速排序有较好的综合性能
- 几乎在任何情况下,堆排序的表现都比较稳定
从零开始打造pdqsort
pdqsort简介
pdqsort (pattern-defeating- quicksort)是一种不稳定的混合排序算法,它的不同版本被应用在C++BOOST. Rust 以及Go 1.19 中。它对常见的序列类型做了特殊的优化,使得在不同条件下都拥有不错的性能
-
关于pivot的选择
- 使用首个元素作为pivot实现简单,但是往往效果不好
- 但是寻找中位数的方法又需要遍历数组,性能不好
-
根据序列长度的不同,来决定选择策略
- 中序列中,我们采集三种元素,寻找他的中位数。从前中后三个位置选取三种元素,选取三个元素中的中位数。
- 长序列中,我们采集九种元素,找到它们之间的中位数。
-
优化重复元素很多的情况
- 采样时pivot的数量有限,所以不一定会采样到相同的元素
- 我们可以对两次partition生成的pivot进行比对,如果两个partition生成的pivot相同,则认为此次分割无效