js 算法 - 插入排序

1,672 阅读3分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

插入排序

插入排序是一种简单的排序算法,插入排序将一组数据分为有序区间和无序区间,每次从无序区间找到合适的一个数据插入到有序区间的合适位置,当无序区间没数据,即只剩下有序区间时,这组数据就变为完全有序。

算法描述

假设是从小到大排序

  1. 将一组数据的首个数据组成有序区间,其他数据组成无序区间
  2. 在无序区间抽出首个数据 A
  3. A 依次与有序区间的各个数据进行对比。若遇到数据比 A 大的,则将 A 插入到该数据的前面一个位置,若 A 比有序区间的任何数据都要大,则插入到有序区间末尾。总之,保证插入后的有序区间依然有序。
  4. 重复 2 和 3 操作,直到无序区间没有数据

算法图解

假设一组数据里有:3、5、4、1、2。

“第一次插入”步骤,3 作为一个有序区间,5、4、1、2 作为无序区间。标记无序区间的首个数据 5,与有序区间的数据 3 作对比,5 比 3 大,由于有序区间后面没有数据了,所以 5 插入到有序区间的 3 后面。

1629774503(1).jpg

“第二次插入”步骤,3、5 作为有序区间,4、1、2 作为无序区间。标记无序区间的首个数据 4,与有序区间的 3 作对比,4 比 3 大,因此需要继续与后面一个数据对比。4 与有序区间的 5 作对比,比 5 小,因此 4 插入到有序区间的 5 的前面。

1629774541(1).jpg

“第三次插入”步骤,同样地,标记无序区间的首个数据 1,1 与有序区间的 3 对比,1 比 3 小,插入到 3 的前面。

1629774573(1).jpg

“第四次插入”步骤,无序区间唯一的数据 2,比有序区间的 1 大,比有序区间的 3 小,因此插入 3 的前面。到了这里,整组数据就已经达到了完全有序。

1629774600(1).jpg

有没有发现,插入排序特别像抽扑克牌?

手上的牌是有序区间,放在桌子上的牌堆是无序区间,每次抽牌时,都要依次与手上的每张牌进行对比,并将该牌插入到相应的位置,保证手上的牌有序。当牌堆抽完了,手上的整副扑克牌就是有序了。

代码实现

注意:虽然说需要将数据分为有序区间和无序区间,但是在实现时并不需要申请两个数组(有序数组和无序数组),只需要在原数组进行抽象划分。

// 插入排序
function insertionSort(arr) {
  if (arr.length <= 1) {
    return arr
  }
  for (var i=1; i<arr.length; i++) {
    var j = i - 1 // j 是有序区间的最大下标
    var val = arr[i] // val 是无序区间的首个数据,用来与有序区间的各个数做对比
    for (; j>=0; j--) {
      if (arr[j] > val) { // 由于要求排序从小到大,也就是说 val 比 arr[j] 小的时候,val 需要排在 arr[j] 前面,arr[j] 需要移位
        arr[j+1] = arr[j]
      } else {
        break // 当不需要移位时,由于有序区间是有序的,直接跳出循环即可
      }
    }
    arr[j+1] = val
  }
  return arr
}
原地排序稳定性最好时间复杂度最坏时间复杂度平均时间复杂度
插入排序稳定O(n)O(n²)O(n²)

插入排序其实是可以改进优化的,优化版的插入排序叫希尔排序,后面再做介绍。

js 算法系列文章推荐