排序
字数: 0
Sorting

冒泡排序

Bubble sort
  • 如果元素本来就是有序的,那么一趟冒泡排序既可以完成排序工作,比较和移动元素的次数分别是 n-1 和 0,因此最好情况的时间复杂度为
  • 如果数据元素本来就是逆序的,那么进行 n-1 趟排序,所需比较和移动次数分别为 ,因此最坏情况子下的时间复杂度为

步骤

  • 比较相邻的元素,如果第一个比第二个大,就交换它们两个
 

选择排序

Selection sort

步骤

  • 在未排序序列中找到最小元素,将其与未排序序列的起始元素交换
  • 从剩余未排序元素中继续寻找最小元素,然后与剩余未排序序列的起始元素再交换

插入排序

Insertion sort
  • 最坏情况:
    • 外层循环
    • 内层循环
  • 最好的情况(已经有序):
    • 内层循环:

步骤

notion image
  • 把序列的第二个元素到最后一个元素当成是未排序序列
  • 从头到尾依次扫描未排序序列,将扫描到的每个元素插入已排序序列的适当位置

计数排序

Counting sort牺牲内存空间来换取低时间复杂度的算法

基础版

  • 找出待排序的数组中最大值
  • 统计数组中每个值为 i 的元素出现的次数,存入计数数组 C 的第 i 项

优化版

基础版能够解决一般的情况,但是它拥有空间浪费的缺陷。
  • 比如一组数据 {101, 109, 108, 102, 110, 107, 103},按照基础版则需要创建一个长度为 111 的计数数组,但是前面的 [0, 100] 的空间根本没有使用
  • 即不仅要找出最大值,还要找出最小值,根据两者的差来确定计数数组的长度

进阶版

进行累加操作,使计数数组存储的元素值,等于原始数组中相应元素的最终排序位置
🧻
例如:arr = [5, 3, 1, 1] 计数后: count = [2, 0, 1, 0, 1] 累加后: count = [2, 2, 3, 3, 4]
原数组元素
1
2
3
4
5
Count
2
3
3
3
4
  • 倒序遍历会更稳定(待补充)
即目标数组
  • 第 2 项 是 1
  • 第 3 项 是 3
  • 第 4 项 是 5

归并排序

Merge sort
 
notion image
共有 个数
Divide
  • 第一层,分为 2 个子区间
  • 第二层,分为 4 个子区间
  • 第三层,分为 8 个子区间 …
Conquer
  • 在第 层(最底层),每个子区间的长度为 1,共 个子区间,每相邻两个子区间进行合并,总共合并 次 …
这个时间复杂度是稳定的,不随需要排序的序列不同而产生波动。

快速排序

Quick sort
参考视频

  • 快速排序算法不检查输入数组是否有序,它始终尝试对其进行排序。
    • 一些特殊情况中,数组不会被分成两半,而是拥有一个空的子数组。
    • 比如数据(局部)有序或者数字完全相同等
  • 最好的情况:每次选的 pivot 几乎能把数据均分成两半,这样递归树的深度是 ,快排的时间复杂度为
  • 最坏的情况:每次找的 pivot 将数组分成两部分,其中有一部分是空,这样递归树就变成了一棵倾斜的树。树的深度为 ,快排的时间复杂度变成
    • 解决方法:选 pivot 的时候随机选,而不是每次选第一个或者最后一个。
  • 平均情况

步骤

  • 从数组中随意选择一个基准元素 (pivot element) (假设取第一个)
  • 设置左右两个指针
    • 一个从最右边开始往左找比基准值小的数(右边先走)
    • 一个从最左边开始往右找比基准值大的数
  • 找到后将它们指向的数字进行交换
    • 即比基准数小的元素放左边,大的放右边
  • 不断重复前两步,直到左右指针相遇left>=righ
  • 停下来之后,将当前指针的位置与这一轮基准数进行交换,并重新设置基准数
 
 
notion image

相关代码

 

课件选择最后一个为 privot
notion image
notion image
notion image

快速选择

基于快速排序的算法:在数组中快速找到一个排名第 k 大或者第 k 小的元素
  • 法一:进行完整的快速排序过程(代码和上方相同)
    • (第 k 大)升序排序后,输出 nums[nums.length - k]
  • 法二:没必要进行整体的排序,只需要找到满足条件的元素即可
    • 参数选择 right=k,输出 nums[k]
2023 - 2026