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

214 阅读3分钟

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

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

由于项目需求,需要使用Redis数据库,为了保证Redis集群的稳定,需要使用到一些算法。因 此在后端使用某些算法可以降低Redis的压力,所以就需要数据结构和算法。
总结:数据结构和算法几乎在于程序开发中的所有地方。

经典的排序算法

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

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

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

  • 在随机的短序列中,插入排序最快,在随机的长序列和中序列中,堆排序和快速排序相差不大。但快排在长序列和中序列中速度最快。
  • 在序列有序中,插入排序在三种情况下都很快,而堆排序相差10倍,快速排序相差几十倍。
  • 大部分情况下,快速排序效果比较好。在任何情况下,堆排序都比较稳定。在短序列情况下,插入排序性能最好。
所以在应用中,面对短排序一般都用插入排序。如果在开发中,你的快速排序分的两个部分比较少(最终的pivot距离序列的两端很接近),这个时候使用快速排序就不太好,我们可以换位堆排序,因为堆排序在任何情况下都比较稳定。

从零开始打造 pdqsort

  • 关于pivot的选择

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

    • 中序列中,我们采集三种元素,寻找他的中位数。从前中后三个位置选取三种元素,选取三个元素中的中位数。
    • 长序列中,我们采集九种元素,找到它们之间的中位数。
  • 优化重复元素很多的情况

    • 采样时pivot的数量有限,所以不一定会采样到相同的元素
    • 我们可以对两次partition生成的pivot进行比对,如果两个partition生成的pivot相同,则认为此次分割无效。