希尔排序
算法思想:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。本质是分组插入排序,每次将较小的元素插入到前面,较大的元素留在后面。
排序过程如下:
以26、53、67、48、57、13、48、32、60、50为例,
1、第一趟排序以n/2即10/2=5为间隔
26、53、67、48、57、13、48、32、60、50,同一颜色为一组,同一组内进行直接插入排序,改变的位置也只能是组内元素原有的位置,结果为13 48 32 48 50 26 53 67 50 57。
2.第二趟以5/2=2为间隔
13 4832 48 50 2653 67 50 57,结果为13 26 32 48 50 48 57 60 67
3.第三趟以1为间隔,即直接插入排序。
结果为 13 26 32 48 48 50 57 60 67
java实现
public static void shellSort(int a[]) {
int i,j;
int gap;//记录间隔
int len=a.length;
for(gap=len/2;gap>0;gap/=2) {
for(i=gap;i<len;i++) {//初始从第gap元素开始
if(a[i]<a[i-gap]) {//a[i-gap]<a[i]时,表示间隔数组内a[i]之前的元素有序,a[i]<a[i-gap]则讲元素一边向后移一边搜索
int temp=a[i];
for(j=i-gap;j>=0&&a[j]>temp;j-=gap) {
a[j+gap]=a[j];
}
a[j+gap]=temp;
}
}
}
}
public static void shellSort2(int a[]) {
int i,j,gap;
int len=a.length;
for(gap=len/2;gap>0;gap/=2) {
for(i=gap;i<len;i++) { //初始从gap开始
for(j=i-gap;j>=0&&a[j+gap]<a[j];j-=gap) {//用元素交换替换上面方法的元素后移
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
算法分析:
1、增量选择
shell排序时间依赖与增量序列,好的增量应该避免序列中的值互为倍数的情况;最后一个增量必须为1;
2、时间复杂度:
有人通过大量的实验,给出了较好的结果:当n较大时,比较和移动的次数约在n^l.25到1.6n^1.25之间。希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(n^3/2)。
希尔排序时间复杂度的下界是n*log2n。希尔排序没有快速排序算法快 O(n(logn)),因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择
3.时间性能优于直接插入排序,,希尔排序的时间性能优于直接插入排序的原因:
①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。②当n值较小时,n和n^2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0( )差别不大。
③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
因此,希尔排序在效率上较直接插入排序有较大的改进。
4.不稳定的排序