插入排序算法是所有排序方法中最简单的一种算法,其主要的实现思想是将数据按照一定的顺序一个一个的插入到有序的表中,最终得到的序列就是已经排序好的数据。

直接插入排序是插入排序算法中的一种,采用的方法是:在添加新的记录时,使用顺序查找的方式找到其要插入的位置,然后将新记录插入。

很多初学者所说的插入排序,实际上指的就是直接插入排序算法,插入排序算法还包括折半插入排序2-路插入排序表插入排序希尔排序等,后序文章都会一一讲到。

所以要完成插入排序,就需要找到这个待插入元素的位置。下面我们一起看看插入排序的具体操作原理。

插入排序的原理


插入排序实际上把待排序的数列分为了两部分,一部分已排好序,另一部分待排序。我们下面还是以一组实际数据为例进行讲解。例如采用直接插入排序算法将无序表{3,1,7,5,2,4,9,6}进行升序排序的过程为:

  • 首先考虑记录 3 ,由于插入排序刚开始,有序表中没有任何记录,所以 3 可以直接添加到有序表中,则有序表和无序表可以如图所示:
  • 向有序表中插入记录 1 时,同有序表中记录 3 进行比较,1<3,所以插入到记录 3 的左侧,如图所示:
  • 向有序表插入记录 7 时,同有序表中记录 3 进行比较,3<7,所以插入到记录 3 的右侧,如图所示:
  • 向有序表中插入记录 5 时,同有序表中记录 7 进行比较,5<7,同时 5>3,所以插入到 3 和 7 中间,如图所示:
  • 向有序表插入记录 2 时,同有序表中记录 7进行比较,2<7,再同 5,3,1分别进行比较,最终确定 2 位于 1 和 3 中间,如图所示:
  • 照此规律,依次将无序表中的记录 4,9 和 6插入到有序表中,如图所示:

接下来我们总结一下直接插入排序的整个执行过程:

  1. 首先需要明确待排序的数列由两部分组成,一部分是已排好序的部分,另一部分是待排序的部分;
  2. 接着我们每次选择待排序的部分的第 1 个元素,分别与前面的元素进行比较。当大于前面的元素时,可以直接进入已排好序的部分;当小于前面的元素时,需要把这个元素拿出来,将前面的元素后移一位,继续与前面的元素相比,直到比较完数组的第 1 个元素或者出现一个元素小于我们拿出来的这个元素,这时停止比较、移动,直接把这个元素放到当时的空位上;
  3. 一直重复步骤 2,当待排序的部分已经没有元素可进行插入时,停止操作,当前的数列为已排好序的数列。

插入排序的实现


插入排序的实现代码已经可以写出来了。首先外层肯定有个大循环,循环这个待排序的部分的数列,内层是分别与前 1 个元素进行比较、移动,直到找到位置进行插入为止。

下面我们看看插入排序的代码实现。

