希尔排序的概念:
希尔排序(Shell Sort)是插入排序的一种,是针对直接插入排序的算法的改进。
该方法又称缩小增量排序。
那么什么是缩小增量排序呢?
首先,我们再来理解下直接插入排序,我们在使用它时,是循环它的第二个数值和它后面的属于与它前面的数值进行比较。
如果小于前面的数值,则将当前数值保存为一临时变量,将将大于当前值的数值往后挪一位,至少前面没有数值比当前值大时,则停止循环,并将中间变量赋值到最后一个挪动位置的数值的原始位置。
直接插入排序的时间复杂度是O(n的p平方)
而希尔排序,就是比它更加优秀的排序方法,它利用增量,把数据分割称几段,分别排序,然后递减增量,重新分组,再次排序,直到增量为1时,进行最后一次排序,如此便可完成排序。
上面提到的分别排序,其实也用的是插入排序,具体见算法
下面给出C代码:
void ShellSort(SqList *L) { int i,j; int increment = L->length; do{ increment = increment/3+1; for(i=increment+1;i<L->length;i++){ if(L->r[i]<L->r[i-increment]){ L->r[0] = L->r[i]; for(j=i-increment;j>0&&L->r[0]<L->[j];j-=increment){ L->r[j+increment] = L->r[j]; } L->r[j+increment] = L->r[0]; } } }while(increment>1) }
上面的例子中,首先我们定义了三个变量,
i用于最外层循环,它的起始位置是增量值,结束位置是数组最大长度
j用于内层循环,保存当前位置-增量值 ,也就是和要比较数据的位置。
increment 用于设置增量,在上面的例子中,我们首先将数组分成三组,这样数据的增量就位4,
如此,我们得到如下的分组,假设我们的数据是{0,10,2,36,12,1,25,42,13,21,11}
那么分组情况如下
10,2,36,12
1,25,42,13
21,11
如上所示,我们将数组分成三组,然后我们将每列的数组进行排序,得到如下结果
1,2,36,12
10,11,42,13
21,25
我们在看下上面的算法,首先i等于增量值+1,因为数组0位置为交换变量,
然后,与当前位置-增量位置的数据进行比较,在第一次循环中,i=5,值为1,i-increment=1,值位10,
因为当前值比前面的值小,所以,开始交换它们的位置,
首先,将当前值赋值给中间变量r[0],然后,开始移动前面一个增量值的位置,直到找不到比当前值大的数据,
最后,将中间变量赋值给最后移动的值,就是r[1],
如此反复,最终结果如上图所示
接着,increment 变为2,则数据分组如下
1,2
36,12,
10,11,
42,13,
21,25
进行排序后,它们的顺序如下
1,2
10,11
21,12
36,13
42,25
接着increment变为1,数组分组如下
1
2
10
11
21
12
36
13
42
25
如此,进行最后一次排序,我们将数据横过来,是不是就是直接插入排序呢?
对了,如此,可以确保,排序是正确的。
下面在给出java版实现
package com.fortune.test;
/**
* Created with IntelliJ IDEA.
* User: liupeng
* Date: 12-7-10
* Time: 下午3:19
*/
public class TestShellSort {
public static void main(String args[]) {
int i;
int a[] = {10, 2, 36, 12, 1, 25, 42, 13, 11};
for (i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println("");
int increment = a.length;
do {
increment = increment / 3 + 1;
sort(a, increment);
} while (increment > 1);
for (i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println("");
}
public static void sort(int arr[], int d) {
for (int i = d; i < arr.length; i++) {
if (arr[i] < arr[i - d]) {
int temp = arr[i];
int j;
j = i - d;
do {
arr[j + d] = arr[j];
j = j - d;
} while (j > 0 && temp < arr[j]);
arr[j + d] = temp;
}
}
}
}