作者 | 程序员小灰

责编 | 伍杏玲

—————  第二天  —————

————————————

让我们先来回顾一下:

插入排序顾名思义,就是在排序的过程中,把数组的每一个元素按照大小关系,插入到前面有序区的对应位置。

比如下面数组中的元素3,按照大小关系,需要插入到前面有序区三个元素之前,而前面三个元素则相应向后挪动:

以此类推,插入排序一共会进行(数组长度-1)轮,每一轮的结果如下:

插入排序的平均时间复杂度是O(n^2)。这个排序算法并不复杂,但显然并不是一个高效的排序算法。

那么,怎样可以对插入排序算法做出优化呢?我们不妨从插入排序的两个特点入手:

1.在大多数元素已经有序的情况下,插入排序的工作量较小

这个结论很明显,如果一个数组大部分元素都有序,那么数组中的元素自然不需要频繁地进行比较和交换。

2.在元素数量较少的情况下,插入排序的工作量较小

这个结论更加显而易见,插入排序的工作量和n的平方成正比,如果n比较小,那么排序的工作量自然要小得多。

如何对原始数组进行预处理呢?聪明的科学家想到了一种分组排序的方法,以此对数组进行一定的“粗略调整”。

所谓分组,就是让元素两两一组,同组两个元素之间的跨度,都是数组总长度的一半,也就是跨度为4。

如图所示,元素5和元素9一组,元素8和元素2一组,元素6和元素1一组,元素3和元素7一组,一共4组。

接下来,我们让每组元素进行独立排序,排序方式用直接插入排序即可。由于每一组的元素数量很少,只有两个,所以插入排序的工作量很少。每组排序完成后的数组如下:

这样一来,仅仅经过几次简单的交换,数组整体的有序程度得到了显著提高,使得后续再进行直接插入排序的工作量大大减少。这种做法,可以理解为对原始数组的“粗略调整”。

但是这样还不算完,我们可以进一步缩小分组跨度,重复上述工作。把跨度缩小为原先的一半,也就是跨度为2,重新对元素进行分组:

如图所示,元素5,1,9,6一组,元素2,3,8,7一组,一共两组。

接下来,我们继续让每组元素进行独立排序,排序方式用直接插入排序即可。每组排序完成后的数组如下:

此时,数组的有序程度进一步提高,为后续将要进行的排序铺平了道路。

最后,我们把分组跨度进一步减小,让跨度为1,也就等同于做直接插入排序。经过之前的一系列粗略调整,直接插入排序的工作量减少了很多,排序结果如下:

让我们重新梳理一下分组排序的整个过程:

像这样逐步分组进行粗调,再进行直接插入排序的思想,就是希尔排序,根据该算法的发明者,计算机科学家Donald Shell的名字所命名。

上面示例中所使用的分组跨度(4,2,1),被称为希尔排序的增量,增量的选择可以有很多种,我们在示例中所用的逐步折半的增量方法,是Donald Shell在发明希尔排序时提出的一种朴素方法,被称为希尔增量。

public static void sort(int [] array){

//希尔排序的增量

int d=array.length;

while(d>1) {

//使用希尔增量的方式,即每次折半

d=d/2;

for(int x=0;x<d;x++) {

for(int i=x+d;i<array.length;i=i+d) {

int temp=array[i];

int j;

for(j=i-d;j>=0&&array[j]>temp;j=j-d) {

array[j+d]=array[j];

}

array[j+d]=temp;

}

}

}

}

public static void main(String [] args)

{

int[] array = {5,3,9,12,6,1,7,2,4,11,8,10};

sort(array);

System.out.println(Arrays.toString(array));

}

看看上面这个数组,如果我们照搬之前的分组思路,无论是以4为增量,还是以2为增量,每组内部的元素都没有任何交换。一直到我们把增量缩减为1,数组才会按照直接插入排序的方式进行调整。

对于这样的数组,希尔排序不但没有减少直接插入排序的工作量,反而白白增加了分组操作的成本。

如何为希尔排序选择更有效的增量方式呢?

为了保证分组粗调没有盲区,每一轮的增量需要彼此“互质”,也就是没有除1之外的公约数。

于是,人们相继提出了很多种增量方式,其中最具代表性的是Hibbard增量和Sedgewick增量。

Hibbard的增量序列如下:

1,3,7,15......

通项公式 2^k-1

利用此种增量方式的希尔排序,最坏时间复杂度是O(n^(3/2))

Sedgewick的增量序列如下:

1, 5, 19, 41, 109......

通项公式 9*4^k - 9*2^k + 1 或者 4^k - 3*2^k + 1

利用此种增量方式的希尔排序,最坏时间复杂度是O(n^(4/3))

关于这两种增量方式的时间复杂度,有些需要很复杂的数学证明,有些是人们的大致猜想,大家暂时不用纠结。

上面数组当中,有两个元素5,绿色的5在前,橙色的5在后。

假如我们按照希尔增量分组,第一轮粗调(增量为4)之后,绿色的元素5会跟元素4交换,换到橙色的5后面:

