算法—3.希尔排序

对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。例如,如果主键最小的元素正好在数组的尽头,要将它挪到正确的位置就需要N-1次移动。希尔排序为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。

1.基本思想

希尔排序的思想是使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。换句话说,一个h有序数组就是h个互相独立的有序数组编织在一起组成的一个数组(见下图)。在进行排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便。用这种方式,对于任意以1结尾的h序列,我们都能够将数组排序。这就是希尔排序。

希尔排序更高效的原因是它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。子数组部分有序的程度取决于递增序列的选择。透彻理解希尔排序的性能至今仍然是一项挑战。实际上,它是我们唯一无法准确描述其对于乱序的数组的性能特征的排序方法。

2.具体算法

/**
 * 希尔排序
 * @author huazhou
 *
 */
public class Shell extends Model{

	public void sort(Comparable[] a){
//		System.out.println("Shell");
		//将a[]按升序排列
		int N = a.length;
		int h = 1;
		//1,4,13,40,121,364,1093,...
		while(h < N/3){
			h = 3*h + 1;
		}
		//将数组变为h有序
		while(h >= 1){
			//将a[i]插入到a[i-h],a[i-2*h],a[i-3*h]...之中
			for (int i = h; i < N; i++) {
				for (int j = i; j >= h && less(a[j],a[j-h]); j-=h) {
					exch(a, j, j-h);
				}
			}
			h = h/3;
		}
	}
}

如果我们在插入排序中加入一个外循环来将h按照递增序列递减,我们就能得到这个简洁的希尔排序。增幅h的初始值是数组长度乘以一个常数因子,最小为1.

和选择排序以及插入排序形成对比的是,希尔排序也可以用于大型数组。它对任意排序(不一定是随机的)的数组表现也很好。实际上,对于一个给定的递增序列,构造一个使希尔排序运行缓慢的数组并不容易。下图是可视轨迹图:

3.算法分析

至于希尔排序算法的性能,目前最重要的结论是它的运行时间达不到平方级别。在实际应用中,使用算法中的递增序列基本就足够了。在最坏的情况下的比较次数和N3/2成正比。

命题:使用递增序列1,4,13,40,121,364...的希尔排序所需的比较次数不会超出N的若干倍乘以递增序列的长度。

证明:大量的实验证明平均每个增幅所带来的比较次数约为N1/5,但只有在N很大的时候这个增长幅度才会变得明显。

4.总结

通过SortCompare可以看到,希尔排序比插入排序和选择排序要快得多,并且数组越大,优势越大。希尔排序能够解决一些初级排序算法无能为力的问题。

有经验的程序员有时会选择希尔排序,因为对于中等大小的数组它的运行时间是可以接受的。它的代码量很小,且不需要使用额外的内存空间。在后面的学习中我们会看到更加高效的算法,但除了对于很大的N,它们可能只会比希尔排序快两倍(可能还达不到),而且更复杂。如果你需要解决一个排序问题而又没有系统排序函数可用(例如直接接触硬件或是运行于嵌入式系统中的代码),可以先用希尔排序,然后再考虑是否值得将它替换为更加复杂的排序算法。

源码下载

时间: 2024-12-15 19:24:21

算法—3.希尔排序的相关文章

排序算法之希尔排序

文章转载自http://www.cnblogs.com/chengxiao/ 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.本文会以图解的方式详细介绍希尔排序的基本思想及其代码实现. 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序:随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组

【数据结构与算法】希尔排序

希尔排序的时间复杂度是O(n^1.3)~O(n^2),空间复杂度是O(1). 代码如下: /** * 源码名称: ShellSort.java * 日期:2014-08-11 * 程序功能:希尔排序 * 版权:[email protected] * 作者:A2BGeek */ public class ShellSort { public void shellSort(int[] in) { int length = in.length; int span = length / 2; int i

算法----(6)希尔排序

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一 1 def shellSort(nums): 2 # 设定步长 3 step = len(nums)//2 4 while step > 0: 5 for i in range(step, len(nums)): 6 # 类似插入排序, 当前值与指定步长之前的值比较, 符合条件则交换位置

五分钟学会一个高难度算法:希尔排序

前言 由于LeetCode上的算法题很多涉及到一些基础的数据结构,为了更好的理解后续更新的一些复杂题目的动画,推出一个新系列 ---<图解数据结构>,主要使用动画来描述常见的数据结构和算法.本系列包括十大排序.堆.队列.树.并查集.图等等大概几十篇. 希尔排序 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.但希尔排序是非稳定排序算法.希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率: 但插入排序

经典排序算法之希尔排序

? 希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法.希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一.希尔排序适合数据量中等情况,几十个到几万个. ? 网上看了好久才彻底明白希尔排序是什么,简单的说将就是按照步进对数据进行分组,对每组分别进行插入排序,直到步进是1的时候则全部完成.在此感谢 dreamcatcher-cx的博客 的讲解. function sortShell(arr)

java排序算法之希尔排序

希尔排序是冲破二次时间屏障的第一批算法之一. 它是通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到最后一趟(比较相邻元素)为止.因此希尔排序也叫缩减增量排序. 希尔排序使用一个序列h1,h2,h3...hk来排序. 具体的意思是 第一趟排序比较的是相隔为hk的元素,也就是比较a[i]与a[i+hk],保证a[i]<=a[i+hk]. 第二次比较的是相隔为hk-1的元素,也就是比较a[i]与a[i+hk-1],保证a[i]<=a[i+hk-1]. 直到最后比较的是相

我的Java开发学习之旅------&gt;Java经典排序算法之希尔排序

一.希尔排序(Shell Sort) 希尔排序(Shell Sort)是一种插入排序算法,因D.L.Shell于1959年提出而得名.Shell排序又称作缩小增量排序. 二.希尔排序的基本思想 希尔排序的中心思想就是:将数据进行分组,然后对每一组数据进行排序,在每一组数据都有序之后 ,就可以对所有的分组利用插入排序进行最后一次排序.这样可以显著减少交换的次数,以达到加快排序速度的目的.       希尔排序的中心思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组.所有距离

排序算法:希尔排序

希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高. 以n=10的一个数组49, 38, 65, 97, 26,

Java学习笔记——排序算法之希尔排序(Shell Sort)

落日楼头,断鸿声里,江南游子.把吴钩看了,栏杆拍遍,无人会,登临意. --水龙吟·登建康赏心亭 希尔算法是希尔(D.L.Shell)于1959年提出的一种排序算法.是第一个时间复杂度突破O(n2)的算法之一. 其基础是插入排序. 上代码: 1 public class ShellSort { 2 3 public static void shellSort(int[] arr){ 4 5 int increment = arr.length; 6 int temp;//牌 7 int i; 8