放肆青春的博客
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)

放肆青春

一个前端菜鸟的技术成长之路
首页
前端
算法
网络
面试
技术
后端
运维
杂项
数据库
工具
网址
电脑
个人
文章
  • 分类
  • 标签
  • 归档
github (opens new window)
gitee (opens new window)
  • 算法基础

    • 数据结构和算法
    • 算法blog
    • 算法基础
    • 算法思维
  • 算法汇总

    • 常见算法题
    • 穷举算法(枚举算法)
    • 递归
    • 二分法
    • 双指针

      • 双指针
      • 双指针算法题
      • 滑动窗口
      • 滑动窗口算法题
    • 回溯法

      • 回溯法
      • 回溯法算法题
    • 分治算法
    • 贪心算法

      • 贪心算法
      • 贪心算法题
    • 动态规划

      • 动态规划
      • 动态规划算法题
  • 排序算法

    • 排序算法
    • 1. 冒泡排序
    • 2. 选择排序
    • 3. 插入排序
      • 直接插入排序
        • 稳定性
        • 演示图
        • 代码实现
      • 折半插入排序
        • 步骤
    • 4. 希尔排序
    • 5. 归并排序
    • 6. 快速排序
    • 7. 堆排序
    • 8. 计数排序
    • 9. 桶排序
    • 10. 基数排序
  • 数据结构

    • 数组

      • 数组概览
      • 数组算法题
    • 字符串

      • 字符串概览
      • 字符串算法题
    • 树

      • 树概览
      • 树算法题
    • 链表

      • 链表概览
      • 双向链表
      • 链表算法题
    • 队列

      • 队列概览
      • 队列算法题
    • 堆

      • 堆概览
      • 堆算法题
    • 散列表(哈希表)

      • 散列表(哈希表)概览
      • 散列表(哈希表)算法题
    • 栈

      • 栈概览
      • 栈算法题
    • 图

      • 图概览
      • 图算法题
  • algorithm
放肆青春
2021-03-18

3. 插入排序

插入排序的设计初衷是往有序的数组中快速插入一个新的元素. 它的算法思想是: 把要排序的数组分为了两个部分, 一部分是数组的全部元素(除去待插入的元素), 另一部分是待插入的元素; 先将第一部分排序完成, 然后再插入这个元素. 其中第一部分的排序也是通过再次拆分为两部分来进行的.

插入排序由于操作不尽相同, 可分为 直接插入排序 , 折半插入排序(又称二分插入排序), 链表插入排序 , 希尔排序 .

# 直接插入排序

概念:将待排序的元素按照大小顺序, 依次插入到一个已经排好序的数组之中, 直到所有的元素都插入进去.

# 稳定性

由于直接插入排序每次只移动一个元素的位置, 并不会改变值相同的元素之间的排序, 因此它是一种稳定排序.

# 演示图

image

# 代码实现

function directInsertionSort(array) {
  for (var i = 1; i < array.length; i++) {
    var j = i;
    while (j > 0 && array[j] < arr[j - 1]) {
      swap(j, j - 1, array);
      j--;
    }
  }
  return array;
}
1
2
3
4
5
6
7
8
9
10

# 折半插入排序

概念:折半插入排序是直接插入排序的升级版. 鉴于插入排序第一部分为已排好序的数组, 我们不必按顺序依次寻找插入点, 只需比较它们的中间值与待插入元素的大小即可.

同直接插入排序类似, 折半插入排序每次交换的是相邻的且值为不同的元素, 它并不会改变值相同的元素之间的顺序. 因此它是稳定的.

# 步骤

  1. 取 0 ~ i-1 的中间点( m = (i-1)>>1 ), array[i] 与 array[m] 进行比较, 若 array[i] < array[m] , 则说明待插入的元素 array[i] 应该处于数组的 0 ~ m 索引之间; 反之, 则说明它应该处于数组的 m ~ i-1 索引之间.

  2. 重复步骤 1, 每次缩小一半的查找范围, 直至找到插入的位置.

  3. 将数组中插入位置之后的元素全部后移一位.

  4. 在指定位置插入第 i 个元素.

注: x>>1 是位运算中的右移运算, 表示右移一位, 等同于 x 除以 2 再取整, 即 x>>1 == Math.floor(x/2) .

function binaryInsertionSort(array) {
  var current, i, j, low, high, m;
  for (i = 1; i < array.length; i++) {
    low = 0;
    high = i - 1;
    current = array[i];

    while (low <= high) {
      //步骤1&2:折半查找
      m = (low + high) >> 1;
      if (array[i] >= array[m]) {
        //值相同时, 切换到高半区,保证稳定性
        low = m + 1; //插入点在高半区
      } else {
        high = m - 1; //插入点在低半区
      }
    }
    for (j = i; j > low; j--) {
      //步骤3:插入位置之后的元素全部后移一位
      array[j] = array[j - 1];
    }
    array[low] = current; //步骤4:插入该元素
  }
  return array;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

虽然折半插入排序明显减少了查询的次数, 但是数组元素移动的次数却没有改变. 它们的时间复杂度都是 O(n²).

更新时间: 2/10/2022, 7:21:32 PM
2. 选择排序
4. 希尔排序

← 2. 选择排序 4. 希尔排序→

最近更新
01
前端权限管理
02-24
02
vue2指令
02-24
03
vue2 hook
02-24
更多文章>
Theme by Vdoing | Copyright © 2019-2022 放肆青春
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式