前言

这次我们介绍插入类排序中的 直接插入排序希尔排序

对于直接插入排序,虽然它的时间复杂度也是 O(n^2) ,但是在元素 有序或近乎有序 的情况下,时间复杂度可以降为 O(n) ,效率比 O(nlogn) 的算法还要高。

然而对于大规模的乱序数组,使用直接插入排序的效率是非常低的。此时我们需要使用希尔排序,希尔排序在直接插入排序的基础上,弥补了直接插入排序只能比较相邻元素的不足,使得可以按照指定步长比较元素,充分发挥了直接插入排序对于小规模有序数组排序的优势。

下面我们分别介绍 直接插入排序希尔排序 两类插入排序。

直接插入排序

有如下数组,我们需要对它从小到大排序,利用直接插入排序步骤如下:

  1. 将第二个元素和第一个元素比较,小于第一个元素的话交换位置,这样第二个元素作为最小的元素排在了最前面,大于的话不交换。
  2. 然后将第三个元素和第二个元素比较,小于第二个元素的话交换位置,然后再和第一个元素比较,小于第一个元素的话再次交换位置,这样第三个元素作为最小的元素排在了最前面,大于的话不交换。
  3. 以此类推,直到最后一个元素插入到合适位置。

下图展示了整个排序的过程:

直接插入排序的代码:

