插入排序算法之希尔排序

一、前沿:

      希尔排序(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

五、参考资料

《数据结构与算法分析》

 

posted @ 2018-08-08 23:17  随心—所欲  阅读(161)  评论(0编辑  收藏  举报