CS61B笔记 | Sorting

选择排序

  • 扫描整个数组找出最小的元素
  • 交换到已排序部分的末尾
  • 循环往复
    时间复杂度O($N^2$)
    一遍一遍找最小项

  • 数组元素依次添加进最大堆 O($NlogN$)
  • 从堆中取元素进入新的数组 O($NlogN$)
    总共的时间复杂度O($NlogN$),这比选择排序要好。空间复杂度O(N),因为有两个额外数组。

原地堆排序

  • 一个数组,它不是堆,但我们假装它是堆,从堆的底部出发,让每一个元素下沉。在下沉了所有元素之后,排序也就完成了。
  • 使用最大堆
    总共的时间复杂度O($NlogN$),但是摆脱了所有额外内存,空间复杂度为O(1)

归并排序

如果有两个小数组,如何得到一个大的数组?

  • 对选择排序的一个改进:把它分成两半,对每一半进行选择排序,然后再选择排序合并回来。
  • 如果这两半再分裂成两半呢?我们需要两次合并。

归并排序的核心思想是将数组分为两半,递归地对每一半进行归并排序,最后将两部分合并成一个有序的数组。
时间复杂度O($NlogN$)
如果有两个小数组,如何得到一个大的数组

归并排序是所有这些性能最稳定的算法。

插入排序

  • 类似于玩扑克牌时的整理方式,即逐个将牌插入到已排序的部分中。插入排序对于已经部分排序的数据有很好的性能,具有稳定性,且实现起来相对简单。
    时间复杂度O($N^2$)
    旅行操作,在那里找出元素需要去哪里
  • 如果是一个有序数组,更改了其中某一个元素,重新排序时选择插入排序将会是最快的!
    • 如果数组非常小,插入排序将会是最快的!(如果数组大小约为15或者更小,插入排序快于归并排序)
  • 在JAVA中,归并排序的实现是分割数组到足够小(并不会到1),直接进行插入排序。结果证明,在现实生活中它更快。

快速排序

Hello 算法对快速排序的介绍
复杂度:

  • 最优情况下时间复杂度 O($NlogN$)
  • 在处理已排序数组时,出现最坏时间复杂度 O($N^2$)
  • 给一个随机数组,O($NlogN$)的概率极高

关键操作:分区
二叉搜索树的中序遍历快速排序,其实是相同的。

快速排序速度比归并排序更快

如何规避 O($N^2$)复杂度?

  1. 提前检查数组是否有序,如果有序丢给归并排序或者插入排序。
  2. 打乱数组重新排序。
  3. 随机选取基准值。

复杂度数学分析

$NlogN$ = $logN!$ 可以把他们看成相等的。
结论:堆排序、归并排序、快速排序都是最快的排序,找不到比他们更快的了!(从渐进分析的角度来看) 仅适用于比较算法

基数排序/逐位排序

先按个位排序,再按十位排序,再按百位排序

MSD最高有效位优先
LSD最低有效位优先

计数排序

如果不进行比较,那么就能规避O($NlogN$)时间复杂度上限。
非基于比较的排序是根据键值本身的定位特征来决定位置的,因此就不需要根据其键值的比较来决定其前后位置关系。
计数排序的时间复杂度是O(n+k),其中n是待排数列长度,而k则是对应进制的基数。
b站视频链接
计数排序可视化

posted @ 2024-10-30 17:51  Merakii  阅读(28)  评论(0)    收藏  举报