数据结构与算法 | 青训营笔记

127 阅读2分钟

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

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

真实案例:实现抖音直播间排行榜

规则:在某个时间段内,直播间礼物数TOP10房间获得奖励,需要在每个直播间展示排行榜

解决方案

  1. 礼物数量存储在 Redis-zset 中,使用 skiplist 使元素整体有序
  2. 使用 Redis 集群,避免单机压力过大,使用 主从算法分片算法
  3. 保证集群原信息稳定,使用 一致性算法
  4. 后端使用 缓存算法(LRU) 降低 Redis 压力,展示房间排行榜

什么是最快的排序算法

单线程下,编程语言自带的排序算法

python 的 timsort

C++ introsort

Rust 的 pdqsort

Go的排序算法有没有提升的空间?

经典排序算法

插入排序

  1. 最优时间复杂程 O(n),
  2. 平均时间复杂度 O(n^2)
  3. 最坏时间复杂度 O(n^2)
  4. 但是已经是比较排序中最优的算法了

快速排序

采用分治思想

  1. 最优时间复杂程 O(n*logn),
  2. 平均时间复杂度 O(n*logn)
  3. 最坏时间复杂度 O(n^2)

堆排序

构造一个大顶堆(根节点元素为最大的元素)

  1. 最优时间复杂程 O(n*logn),
  2. 平均时间复杂度 O(n*logn)
  3. 最坏时间复杂度 O(n*logn)

image-20220526001915795

从零打造 pdqsort

image-20220526002527327

version 1

需要解决的问题

  1. 短序列的具体长度是多少

    给出的建议是12~32,在不同语言和场景中不同,在泛型版本,根据测试选定24

  2. 如何得知快速排序不佳,以及何时切换到堆排序

    当最终选择的分割点的位置离序列两端很接近时,(距离小于 length/8),判断其表现不佳,当这种情况达到一定次数时,切换到堆排序

version 2

优化快排的 pivot

  1. 短序列(<=8) 选择固定元素即可
  2. 中序列 (<=50)采样三个元素,选取其中的中位数
  3. 长序列,采样九个元素,选取中位数

Pivot 的采样方式使得我们有探知序列当前状态的能力

  1. 如果采用数为逆序,则反转序列
  2. 如果采样数为正序,则使用 有限制次数的 插入排序

final version

对重复元素较多的情况进行优化

问题?

如何判断序列的重复元素很多呢?

如果两次生成的 pivot 是相同的,则认为进行了无效分割,则认为 pivot 就是重复元素

就将 pivot 相同的值排列到一起

final version 版本也就是 go 1.19默认的排序算法


总结

通过这个课程可以了解到,工程实践过程中和学校课程中的数据结构和算法的区别。没有完美的算法,在实际生产环境中,单一的算法更不可能胜任所有的场景,我们可以取长补短,在不同的场景下,发挥算法的最大优势。