希尔排序(Shell Sort)
来源:互联网 发布:java response json 编辑:程序博客网 时间:2024/05/23 00:05
1、概述
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
希尔排序按其设计者希尔(Donald Shell)的名字命名,该算法由1959年公布。一些老版本教科书和参考手册把该算法命名为Shell-Metzner,即包含Marlene Metzner Norton的名字,但是根据Metzner本人的说法,“我没有为这种算法做任何事,我的名字不应该出现在算法的名字中。”
希尔排序是基于插入排序的以下两点性质而提出改进方法的:
- 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。
- 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。
2、算法原理
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2 < d1重复上述的分组和排序,直至所取的增量 =1( < … < d2 < d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法。
比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比较就可能消除多个元素交换。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。
3、算法分析
①时间复杂度
希尔排序的时间复杂度与增量序列的选取有关,例如希尔增量时间复杂度为O(n²),而Hibbard增量的希尔排序的时间复杂度为O(n^2/3),希尔排序时间复杂度的下界是nlog2n。希尔排序没有快速排序算法快:O(n(logn)),中等大小规模表现良好,对规模非常大的数据排序不是最优选择。但是比O(n²)复杂度的算法快得多,也就是说基本上优于冒泡、选择排序。
希尔排序的执行时间依赖于增量序列。
合适的增量序列特征:
- 最后一轮的增量必须为1。
- 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。
希尔排序的时间性能优于直接插入排序的原因:
- 当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
- 当n值较小时,n和n²的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n²)差别不大。
- 在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量d逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按d-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
②算法稳定性
一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,由于多次插入排序,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,因此,希尔排序是不稳定的。
4、实现(Java)
代码已上注释。
/** * @author Hanlin Wang */public class ShellSort { public static void main(String[] args) { int[] data = {57,68,59,52,72,28,96,33,24,19}; ShellSort.sort(data); } public static void sort(int[] data){ //i:控制每轮(不同的增量)的趟数。 int i; //j:每趟排序次数,以及控制索引。 int j; //k:记录每趟排序的要被用来排序(插入)的元素的值。 int k; //l:用于记录打印轮次 int l = 0; //increment为增量 for (int increment = data.length / 2; increment > 0; increment /= 2) { System.out.println("-----------------------------"); System.out.println("当 increment = "+ increment +"\n"); for (i = increment; i < data.length; i++) { k = data[i]; for (j = i; j >= increment && k < data[j-increment]; j -= increment) { data[j] = data[j-increment]; } //最后将原来的被插入的元素赋值在指定的索引上。 data[j] = k; //打印本轮结果 String txt = ""; for (int a : data) { txt += a + ","; } System.out.println("第" + (++l) + "轮排序的结果为:"); System.out.println(txt.substring(0, txt.length() - 1) + "\n"); } l = 0; } }}
运行结果:
当 increment = 5
第1轮排序的结果为:
28,68,59,52,72,57,96,33,24,19
第2轮排序的结果为:
28,68,59,52,72,57,96,33,24,19
第3轮排序的结果为:
28,68,33,52,72,57,96,59,24,19
第4轮排序的结果为:
28,68,33,24,72,57,96,59,52,19
第5轮排序的结果为:
28,68,33,24,19,57,96,59,52,72
当 increment = 2
第1轮排序的结果为:
28,68,33,24,19,57,96,59,52,72
第2轮排序的结果为:
28,24,33,68,19,57,96,59,52,72
第3轮排序的结果为:
19,24,28,68,33,57,96,59,52,72
第4轮排序的结果为:
19,24,28,57,33,68,96,59,52,72
第5轮排序的结果为:
19,24,28,57,33,68,96,59,52,72
第6轮排序的结果为:
19,24,28,57,33,59,96,68,52,72
第7轮排序的结果为:
19,24,28,57,33,59,52,68,96,72
第8轮排序的结果为:
19,24,28,57,33,59,52,68,96,72
当 increment = 1
第1轮排序的结果为:
19,24,28,57,33,59,52,68,96,72
第2轮排序的结果为:
19,24,28,57,33,59,52,68,96,72
第3轮排序的结果为:
19,24,28,57,33,59,52,68,96,72
第4轮排序的结果为:
19,24,28,33,57,59,52,68,96,72
第5轮排序的结果为:
19,24,28,33,57,59,52,68,96,72
第6轮排序的结果为:
19,24,28,33,52,57,59,68,96,72
第7轮排序的结果为:
19,24,28,33,52,57,59,68,96,72
第8轮排序的结果为:
19,24,28,33,52,57,59,68,96,72
第9轮排序的结果为:
19,24,28,33,52,57,59,68,72,96
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(shell sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(shell sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(shell sort)
- 希尔排序(Shell Sort)
- 希尔排序(shell sort)
- Shell Sort 希尔排序
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 希尔排序(Shell Sort)
- 关关于android 微信sdk 分享 图片 到 朋友圈 的问题
- JAVA多线程通信之wait和notify的使用
- Mybatis,Ibatis,添加,修改,删除,获得结果集
- 三门问题
- 琐碎资料
- 希尔排序(Shell Sort)
- 莫对算法
- 数位dp 洛谷P2602 [ZJOI2010]数字计数
- codeforces 4c Registration system 字符串 map应用
- 基础数学算法
- Minor GC、Major GC和Full GC之间的区别
- CSS3的属性记载
- java 集合类
- 405. Convert a Number to Hexadecimal | 10进制整数转16进制数