public class InsertSort {public static void main(String[] args) {int[] array = {5, 9, 1, 9, 5, 3, 7, 6, 1}; // 待排序数组sort(array);print(array);}/** 从小到大 */public static void sort(int array[]) {int length = array.length;// 循环待排序的部分的数列// 第一个数据(下标为0的数据)由于插入排序刚开始,有序表中没有任何记录,可以直接添加到有序表中for (int i = 1; i < length; i++) {int temp = array[i];int j = i;// 如果前面的元素小于temp,则向后移for (; j > 0 && array[j - 1] > temp; j--) {array[j] = array[j - 1];}// 前一个元素(array[j - 1])和后一个元素(array[j])是相同的// 在下一轮时,当array[j - 1]小于或等于temp时,将temp插入array[j](即上一轮的array[j - 1])array[j] = temp;}}/*** 打印数组*/public static void print(int array[]) {for (int i = 0; i < array.length; i++) {System.out.print(array[i] + "   ");}System.out.println();}
}

插入排序的特点及性能


插入排序的操作很简单,而且我们通过上面的实例及原理可以知道,插入排序在数列近似有序时,效率会比较高,因为这样会减少比较和移动的次数。

插入排序的时间复杂度是 O(n2),我们会发现这个实现是个双重嵌套循环,外层执行n遍,内层在最坏的情况下执行 n 遍,而且除了比较操作还有移动操作。最好的情况是数列近似有序,这时一部分内层循环只需要比较及移动较少的次数即可完成排序。如果数列本身已经排好序,那么插入排序也可以达到线性时间复杂度及 O(n),所以我们应该明确地认识到,使用插入排序算法进行排序时,数列越近似有序,性能就越高。

插入排序的空间复杂度是 O(1),是常量级的,由于在采用插入排序时,我们只需要使用一个额外的空间来存储这个“拿出来”的元素,所以插入排序只需要额外的一个空间去做排序,这是常量级的空间消耗。

插入排序是稳定的,由于是数组内部自己排序,把后面的部分按前后顺序一点点地比较、移动,可以保持相对顺序不变,所以插入排序是稳定的排序算法

插入排序的适用场景


插入排序的性能并不是很好,和冒泡排序也算是“难兄难弟”了。但插入排序也有一个好处就是所占用的空间很少,只有一个存储临时变量的额外空间就够了。

插入排序由于其时间复杂度并不是很好,所以很少会被单独使用。在所有的基本排序算法中,在一般情况下我们可以直接选择快速排序,因为这个排序算法已经够用了。

由于在数列近似有序时,性能会比较好,而且对于元素较少的情况,时间复杂度就算是 O(n2) 也不会消耗太多的性能,所以插入排序并非一无是处。

前面提到,在快速排序的分区规模达到一定的值比如 10 时,我们会改用插入排序算法去排序那个分区的数据。而快速排序的最后的数据往往是近似有序的,所以使用快速排序的性能并不一定会有多好,这时使用插入排序的实际性能往往会更好些。所以很多编程语言在内部对快速排序的实现也是在分区的元素数量达到了一定小的规模时,改用插入排序对分区的数据元素进行排序操作。

插入排序的优化


下面的优化就不写代码了,感兴趣的可以自己百度一下。

  • 折半插入排序算法(折半排序算法)

前面介绍了直接插入排序算法的理论实现和具体的代码实现,如果你善于思考就会发现该算法在查找插入位置时,采用的是顺序查找的方式,而在查找表中数据本身有序的前提下,可以使用折半查找来代替顺序查找,这种排序的算法就是折半插入排序算法。

折半插入排序算法相比较于直接插入排序算法,只是减少了关键字间的比较次数,而记录的移动次数没有进行优化,所以该算法的时间复杂度仍是 O(n2)。

  • 2-路插入排序算法

2-路插入排序算法是在折半插入排序的基础上对其进行改进,减少其在排序过程中移动记录的次数从而提高效率。

具体实现思路为:另外设置一个同存储记录的数组大小相同的数组 d,将无序表中第一个记录添加进 d[0] 的位置上,然后从无序表中第二个记录开始,同 d[0] 作比较:如果该值比 d[0] 大,则添加到其右侧;反之添加到其左侧。

在这里的数组 d 可以理解成一个环状数组。

2-路插入排序相比于折半插入排序,只是减少了移动记录的次数,没有根本上避免,所以其时间复杂度仍为O(n2)。

  • 表插入排序算法

前面所介绍到的三种插入排序算法,其基本结构都采用数组的形式进行存储,因而无法避免排序过程中产生的数据移动的问题。如果想要从根本上解决只能改变数据的存储结构,改用链表存储。

表插入排序,即使用链表的存储结构对数据进行插入排序。在对记录按照其关键字进行排序的过程中,不需要移动记录的存储位置,只需要更改结点间指针的指向。

与直接插入排序相比只是避免了移动记录的过程(修改各记录结点中的指针域即可),而插入过程中同其它关键字的比较次数并没有改变,所以表插入排序算法的时间复杂度仍是O(n2)。

排序算法 | 插入排序算法原理及实现和优化相关推荐