public static void sort(Comparable[] arr) {    int n = arr.length;    // 0位置不需要比,从1到最后一个位置n-1    for (int i = 1; i <= n - 1; i++) {        for( int j = i; j > 0 && arr[j].compareTo(arr[j-1]) < 0 ; j--) {            swap(arr, j, j-1);        }    }}private static void swap(Object[] arr, int i, int j) {    Object t = arr[i];    arr[i] = arr[j];    arr[j] = t;}

优化

优化的思路就是将内循环中每次 swap 交换操作修改为 让较大的元素后移,最后再进行一次交换 ,这样一来访问数组的次数就减少了(交换需要三行,赋值只需要一行)。

优化步骤如下:

  1. 每次先保存当前插入的元素。
  2. 将当前保存的元素(第二个元素)和第一个元素比较,小于第一个元素的话,将第一个元素移动到第二个元素位置,然后当前保存的元素移动到第一个元素位置,这样第二个元素作为最小的元素排在了最前面。
  3. 将当前保存的元素(第三个元素)和第二个元素比较,小于第二个元素的话,将第二个元素移动到第三个元素位置,然后当前保存的元素移动到第二个元素位置,接着小于第一个元素的话再次执行以上操作,这样第三个元素作为最小的元素排在了最前面。
  4. 以此类推,直到最后一个元素插入到合适位置。

下图展示了优化思路的过程:

优化的直接插入排序代码:

public static void sort(Comparable[] arr) {    int n = arr.length;    // 0位置不需要比,从1到最后一个位置n-1    for (int i = 1; i <= n - 1; i++) {        // 保存当前插入的元素        Comparable e = arr[i];        int j;        for (j = i; j > 0 && arr[j - 1].compareTo(e) > 0; j--) {            arr[j] = arr[j - 1];        }        arr[j] = e;    }}

希尔排序

上面我们介绍了直接插入排序,它对于大规模乱序数组的排序效率比较低,因为只能交换相邻的元素,所以元素只能一点一点地从数组的一端移动到另一端。此外,如果最小的元素在数组的末尾,那么将它插入到正确位置需要移动 N-1 次。

希尔排序的出现,解决了上述问题。它能够交换不相邻的元素以对数组的局部进行排序,并最终用直接插入排序将局部有序的数组排序。

希尔排序的思想是使数组中任意间隔为 h 的元素都是有序的。这样的数组也叫作 h 有序数组 。我们不研究 h 是如何得来的,这里直接使用了《算法》书中的 h 步长序列。

h = 3*h+1 ,根据 h 的取值分别为1、4、13 ...

实际上只需要把直接插入排序代码中移动元素的距离由 1 改为 h 即可。这样,希尔排序就转换为了一个类似于直接插入排序但使用不同增量的过程。

下图展示了希尔排序的过程:

如果你仔细观察,会发现在 h=1 时,相比直接插入排序,比较的次数大大减少了,这是因为希尔排序使得部分子数组有序,而直接插入排序对于近乎有序的数组,效率是非常高的。

希尔排序代码:

public static void sort(Comparable[] arr) {    int n = arr.length;    // 步长序列: 1, 4, 13...    int h = 1;    while (h < n / 3) {        h = 3 * h + 1;    }    while (h >= 1) {        for (int i = h; i < n; i++) {            // 将 arr[i] 插入到 arr[i-h], arr[i-2*h], arr[i-3*h]... 中            Comparable e = arr[i];            int j;            // 优化的插入排序            for (j = i; j >= h && e.compareTo(arr[j - h]) < 0; j -= h) {                arr[j] = arr[j - h];            }            arr[j] = e;        }        h /= 3;    }}

ds排序--希尔排序_图解直接插入排序和希尔排序相关推荐

  1. python实现希尔排序算法_排序算法总结(冒泡排序、直接插入排序、希尔排序)(python实现)...

    其实本文叫排序算法总结有点过了,只是用python实现了一遍.本文都是参照一篇csdn博客<数据结构排序算法>,里面详细介绍每种排序算法的原理,并给出了C++的实现,再次膜拜. # -*- ...

  2. 中希尔排序例题代码_超全面分析十大排序算法

    点击上方"零一视界",选择"星标"公众号 资源干货,第一时间送达 作者 | 不该相遇在秋天 责编 | 程序员小吴 前言 本文全长 14237 字,配有 70 张 ...

  3. 按照姓名升序排序的代码_干货:6种EXCEL排序方法,让老板对你刮目相看

    排序是EXCEL中十分常用的功能,可你知道除了按列升序.降序排列,EXCEL还能按行排序.甚至自定义排序么?今天就为大家介绍EXCEL中6种排序方法. 升降排序 如果需要对学生的总成绩从低到高排序,首 ...

  4. python中从小到大排序的函数_深入理解Python中的排序函数

    由于 Python2 和 Python3 中的排序函数略有区别,本文以Python3为主. Python 中的排序函数有 sort , sorted 等,这些适用于哪些排序,具体怎么用,今天就来说一说 ...

  5. 排序算法一:冒泡排序,插入排序以及选择排序原理与MATLAB实现

    最近在学习排序算法的一些知识.还是比较有趣的.所以好好研究了一下各个算法.并且使用matlab进行了个基本的实现,目前仅仅是实现吧,优化什么的可能目前的水平达不到吧,毕竟是用matlab实现,还是比较 ...

  6. matlab 冒泡排序算法,排序算法一:冒泡排序,插入排序以及选择排序原理与MATLAB实现...

    冒泡排序 冒泡排序 思想 这个方法就是在每一趟的循环中依次比较前后两个元素之间的大小,然后进行一个交换.这样在多趟循环中实现无序数列的有序排列.下面是使用matlab实现的 eg:冒泡算法的原理是:根 ...

  7. python字典排序并输出_对Python的字典进行排序

    我们知道Python的内置dictionary数据类型是无序的,通过key来获取对应的value.可是有时我们需要对dictionary中 的item进行排序输出,可能根据key,也可能根据value ...

  8. 10种排序算法比较(直接插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序、归并排序、基数排序、折半插入排序、2路插入排序)

    本文(所有排序算法代码+综合比较代码)链接:https://download.csdn.net/download/qq_39932172/11217572 一.比较目的: 由于<数据结构> ...

  9. mysql分组后组内排序_图解排序 3/10 希尔排序

    希尔排序,它是由 D.L.Shell 于1959 年提出而得名.根据它的名字很难想象算法的核心思想.[ 所以只能死记硬背了,面试官问:希尔排序的思想是什么?].它的核心思想是把一个序列分组,对分组后的 ...

最新文章

  1. hql刪除語句,根據參數刪除
  2. 我的Go语言学习之旅八:创建一个简单的WEB服务器
  3. 使用Axios拦截器打印前端请求日志和后端后返回日志
  4. html知识管理,index.html
  5. Node.js实战(四)之调试Node.js
  6. ESP32+AMG8833+RGB屏240*320(ST7789)红外热成像
  7. Python爬取58同城租房数据,破解字体加密
  8. JIRA实践系列-JIRA与teambition对接指南
  9. 小米全面对标iPhone
  10. linux越狱时手机怎么进入dfu,iOS详细越狱步骤 进入DFU模式_iPhone资讯_太平洋电脑网PConline...
  11. STM32 cudeIDE工程新建步骤
  12. 关于MapStruct使用expression表达式的小坑
  13. 苹果cookie是打开还是关闭_cookie那些事
  14. 2012年西安校园招聘会
  15. 思维导图-Freemind
  16. Java入门(三)JAVA SE 01
  17. bim软件功能划分可以分为几类?用于revit的出图插件
  18. 第一型曲线积分的思路总结
  19. 全球与中国密封件和包装产品市场现状及未来发展趋势
  20. 一文搞定晶晨S905L3A电视盒子刷Armbian

热门文章

  1. Google Guava EventBus用于事件编程
  2. Java中的紧凑堆外结构/组合
  3. 我如何向团队解释依赖注入
  4. Spring vs Guice:重要的一个关键区别
  5. MacBook如何快速显示桌面
  6. Linux 命令之 7z(7-zip) -- 压缩/解压文件
  7. xshell调出oracle安装界面,XShell+Xmanager实现在XShell中显示远程服务器的图形界面
  8. 图书管理系统python语言-Python简易版图书管理系统
  9. php mysql导出csv文件_详解PHP导入导出CSV文件
  10. python正则_python的正则表达式