希尔排序
希尔排序的思想是使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。在排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便。用这样的方式,对于任意以1结尾的h序列,我们都能够将数组排序。
Java实现代码(使用简单递增序列)
public static void shellSort(int[]A){
int len=A.length;
int h=1;
int midnum=0;
while(h<len/3) h=3*h+1;
while(h>=1){
for(int i=h;i<len;i++){
for(int j=i;j>=h&&A[j]<A[j-h];j=j-h){
midnum=A[j];
A[j]=A[j-h];
A[j-h]=midnum;
}
}
h=h/3;
}
}
希尔排序更高效的原因在于是它权衡了子数组的规模和有序性。排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。子数组部分有序的程度取决于递增序列的选择。
如何选择递增序列:
算法的性能不仅取决于h,还取决于h之间的数学性质,比如它们的公因子等。目前还无法证明某个序列是最好的。我们使用的递增序列很简单,和复杂的递增序列性能接近。目前最重要的结论是它的运行时间达不到平方级别。
Sedgewick的增量{1,5,19,41,109,209,505,929,2161,3905,8929······}
用此增量的希尔排序最坏的时间复杂度为O(n^(4/3))
Java实现代码(使用Sedgewick增量)
public static void shellSort(int []A){
int[]Sedgewick={1,5,19,41,109,209,505};
int len=A.length;
int index=0;
int midnum=0;
for(int i=0;i<Sedgewick.length;i++){
if(len<Sedgewick[i])
index=i-1;
break;
}
while(index>=0){
for(int i=Sedgewick[index];i<len;i++){
for(int j=i;j>=Sedgewick[index]&&A[j]<A[j-Sedgewick[index]];j=j-Sedgewick[index]){
midnum=A[j];
A[j]=A[j-Sedgewick[index]];
A[j-Sedgewick[index]]=midnum;
}
}
index--;
}
}