  1. c++排序算法ppt_C/C++学习教程:C语言排序算法—插入排序算法

    前言:插入排序算法是所有排序方法中最简单的一种算法,其主要的实现思想是将数据按照一定的顺序一个一个的插入到有序的表中,最终得到的序列就是已经排序好的数据. 直接插入排序是插入排序算法中的一种,采用的方 ...

  2. C/C++学习教程:C语言排序算法—插入排序算法

    前言:插入排序算法是所有排序方法中最简单的一种算法,其主要的实现思想是将数据按照一定的顺序一个一个的插入到有序的表中,最终得到的序列就是已经排序好的数据. 直接插入排序是插入排序算法中的一种,采用的方 ...

  3. 冒泡排序、选择排序、插入排序算法及时间复杂度详解

    冒泡.选择.插入排序算法及其时间复杂度详解 冒泡排序 选择排序 插入排序 冒泡排序 流程: 把0到N个元素中的最大值放在N位置 把0到N-1个元素中的最大值放在N-1位置 把0到N-2个元素中的最大值 ...

  4. JavaScript排序算法——插入排序算法

    // 插入排序-原理解释:从数组第二项开始循环,每次循环取当前项与前边的项对比,符合条件则交换位置.function insertSort(array) { // 从第二个元素开始循环for (var ...

  5. Java算法--插入排序算法

    package com.zhangxueliang;/*** 插入排序*/ public class InsertionSort {public static void main(String[] a ...

  6. java 合并排序算法、冒泡排序算法、选择排序算法、插入排序算法、快速排序...

    算法是在有限步骤内求解某一问题所使用的一组定义明确的规则.通俗点说,就是计算机解题的过程.在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法.前者是推理实现的算法,后者是操作实现的算法. ...

  7. 插入排序算法(基于Java实现)

    title: 插入排序算法(基于Java实现) tags: 插入算法 插入排序算法原理及代码实现: 一.插入排序算法的原理 首先,我们将数组中的数据分为两个区间,已排序区间和未排序区间.初始已排序区间 ...

  8. 十大经典排序算法-快速排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

  9. 十大经典排序算法-归并排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

最新文章

  1. Twitter 禁止未经用户同意分享照片和视频
  2. OVS DPDK vhost-user详解(十三)
  3. adcclk最大_STM32 ADC转换时间
  4. Python入门--__init__,__new__
  5. C#_基础:排序算法
  6. Java:用Lambda表达式简化代码一例
  7. 工程伦理 期末考试答案2022夏
  8. Hart/Hart-IP协议 介绍、分析和应用
  9. [内核内存] [arm64] 内存初始化4---bootm_init
  10. 强大视频电影播放软件——乐鱼影音盒!
  11. ubuntu如何看到隐藏文件夹
  12. 使用Vue获取外网ip地址
  13. DDIM代码详细解读(1):数据集加载、类别条件信息读取、关键超参数解析
  14. 拼字 公式_蒸汽机的未来,3D拼字游戏等等
  15. 数据平台作业调度系统详解-实践篇
  16. python队列的实现
  17. mac屏幕保护SaveHollywood安装方法
  18. Windows常用操作—热键(快捷键)
  19. 活体检测CDCN学习笔记
  20. 在线html编辑器 富文本转为html代码

热门文章

  1. 深信服python开发笔试_深信服 python开发 北京 笔试一面二面 面经
  2. 偏斜度与峰度计算 python 与 numpy 实现
  3. 2021年场(厂)内专用机动车辆安全管理新版试题及场(厂)内专用机动车辆安全管理模拟考试题
  4. 《美丽的京剧》——市场调研
  5. 真正可行的canon ip1000清零软件使用方法.
  6. 2020年中国保险科技行业发展现状及未来发展潜力分析[图]
  7. 远程控制阀门和限位开关
  8. 循环式:While ... Wend
  9. (附源码)SSM校园食堂订餐系统JAVA计算机毕业设计项目
  10. glibc: ld.so;ld; LD_LIBRARY_PATH; rpath-link