一.希尔排序的基本思想
将整个序列按照一定的增量分成若干个子序列分别进行直接插入排序,待整个序列基本有序时,再对整个序列进行直接插入排序。
二.操作方法
-
选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
-
按增量序列个数k,对序列进行k 趟排序;
-
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
三.算法的java实现
我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 .....1} ,n为要排序数的个数
即:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
/**
* 希尔排序
* @param array
*/
public static void shellSort(int[] array){
int dk = array.length/2;
while(dk>=1){
shellInsertSort(array,dk);
dk=dk/2;
}
}
/**
* 根据增量对数组从小到大排序
* @param array
* @param dk 增量
*/
public static void shellInsertSort(int[] array,int dk){
for (int i = dk; i < array.length; i++) {
int currentVal = array[i]; //设置哨兵
int position = i; //即将插入的位置
for(int j=i-dk; j>=0; j=j-dk){
if(array[j]>currentVal){
array[j+dk] = array[j]; //如果前一个元素比后一个元素大,就往后移
position = j;
}else{
break;
}
}
array[position] = currentVal; //插入元素
}
}
四.效率
如果增量序列d = {n/2 ,n/4, n/8 .....1},希尔排序的时间复杂度为O(nlgn))。
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数,目前还没有人给出选取最好的增量因子序列的方法。增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意:增量因子中除1 外没有公因子,且最后一个增量因子必须为1。希尔排序方法是一个不稳定的排序方法。
五.应用场景
希尔排序不适用于链式存储结构,因为增量初始值不容易选择,所以该算法不常用。