第二轮粗调(增量为2)之后:

最终排序结果:

相同的元素5,在排序之后改变了次序,由此可见希尔排序是一个不稳定排序。

声明:本文为作者投稿,首发于个人公众号程序员小灰,版权归其所有。

【END】

学习Python的

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

 热 文 推 荐 

你点的每个“在看”,我都认真当成了喜欢

漫画:什么是希尔排序?相关推荐

  1. 直接插入排序与希尔排序

    直接插入排序(Straight Insertion Sort):         一种最简单的排序方法,其基本操作是将一条记录插入到已排好的有序表中,从而得到一个新的.记录数量增1的有序表. 原理图如 ...

  2. 用python写希尔排序_python希尔排序介绍(实例)

    希尔排序介绍 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本,该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个&qu ...

  3. 插入排序,希尔排序,堆排序

    本文将介绍三种排序算法--插入排序,希尔排序,堆排序.本文所有例子都是使用升序 一.插入排序 算法思想 维护一个有序数组,将要插入的数据与有序数组自最后一个元素直到合适位置的数一一比较. eg: 有序 ...

  4. 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序...

    先推荐一篇关于排序算法的文章:http://www.cppblog.com/guogangj/archive/2009/11/13/100876.html 本文思路部分来源于上篇文章,但测得的结果似乎 ...

  5. java算法----排序----(6)希尔排序(最小增量排序)

    1 package log; 2 3 public class Test4 { 4 5 /** 6 * java算法---希尔排序(最小增量排序) 7 * 8 * @param args 9 */ 1 ...

  6. 希尔排序——算法系列

    希尔排序: 插入排序的升级版,主要采用了分组的策略,采用逐渐减小步长来控制分组的大小,各组内采用插入排序,当步长减小为1的时候,大部分数据都已经有序,所以较插入排序优化了许多. 代码: using S ...

  7. 【Java】5大排序算法总结(插入排序+希尔排序+选择排序+堆排序+冒泡排序)

    快速导航: 1. 稳定性 2 . 插入排序 3. 希尔排序 4. 选择排序 5. 堆排序 6 冒泡排序 1. 稳定性 两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法 ...

  8. 算法系列【希尔排序】篇

    常见的内部排序算法有:插入排序.希尔排序.选择排序.冒泡排序.归并排序.快速排序.堆排序.基数排序等.用一张图概括: 关于时间复杂度: 1.     平方阶 (O(n2)) 排序各类简单排序:直接插入 ...

  9. 排序算法---希尔排序(java版)

    希尔排序 原理 先将待排序表分割成若干相隔某个"增量"的记录组成一个子表,对各个子表分别进行直接插入,当整个表中的元素已成基本有序是,再对全体记录进行一次直接插入排序.希尔排序主要 ...

最新文章

  1. 日访问量百亿级的应用如何做缓存架构设计
  2. Traceroute笔记
  3. 神策数据上线 IPTV Demo ,三大价值助力数据驱动
  4. java设计模式之设计原则②依赖倒置原则
  5. centos编译mysql5.6_centos7上编译安装mysql5.6
  6. 苹果验证电子邮件地址服务器错误,苹果7P账户申请,验证电子邮件地址创建新Apple ID发生未知错误...
  7. java 画多边形_javascript绘制一个多边形
  8. C程序语言表达式运算顺序,详解C++编程中表达式的语义与计算顺序
  9. python3 socketserver源码解析_解读python中SocketServer源码
  10. go 的时间与时间戳计算
  11. jQuery 省市区多级(三级/四级/五级。。。)联动 BY 凨来了
  12. HTML5期末大作业:关于家乡介绍的HTML网页设计——郑州美景HTML+CSS(5页) 学生DW家乡介绍网页设计作业成品 web课程设计网页规划与设计
  13. 基于C++实现惊险刺激的Flappy Bird设计
  14. tplinkwr710n改无线打印服务器,TP-Link TL-WR710N V1无线路由器AP模式设置
  15. Android 架构设计与挑选
  16. 这位“华为天才少年”,竟然要我用“充电宝”打《只狼》
  17. 主成分分析(PCA)(principal component analysis)
  18. golang实现稀疏数组(Sparse array)
  19. ZZULIOJ-1095: 时间间隔(多实例测试)(Java)
  20. 图层样式之:内发光、外发光

热门文章

  1. 关于TTThumbsViewController加载更多
  2. 产品工作中/阅读中的涓滴意念
  3. 在Asciidoc中的多级列表以及缩进的使用
  4. leetcode 384 打乱数组
  5. 动画学习android,Android动画学习
  6. 【论文解读】Cross-dataset Training for Class Increasing Object Detection
  7. leetcode python3 简单题136. Single Number
  8. AttributeError: type object 'h5py.h5.H5PYConfig' has no attribute '__reduce_
  9. pythonweb接口优化_记一次flask web接口速度优化
  10. python快速编程入门课本中的名片管理器_python优雅操作-实现名片管理系统