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

108 阅读3分钟

目标

  • 数据结构和算法学习重要性说明
  • pdqsort

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

  • 由于项目需求,需要使用Redis数据库,为了保证Redis集群的稳定,需要使用到一些算法。因 此在后端使用某些算法可以降低Redis的压力,所以就需要数据结构和算法。
  • 案例:某时间段,抖音排行榜top10

  • 解决方案:

    • 礼物数量在zset,用skiplist使得元素整体有序
    • 通过主从算法、分片算法,使用Redis集群,避免单机压力过大
    • 一致性算法保证集群信息的稳定
    • LRU降低Redis压力,展示排行
  • 总结:数据结构和算法几乎在于程序开发中的所有地方。

  • 最快排序

    • python-timsort
    • C++-introsort
    • Rust-pdqsort
    • Go排序算法提升——introsort(<=1.8)
    • 现重新实现,在常见常见比之前快大概10倍,成为默认排序算法

2 经典的排序算法

  1. 插入排序:从第二个元素开始与前驱元素进行一一对比,比较结果决定是否移动位置。最好的情况是有序排列的数组,时间复杂度为O(n),平均和最差为O(n^2)。
  2. 快速排序:选pivot,将数组递归分开,用两个指针,分别指向左右两边,一次比较大小,交替进行,时间复杂度最好和平均是O(nlogn),最坏都为O(n^2)。性能处于中间层次
  3. 堆排序:利用不断地调整堆排序,使堆保持最大或最小根堆。通过上滤或下滤的操作来实现调整堆。堆排序最好最坏都为O(nlogn)。

总结:不同场景下需要用不同的排序算法才能达到最好的效果,因此没有排序算法可以说是最快最好的。

根据序列元素排列情况划分:

  • 完全随机的情况(random)

  • 有序/逆序的情况(sorted/reverse)

  • 元素重复度较高的情况(mod8)

  • 在此基础上,还需要根据序列长度的划分(16/128/1024)

  • 根据实际场景的benchmark结论:

    • 在随机的短序列中,插入排序最快,在随机的长序列和中序列中,堆排序和快速排序相差不大。但快排在长序列和中序列中速度最快。
    • 在序列有序中,插入排序在三种情况下都很快,而堆排序相差10倍,快速排序相差几十倍。
    • 大部分情况下,快速排序效果比较好。在任何情况下,堆排序都比较稳定。在短序列情况下,插入排序性能最好

插入-单车 快排-汽车 堆排序-地铁

3 从零开始打造 pdqsort

  • pdqsort(pattern-defeating-quicksort)

    • 不稳定的混合排序
    • 应用在 C++ Boost、rust、go 1.19
    • 对常见的序列类型进行特殊优化
  • version1- 结合经典算法继续切换

    • 短序列(12-32,泛型选24),插入
    • 其他,快排
    • 快排不佳则用堆排序,如何判别:看pivot位置选择
      • 接近两端length/8,次数为limit(bits.Len(length)),切换
  • version2——改进pivot选择,改进partition(虎烈)

    • 关于pivot的选择

      • 使用首个元素作为pivot实现简单,但是往往效果不好
      • 但是寻找中位数的方法又需要遍历数组,性能不好
    • 根据序列长度的不同,来决定选择策略

      • 短序列(<=8),选择固定元素
      • 中序列(<=50)中,我们采集三种元素,寻找他的中位数。从前中后三个位置选取三种元素,选取三个元素中的中位数。
      • 长序列(>50)中,我们采集九种元素,找到它们之间的中位数。
    • 发现序列可能逆序,翻转

    • 发现序列可能有序,有限的插入排序

  • final version

  • 优化——重复元素很多的情况(partitonEqual)

    • 采样时pivot的数量有限,所以不一定会采样到相同的元素
    • 我们可以对两次partition生成的pivot进行比对,如果两个partition生成的pivot相同,则认为此次分割无效。
    • 方案:检测到这次pivot和上次相同,使用partitonEqual将重复元素排列到一起,减少重复元素对pivot选择的干扰
  • 优化-pivot选择策略不佳——随机交换元素

-大致10%-50%的提升

学习心得

  • 高性能算法根据不同情况取长补短开发的
  • 理论注重理论性能,时空复杂度,但是生产环境需要考虑实际场景的实际性能
  • pdqsort做了fallback时机、pivot选择策略、是否对不同pattern优化方面工作
  • 实际开发的优化一定要考虑实际场景

引用

ppt:⁣⁡⁤‬⁢‬⁣‬⁤⁡⁤⁤‌​‬‌⁢⁡‌⁡​⁤​​⁡​‍‬⁢⁣‍​⁢‍‍‬‌‍⁡‬⁡数据结构与算法.pptx - 飞书云文档 (feishu.cn)