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

103 阅读3分钟

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

一、经典排序算法

1、插入排序

  • 基本思想 插入排序是一种最简单的排序方法,它的基本思想是在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。按照此法对所有元素进行插入,直到整个序列排为有序为止。

  • 过程(升序)

    value3251
    index0123
    • index=1index=0 两者比较,前者大于后者时, index=1 的值插入到 index=0 前面,这时序列的前两者已经排好,进入下一步;
    • index=2index=1 两者比较,前者大于后者, index=2 的值插入到 index=1 前面,重复①,进入下一步;
    • index=3index=2 两者比较,前者大于后者, index=3 的值插入到 index=2 前面,重复②,结束。这时,序列已排好序。
  • Go实现

    image.png

2、快速排序

  • 基本思想 首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它左边,所有比它大的数都放到它右边。利用分治的思想,左右两边分开独立完成上述排序,递归或迭代重复这个过程即可。

  • Go实现

    image.png

3、堆排序

  • 基本思想 在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。堆中定义以下几种操作:

    • 最大堆调整):将堆的末端子节点作调整,使得子节点永远小于父节点
    • 创建最大堆:将堆中的所有数据重新排序
    • 排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算
  • Go实现

    image.png image.png

4、三种算法对比

  • 时间复杂度对比

    bestavgworst
    insertO(n)O(n^2)O(n^2)
    quickO(n * logn)O(n * logn)O(n^2)
    heapO(n * logn)O(n * logn)O(n * logn)

二、bdpsort

1、简介

  • 不稳定的混合排序算法
  • 对常见序列类型做了特殊化的优化,在不同的条件下都拥有不错的性能
  • “不断判定目前的序列情况,然后使用不同的方式和路径达到最优解”

2、version1

个人理解是类似于在快速排序分区后得到pivot再进行算法的选择,序列长度小于24,直接插入排序得到结果;在分区时得到的pivot在序列两端的次数到达limit次,则使用堆排序保持O(n * logn)的性能,其余情况都需要再分区。

image.png

  • 实现 尝试把上述的 quickSort 修改成下面的样子,貌似能实现。

    image.png

3、version2

version1中pivot选取为序列的首个数据,这种选取策略是最简单的,但是很容易产生下图的情况:pivot过于接近序列两端。

image.png

因此,进一步的优化可以从pivot的选择入手。当pivot选取为整个序列的中位数或近似中位数,这是最好的情况。

image.png

4、final version

version2的进一步优化:对pivot重复的情况进行优化,将重复的pivot放在一起,减少快排表现不佳的情况。

image.png

  • final 版本的时间复杂度:

    bestavgworst
    O(n)O(n * logn)O(n * logn)

参考资料

【数据结构与算法 学习资料】第三届字节跳动青训营 - 后端专场