码迷,mamicode.com
首页 > 编程语言 > 详细

基本排序算法<二>

时间:2016-05-17 21:17:11      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:

希尔排序

  原理:希尔排序也称之为递减增量排序,它是对插入排序的改进。在插入排序中,我们知道,插入排序对于近似已排好序的序列来说,效率很高,可以达到线性排序的效率。但是插入排序效率也是比较低的,他一次只能将数据向前移一位。比如如果一个长度为N的序列,最小的元素如果恰巧在末尾,那么使用插入排序仍需一步一步的向前移动和比较,要N-1次比较和交换。希尔排序通过将待比较的元素划分为几个区域来提升插入排序的效率。这样可以让元素可以一次性的朝最终位置迈进一大步,然后算法再取越来越小的步长进行排序,最后一步就是步长为1的普通的插入排序的,但是这个时候,整个序列已经是近似排好序的,所以效率高。

  如下图,我们对下面数组进行排序的时候,首先以4为步长,这是元素分为了LMPT,EHSS,ELOX,AELR几个序列,我们对这几个独立的序列 进行插入排序,排序完成之后,我们减小步长继续排序,最后直到步长为1,步长为1即为一般的插入排序,他保证了元素一定会被排序。

技术分享

  希尔排序的增量递减算法可以随意指定,可以以N/2递减,只要保证最后的步长为1即可。

实现:

public static void shellSort(int[] arr){
	int N=arr.length;
	int h=1;
	while(h<N/3){
		h=3*h+1;
	}
	while (h>=1) {
		for(int i =h; i <N; i++) {
			for (int j =i; j>=h&&(arr[j]<arr[j-h]); j-=h) {
					swap(arr, j, j-h);	
			}
		}
		h=h/3;
	}
}

  可以看到,希尔排序的实现是在插入排序的基础上改进的,插入排序的步长为1,每一次递减1,希尔排序的步长为我们定义的h,然后每一次和前面的-h位置上的元素进行比较。算法中,我们首先获取小于N/3 的最大的步长,然后逐步长递减至步长为1的一般的插入排序。

  下面是希尔排序在各种情况下的排序动画:

技术分享

分析:

1. 希尔排序的关键在于步长递减序列的确定,任何递减至1步长的序列都可以,目前已知的比较好的序列有:

  • Shell’s 序列: N/2 , N/4 , …, 1 (重复除以2);
  • Hibbard’s 序列: 1, 3, 7, …, 2k – 1 ;
  • Knuth’s 序列: 1, 4, 13, …, (3k – 1) / 2 ;该序列是本文代码中使用的序列。
  • 已知最好的序列是 Sedgewick’s (Knuth的学生,Algorithems的作者)的序列: 1, 5, 19, 41, 109, ….

该序列由下面两个表达式交互获得:

  • 1, 19, 109, 505, 2161,….., 9(4k – 2k) + 1, k = 0, 1, 2, 3,…
  • 5, 41, 209, 929, 3905,…..2k+2 (2k+2 – 3 ) + 1, k = 0, 1, 2, 3, …

  “比较在希尔排序中是最主要的操作,而不是交换。”用这样步长的希尔排序比插入排序和堆排序都要快,甚至在小数组中比快速排序还快,但是在涉及大量数据时希尔排序还是比快速排序慢。

  2. 希尔排序的分析比较复杂,使用Hibbard’s 递减步长序列的时间复杂度为O(N3/2),平均时间复杂度大约为O(N5/4) ,具体的复杂度目前仍存在争议。

  3. 实验表明,对于中型的序列( 万),希尔排序的时间复杂度接近最快的排序算法的时间复杂度nlogn。

  最后总结一下本文介绍的三种排序算法的最好最坏和平均时间复杂度。

名称 最好 平均 最坏 内存占用 稳定排序
插入排序 n n2 n2 1
选择排序 n2 n2 n2 1
希尔排序 n nlog2n

n3/2
依赖于增量递减序列目前最好的是 nlog2n 1

基本排序算法<二>

标签:

原文地址:http://www.cnblogs.com/wxgblogs/p/5503108.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!