数据结构与算法-冒泡/插入/选择排序

248 阅读3分钟

数据结构与算法

排序算法比较
排序算法比较

冒泡/插入/选择排序

思考

  • 如何分析一个排序算法
  • 冒泡排序的原理和性能分析
  • 插入排序的原理和性能分析
  • 选择排序的原理和性能分析

如何分析一个排序算法

  1. 最好情况、最坏情况、平均情况时间复杂度
  • 为了对比各种排序算法,有必要分析
  • 有序和无序,性能还有有影响
  1. 时间复杂度的系数、常数、低阶
  • 10,100,1000比较不同排序算法,系数、常数、低阶还是有必要的
  1. 比较次数和交换次数
  • 元素比较大小
  • 元素移动(交换)位置

排序算法的内存消耗:原地排序,空间复杂度为O(1)的排序算法

排序算法的稳定性:元素中存在相同的元素,排序的同时,不改变相同元素的排序位置,前后顺序不变

3, 3, 5, 6 => 6, 5, 3, 3 (3, 3 相对位置不变)

冒泡排序

冒泡排序只会操作相邻的两个数据

JavaScript冒泡排序代码

JavaScript冒泡排序优化代码

  • 冒泡排序是原地排序算法

    • 涉及常量数据的交换,空间复杂度O(1)
  • 冒泡排序是稳定的排序算法

    • 数据相同时,不改变相对位置
  • 冒泡排序的时间复杂度

    • 最好情况O(n)
    • 最坏情况O(n^2)
  • 冒泡排序的平均情况复杂度分析

    • 有序度和逆序度

有序度:有序元素对:a[i] <= a[j], 如果i < j。

逆序度:有序元素对:a[i] < a[j], 如果i > j。

有序度
有序度
冒泡有序度分析
冒泡有序度分析

逆序度 + 有序度 = 满有序度

交换次数总是确定的,初始状态时,要进行n(n-1)/2次交换,最好情况下也就是n(n-1)/2,去中间值n(n-1)/4,冒泡排序的平均情况复杂度O(n^2)

插入排序

分为两个区间,已排序区间和未排序区间,取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入

JavaScript插入排序算法代码

  • 稳定排序算法
  • 原地排序算法
  • 时间复杂度最好O(n),最坏O(n^2)

选择排序

分为两个区间,已排序区间和未排序区间,选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾

JavaScript选择排序算法代码

  • 稳定排序算法
  • 非原地排序算法,顺序不可控制
  • 时间复杂度最好O(n),最坏O(n^2)

插入排序VS冒泡排序

// 冒泡排序中数据的交换操作:
if (a[j] > a[j+1]) { // 交换
   let tmp = a[j];
   a[j] = a[j+1];
   a[j+1] = tmp;
   flag = true;
}

// 插入排序中数据的移动操作:
if (a[j] > value) {
  a[j+1] = a[j];  // 数据移动
else {
  break;
}

推荐用插入排序算法

用冒泡排序,需要 K 次交换操作,每次需要 3 个赋值语句,所以交换操作总耗时就是 3*K 单位时间。而插入排序中数据移动操作只需要 K 个单位时间

希尔排序,插入排序的优化

引用地址