希尔排序:这是一种基于插入排序的快速的排序算法。
这种排序的主要思想就是:使数组中任意间隔为h的元素都是有序的,这样的数组称为h有序数组。
如下图,就是一个h有序数组(h=4):
实现希尔排序的方法就是对于每一个h,用插入排序的方式,将h个子数组独立排序,然后逐渐减小h的值,直到h=1。
java代码如下:
/**
* 希尔排序
*/
public class Shell {
public static void sort(int[] a){
int N = a.length;
int h = 1;
while(h < N/3){ // h = 1/2(3^k - 1) 1, 4, 13, 40, 121, 364, 1093, ...
h = 3*h + 1; // 选取合适的递增数列可以提高算法性能 这里使用Algorithms一书中推荐的递增数列
}
while(h >=1){
for (int i = h; i < N; i++) {
for (int j = i; j >= h && (a[j] < a[j-h]); j -= h) {
int temp = a[j];
a[j] = a[j-h];
a[j-h] = temp;
}
}
h = h/3;
}
}
}
轨迹图:
在上述代码中,使用了序列1/2(3^k-1),从N/3开始逐渐减至1。这种序列称之为递增序列。选择合理的递增序列将提高算法的性能。
特点:
这种排序非常的高效,因为它平衡了子数组的规模和有序性。
和选择排序以及插入排序相比,希尔排序也可用于大型数组,对任意排序的数组表现也很好。
小彩蛋:
最近发现了一个有趣的交换的方法,不增加新的变量来交换a b两个变量的值
a = a ^ b;
b = a ^ b; //实际上是(a^b)^b 也就是a异或了b两次,等号右边是a的值
a = a ^ b; //此时b里面已经是“果汁”,实际上是(a^b)^a,也就是b异或了a两次,是b
所以上述代码中交换可以换成下面这样。
a[j] = a[j]^a[j-h];
a[j-h] = a[j]^a[j-h];
a[j] = a[j]^a[j-h];
这样写立刻显得逼格满满啊 逃)。