希尔排序
希尔排序:确定一个增量k,每间隔k取一个数值,对这个序列进行快速排序,不断缩小k的值,进行相同操作,直到k的值1的时候,对整个数组进行一次全排序,这个时候整个数组是有序的。增量的取值可能会极大的影响排序的性能,一般选取N/2作为k的值,但这不一定是最佳值。
举个例子
有一个数组: 3 2 6 8 1
第一次增量设置为2:
先对 3 6 1 排序:1 3 6
再对 2 8 排序: 2 8
整合:1 2 3 8 6
第二次增量为1:
增量为1时对整体排序:1 2 3 6 8
代码实现
public class ShellSort {
/**
* 希尔排序:通过一个合适的增量来对一个长度为N的数组进行排序,当增量为1时,才对整个数组进行排序,每次小规模排序采用的是插入排序
* 进行排序时选择一个合理的希尔增量会对程序性能产生较大的影响,通常我们选择N/2作为增量
*/
//initIncr为初始增量
public static int[] shellSort(int[] arr, int initIncr) {
int len = arr.length;
while (initIncr >= 1) {
//增量大小取决于这一次需要进行多少次排序
for (int k = 0; k < initIncr; k++) {
for (int i = k; i < len; i += initIncr) {
//将当前元素存起来
int current = arr[i];
//从当前元素的前一个开始元素开始比较并移动
int j = i - initIncr;
while (j >= 0 && arr[j] > current) {
arr[j + initIncr] = arr[j];
j -= initIncr;
}
//由于前面j-initIncr导致此处应该用j+initIncr
arr[j + initIncr] = current;
}
}
initIncr /= 2;
}
return arr;
}
public static void main(String[] args) {
Random r = new Random();
int[] arr = new int[20];
for (int i = 0; i < arr.length; i++) {
arr[i] = r.nextInt(100);
}
//未排序
System.out.printf("排序前:%s \n", Arrays.stream(arr).boxed().map(Object::toString).collect(Collectors.joining(" ")));
//排好序
System.out.printf("排序后:%s \n", Arrays.stream(shellSort(arr, 4)).boxed().map(Object::toString).collect(Collectors.joining(" ")));
}
}
运行结果
排序前:14 47 56 97 5 40 39 33 39 72 91 63 51 81 96 34 3 20 63 7
排序后:3 5 7 14 20 33 34 39 39 40 47 51 56 63 63 72 81 91 96 97