1.基本思想

  希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

2.实现原理

  对于n个待排序的数列,取一个小于n的整数gap(gap被称为步长)将待排序元素分成若干个组子序列,所有距离为gap的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小gap的值,并重复执行上述的分组和排序。重复这样的操作,当gap=1时,整个数列就是有序的。

3.代码实例

(1)代码:

   /**
* 对希尔排序中的单个组进行排序
* <p>
* 参数说明:
* a -- 待排序的数组
* n -- 数组总的长度
* i -- 组的起始位置
* gap -- 组的步长
* <p>
* 组是"从i开始,将相隔gap长度的数都取出"所组成的!
*/
public static void groupSort(int[] a, int n, int i, int gap) {
//打印分组
System.out.print("gap="+gap+" [");
//打印第一个比较的元素
System.out.print(a[i]);
//直接插入排序
for (int j = i + gap; j < n; j += gap) {
//被比较的元素
System.out.print(" "+a[j]);
// 如果a[j] < a[j-gap],则寻找a[j]位置,并将后面数据的位置都后移。
if (a[j] < a[j - gap]) {
int tmp = a[j];
int k = j - gap;
while (k >= 0 && a[k] > tmp) {
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = tmp;
// System.out.print(" ("+a[j]+"<-->"+a[j-gap]+")");
}
}
System.out.println("]");
}
/**
* 希尔排序
* <p>
* 参数说明:
* a -- 待排序的数组
* n -- 数组的长度
*/
public static void shellSort(int[] a, int n) {
// gap为步长,每次减为原来的一半。
for (int gap = n / 2; gap > 0; gap /= 2) {
// 共gap个组,对每一组都执行直接插入排序
for (int i = 0; i < gap; i++)
groupSort(a, n, i, gap);
System.out.printf("after sort:");
for (int i = 0; i < a.length; i++)
System.out.printf("%d ", a[i]);
System.out.println();
System.out.println();
}
}
public static void main(String[] args) {
int i;
int a[] = {80, 30, 60, 40, 20, 10, 50, 70,100};
System.out.printf("before sort:");
for (i = 0; i < a.length; i++)
System.out.printf("%d ", a[i]);
System.out.println();
System.out.println();
shellSort(a, a.length);
}

(2)结果:

before sort:80 30 60 40 20 10 50 70 100

gap=4 [80 20 100]

gap=4 [30 10]

gap=4 [60 50]

gap=4 [40 70]

after sort:20 10 50 40 80 30 60 70 100

gap=2 [20 50 80 60 100]

gap=2 [10 40 30 70]

after sort:20 10 50 30 60 40 80 70 100

gap=1 [20 10 50 30 60 40 80 70 100]

after sort:10 20 30 40 50 60 70 80 100

4.算法分析

(1)希尔排序时间复杂度

  希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。

(2)希尔排序空间复杂度

  空间复杂度是O(1) 因为只有一个缓冲单元。

(3)希尔排序稳定性

  希尔排序是不稳定的算法,它满足稳定算法的定义。对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。

  算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!

5.排序特点

我们知道一次插入排序是稳定的,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

  希尔排序的时间性能优于直接插入排序,原因如下:

  (1)当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。

  (2)当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。

  (3)在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。

  因此,希尔排序在效率上较直接插人排序有较大的改进。

 希尔排序的平均时间复杂度为O(nlogn)

排序算法(3)--Insert Sorting--插入排序[3]--Shell Sort--希尔排序的更多相关文章

  1. Shell Sort(希尔排序)

    这个排序算法很厉害,我个人很喜欢这个算法,但算法的时间复杂度难计.算法对增量(这里也称作step(步长))的选择也需要注意,只记得个希尔增量的最坏情况为O(n^2).Hibbard增量的最坏情况为O( ...

  2. JavaScript 排序算法(JavaScript sorting algorithms)

    JavaScrip 排序算法(JavaScript Sorting Algorithms) 基础构造函数 以下几种排序算法做为方法放在构造函数里. function ArrayList () { va ...

  3. 排序算法——(2)Python实现十大常用排序算法

    上期为大家讲解了排序算法常见的几个概念: 相关性:排序时是否需要比较元素 稳定性:相同元素排序后是否可能打乱 时间空间复杂度:随着元素增加时间和空间随之变化的函数 如果有遗忘的同学可以看排序算法——( ...

  4. 【高级排序算法】1、归并排序法 - Merge Sort

    归并排序法 - Merge Sort 文章目录 归并排序法 - Merge Sort nlogn 比 n^2 快多少? 归并排序设计思想 时间.空间复杂度 归并排序图解 归并排序描述 归并排序小结 参 ...

  5. 排序算法(2)--Insert Sorting--插入排序[2]--binary insertion sort--折半(二分)插入排序

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.基本思想 二分法插入排序的思想和直接插入一样,只是找合适的插入位置的方式不同,这里是按二分法找到合适的位置,可 ...

  6. 排序算法(1)--Insert Sorting--插入排序[1]--straight insertion sort--直接插入排序

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.基本思想 将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表.即:先将序列的第1个记录看成 ...

  7. Java 常用排序算法实现--快速排序、插入排序、选择、冒泡

      public class ArrayOperation {    //二分查找算法    public static int branchSearch(int[] array, int searc ...

  8. python实现排序算法(一)——插入排序算法

    ''' 插入排序算法 原始数据data 排序数据后数据SortedData,默认是从小打大排序 1.从data第一个元素开始,该元素赋值给SortedData[0],可以认为SortedData已经被 ...

  9. 必须知道的八大种排序算法【java实现】(二) 选择排序,插入排序,希尔算法【详解】

    一.选择排序 1.基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换:然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止. 2.实例 3.算法 ...

随机推荐

  1. ArrayList的源码分析

    在项目中经常会用到list集合来存储数据,而其中ArrayList是用的最多的的一个集合,这篇博文主要简单介绍ArrayList的源码分析,基于JDK1.7: 这里主要介绍 集合 的属性,构造器,和方 ...

  2. nginx官方文档 之 http负载均衡 学习笔记

    一.负载均衡 算法 大致可以分两类: (1)不能保证用户的每一次请求都通过负载均衡到达同一服务器. (2)可保证用户的每一次请求都通过负载均衡到达同一服务器. 第二类的应用场景: 1.如果服务器有缓存 ...

  3. D02-R语言基础学习

    R语言基础学习——D02 20190423内容纲要: 1.前言 2.向量操作 (1)常规操作 (2)不定长向量计算 (3)序列 (4)向量的删除与保留 3.列表详解 (1)列表的索引 (2)列表得元素 ...

  4. NPOI读取excel文件导出数据, 而此时文件正在打开中抛异常怎么办

    项目中需要用到一些数值表格, 方便起见都是用excel来的. 而如果excel正打开中, 直接使用npoi制作的工具来导出数据的话, 在这一行将会异常: workbook = new XSSFWork ...

  5. 使用Dump转储文件排查线上环境服务未知问题

    利用Dump转储文件获取正式环境程序堆栈状态 服务异常找不到原因时,我们通常通过重新启动服务来尝试解决问题,但是在决定重启之前,请不要立刻重启Windows服务或站点 重启服务会让当前案发现场的内存证 ...

  6. ElasticSearch入门2: 基本用法

    基本用法:  一.索引创建 (启动集群和索引请看上一篇文章:http://www.cnblogs.com/liuxiaoming123/p/8081883.html) 1.打开浏览器,输入请求:htt ...

  7. 客户端禁用cookie

    如果客户端禁用cookie的话不影响session使用 的设置方法: <sessionState     cookieless="AutoDetect"

  8. getFields和getDeclaredFields

    getFields()获得某个类的所有的公共(public)的字段,包括父类. getDeclaredFields()获得某个类的所有申明的字段,即包括public.private和proteced, ...

  9. Windows下编译打包Spice PC客户端

    目录 1 环境搭建 2 编译客户端 3 打包客户端   1 环境搭建 1.1 准备工作 安装启动: 安装替换图标工具: Resource Hacker 安装exe制作工具: NSIS(提取码:3dfp ...

  10. 【详解】ThreadPoolExecutor源码阅读(三)

    系列目录 [详解]ThreadPoolExecutor源码阅读(一) [详解]ThreadPoolExecutor源码阅读(二) [详解]ThreadPoolExecutor源码阅读(三) 线程数量的 ...