刚接触希尔排序的时候,我是懵的,因为在学校根本没有学过希尔排序啊!
查询资料:希尔排序是插入排序的升级版;
从维基百科截取的Java实现希尔排序的代码
public static void shellSort(int[] arr) {
int length = arr.length;
int temp;
for (int step = length / 2; step >= 1; step /= 2) {
for (int i = step; i < length; i++) {
temp = arr[i];
int j = i - step;
while (j >= 0 && arr[j] > temp) {
arr[j + step] = arr[j];
j -= step;
}
arr[j + step] = temp;
}
}
}
我们来简单的试一下:
public class ShellSortFromWiki{
public static void main(String[] args){
int[] a = {4, 9, 11, 3, 8, 6, 2, 7, 13, 1, 12, 5, 10};
shellSort(a);
print(a);
}
public static void shellSort(int[] arr) {
int length = arr.length; //获取数组的长度
int temp; //临时变量temp
// step是每个区域的数值的个数,当每个区域排序到不能再继续往下排的时候;
// 将区域再次变小,这里是 step /= 2,将每个区域再分一半
for (int step = length / 2; step >= 1; step /= 2) {
for (int i = step; i < length; i++) {
temp = arr[i];
int j = i - step;
while (j >= 0 && arr[j] > temp) {
arr[j + step] = arr[j];
j -= step;
}
arr[j + step] = temp;
}
}
}
static void print(int[] a){
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
打印:
对以上代码稍加修改,打印出每一次排序的过程
2 9 11 3 8 6 4 7 13 1 12 5 10
2 7 11 3 8 6 4 9 13 1 12 5 10
2 7 11 3 8 6 4 9 13 1 12 5 10
2 7 11 1 8 6 4 9 13 3 12 5 10
2 7 11 1 8 6 4 9 13 3 12 5 10
2 7 11 1 8 5 4 9 13 3 12 6 10
2 7 11 1 8 5 4 9 13 3 12 6 10
1 7 11 2 8 5 4 9 13 3 12 6 10
1 7 11 2 8 5 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 4 9 13 3 12 6 10
1 7 5 2 8 11 3 9 13 4 12 6 10
1 7 5 2 8 11 3 9 13 4 12 6 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 7 5 2 8 6 3 9 11 4 12 13 10
1 5 7 2 8 6 3 9 11 4 12 13 10
1 2 5 7 8 6 3 9 11 4 12 13 10
1 2 5 7 8 6 3 9 11 4 12 13 10
1 2 5 6 7 8 3 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 5 6 7 8 9 11 4 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 11 12 13 10
1 2 3 4 5 6 7 8 9 10 11 12 13
1 2 3 4 5 6 7 8 9 10 11 12 13
总共30行数据,减去最后一行打印,总共29条;
接下来说一下这个排序算法的排序方式:
希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前进一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快).
注意:如果你看这些文字实在是看不懂,建议拿出纸笔,一步一步算(小编比较愚钝,就是这么做的);
这里维基百科提供的代码是根据数组的长度除以2[for (int step = length / 2; step >= 1; step /= 2)];
但这并不是最佳的解决方法
我们来比较一下相同的数组排序次数的差别:
插入排序:38次
二分希尔排序:29次
knuth希尔排序:21次
明显是knuth希尔排序更快,下面介绍一下knuth希尔排序算法:
public static void sort(int[] arr) {
int h = 1;
while(h <= arr.length /3 ) {
h = h*3 + 1;
}
for(int gap = h; gap > 0; gap = (gap-1)/3) {
for(int i=gap; i<arr.length; i++) {
for(int j=i; j>gap-1; j-=gap) {
if(arr[j] < arr[j-gap]) {
swap(arr, j, j-gap);
}
}
}
}
}
几种常见的Gap序列:
1)希尔原本的Gap:N/2、N/4、...1(反复除以2)
2)Hibbard的Gap:1、3、7、...、2k-1(k表示第几个gap)
3)Knuth的Gap: 1、4、13、...、(3k - 1) / 2(k表示第几个gap)
4)Sedgewick的Gap: 1、5、19、41、109、...
看不懂?!
拿出笔来算 !!