插入排序算法之希尔排序
一、前沿:
希尔排序(Shell Sort)的名称源于它的发明者Donald Shell,该算法是冲破了二次元时间屏障的算法之一。
基本思想:先取一个小于n的整数ht作为第一个增量,把文件的全部记录分成ht个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量ht-1<ht重复上述的分组和排序,直至所取的增量ht=1(h1<h2<....ht),即所有记录放在同一组中进行直接插入排序为止。
二、详细步骤:
希尔排序使用一个序列h1,h2,......ht 叫做 增量序列,只要h1=1,任何增量序列都是可行的,在使用hk的一趟增量序列后,数组中任何a[i]<=a[i+k]是有意义的。所有相隔k的元素都是有序的,此时称之为数组是hk有序的。下图为希尔排序每趟后的情况:
hk排序的一般做法是,对于hk,hk+1.......N-1中的每一个位置i,把其上的元素放置在i,i-hk,i-2hk,.....中的正确位置上。虽然并不影响最终结果,但通过观察可发现,一趟hk排序的作用就是对hk个独立的子数组执行一次插入排序,在分析希尔排序的运行时间时,这个观测结果是很重要的!!
三、算法实现
在考虑到增量序列的问题中,可以通过ht=[n/2]和hk=[hk+1/2]。也可以通过自己设定增量序列来实现:
1 /** 2 * 希尔排序是简单插入排序的改进版,突破了复杂度为O(n*n)的排序算法,它与插入排序不同的是 3 * ,它会优先比较距离较远的元素,它又叫缩小增量排序 4 */ 5 public static void shellSort1(int[] r, int low, int high, int[] delta) { 6 for (int k = 0; k < delta.length; k++) 7 shellInsert(r, low, high, delta[k]); //一趟步长为 delta[k]的直接插入排序 8 } 9 //shellInsert 执行的是插入排序 10 private static void shellInsert(int[] r, int low, int high, int deltaK) { 11 for (int i = low + deltaK; i <= high; i++) 12 if (r[i]<r[i-deltaK]) { 13 //小于时,需将 r[i] 插入有序表,执行的过程跟插入排序一样 14 int temp = r[i]; 15 int j ; 16 for (j= i - deltaK; j >= low && temp < r[j]; j = j - deltaK) 17 r[j + deltaK] = r[j]; //记录后移 18 r[j + deltaK] = temp; //插入到正确位置 19 System.out.println(Arrays.toString(r)); 20 } 21 22 23 }
四、时间复杂度分析
希尔排序的运行时间依赖于增量序列的选择,希尔排序的平均情形分析,除最平凡的一些增量序列外,是一个长期未曾解决的问题。我们将对希尔排序的最坏情况分析:
1、使用希尔增量时希尔排序的最坏情形运行时间为O(n2)
2、使用Hibbard增量的希尔排序的最坏情况运行时间为O(n3/2):证明略
实践中,大多数希尔排序的运行时间为O(n3/2)
五、参考资料
《数据结构与算法分析》