插入排序

70 阅读4分钟

一. 选择排序

function insertionSort(arr) {
  const len = arr.length;
  // 从数组的第二个元素开始,因为第一个元素默认已排序
  for (let i = 1; i < len; i++) {
      // 取出当前要插入的元素,就像从桌上拿起一张牌
      let key = arr[i];
      // 已排序部分的最后一个元素的索引
      let j = i - 1;

      // 在已排序部分从后往前比较,找到合适的插入位置
      while (j >= 0 &&  key < arr[j]) {
          // 如果当前元素大于 key,就把它往后挪一个位置,就像把牌往后挪
          arr[j + 1] = arr[j];
          // 继续往前比较
          j--;
      }

      // 插入元素,把牌放到合适的位置
      arr[j + 1] = key;
  }

  return arr;
}

// 测试数组
const array = [5, 3, 8, 4, 2];
const sortedArray = insertionSort(array);
console.log(sortedArray); 

思路:

类似打扑克牌

  1. 先取第一张,然后是后面几张牌;
  2. 后面几张牌,从左至右,先取左边第一张;
  3. 将左边第一张和取出的第一张比较,根据大小比较,确定是否交换顺序;
  4. 已经排序的有两条数据,再取后面的数据,从左至右,取左边第一张;
  5. 将取出的第一张和已排序的数据比较,从右至左,先和已排序的最右边的数据比较,比较大小,确定是否交换顺序,如果不需要交换,则停止,如果需要交换 , 则继续从左去比较数据

二.总结

插入排序(Insertion Sort)是一种简单直观的排序算法,其工作原理与整理扑克牌的方式类似。下面从算法原理、排序步骤、代码实现、复杂度分析、稳定性等多个方面详细介绍插入排序。

算法原理

插入排序将数组分为已排序和未排序两部分。初始时,已排序部分仅包含数组的第一个元素,其余元素构成未排序部分。之后,依次从未排序部分取出元素,将其插入到已排序部分的合适位置,使得插入后已排序部分仍然保持有序,不断重复该过程,直至整个数组有序。

排序步骤

假设我们要对数组 [5, 3, 8, 4, 2] 进行升序排序,插入排序的具体步骤如下:

初始状态

将数组的第一个元素 5 视为已排序部分,[3, 8, 4, 2] 为未排序部分。此时已排序数组为 [5],未排序数组为 [3, 8, 4, 2]

第一轮插入
  • 从未排序部分取出第一个元素 3
  • 将 3 与已排序部分的元素从后往前比较,即先与 5 比较,发现 3 < 5
  • 把 5 往后移动一位,将 3 插入到原来 5 的位置。此时已排序数组变为 [3, 5],未排序数组变为 [8, 4, 2]
第二轮插入
  • 取出未排序部分的第一个元素 8
  • 将 8 与已排序部分的元素从后往前比较,先与 5 比较,8 > 5,所以 8 直接放在 5 后面。此时已排序数组变为 [3, 5, 8],未排序数组变为 [4, 2]
第三轮插入
  • 取出未排序部分的第一个元素 4
  • 将 4 与已排序部分的元素从后往前比较,先与 8 比较,4 < 8,把 8 往后移动一位;再与 5 比较,4 < 5,把 5 往后移动一位;接着与 3 比较,4 > 3,将 4 插入到 3 后面。此时已排序数组变为 [3, 4, 5, 8],未排序数组变为 [2]
第四轮插入
  • 取出未排序部分的最后一个元素 2
  • 将 2 与已排序部分的元素从后往前比较,依次将 8543 往后移动一位,最后将 2 插入到最前面。此时整个数组排序完成,变为 [2, 3, 4, 5, 8]

算法特点

  • 时间复杂度

    • 最好情况:O(n)(数组已经有序)
    • 最坏情况:O(n²)(数组逆序)
    • 平均情况:O(n²)
  • 空间复杂度:O(1)(原地排序,只需要常数级别的额外空间)

  • 稳定性:插入排序是稳定的排序算法,即相同关键字的元素在排序后相对位置不变。

  • 适用性:对于小规模数据或基本有序的数据,插入排序性能较好。然而,对于大规模无序数据,其性能较差。

难点总结

arr[j+1]=current代码解析; 有两种情况,一种是一直循环,直到j=-1,这时赋值arr[0]=current即可,另一种是没有轮询到j=-1提前结束,比如轮询到j的时候,发现不需要替换,但是上一步j+1位置已经赋值并预留了替换的位置了,上一步j+1的值已经后移到j+2的位置了,所以arr[j+1]赋值current就可以了