1、为什么要学习数据结构和算法
例子:抖音直播排行的功能。
Go的排序算法有没有提升空间?
2、经典排序算法
2.1-插入排序:将元素不断插入已经排序号的array中。
插入元素不断交换,直到找到第一个比其小的元素
时间复杂度
最好 O(n) 平均 O(n^2) 最坏 O(n^2)
2.2-快速排序
好和平均是 O(n*logn),最坏是O(n^2)
2.3-堆排序
时间复杂度 情况都是O(n*logn)
小结:
- 插入排序在短序列中速度最快
- 快排在其他情况中速度不大
- 堆排序速度于最快算法差距不大
- 所有短序列和元素有序情况下,插入排序性能最好
- 在大部分的情况下,快速排序有较好的综合性能
- 几乎在任何条件下,堆排序的表现都比较稳定
pdqsort
一种不稳定的混合排序算法。他对常见的排序做了特殊的优化,使得在不同条件下都拥有不错的性能。
version1
当快排他离两段很近,就说明他的状况不加,使用堆排序。
其他的时候就使用快排
version2
要在寻找pivot的开销和pivot带来的性能优化里面寻找近似的中位数。
特点:如果选择中位数一般是选择近似中位数,就是把当前三个数取中位数。因为一般这个数字和真正的中位数比较接近
发现序列可能是逆序,就翻转排序->应对reverse场景
发现序列可能是有序,就翻转排序->应对sort场景
version3 重复度较高
拓展:mp.weixin.qq.com/s/5HqfRGqPy…
Go 1.18 泛型对于排序算法的影响
Go 1.18 的泛型在这种情况下有较大的性能提升并且增加了可维护性,同样的算法在经过泛型改造后能得到 2x 的性能提升。这一点我们通过观察 pdqsort 泛型版本,以及 pdqsort (with sort.Interface) 的版本性能对比可以观察出来。
在可维护性方面,通过泛型的类型约束抽象了所有可比对的基本类型,不需要使用复杂的代码生成技术。
在性能方面,泛型由于有了类型参数,可以在编译期生成大量代码,免去了使用 sort.Interface 带来的抽象开销。
BlockQuickSort 的优化基本来自减少分支预测,原理是在 partition 一个长序列的时候,先存储需要交换的元素,后续统一放到真正的序列中。经过实际性能测试,发现这一优化在 Go 上并不成立,甚至是一个负优化。原因可能由于 Go 是一门 heap-allocate 的语言,对于此类优化并不敏感。并且对于减少分支预测,Go 的编译器在某些情况下并不能优化到相应指令(CMOV)。
这个课程更多的内容是理解和掌握其中的内容和概念,做笔记的地方相对而言比较少。