虽然从宏观上看希尔排序是把一堆数分组进行排序,但是从代码实现上来说,本质上还是两个数的两两比较
实现过程
- 增量gap是数组长度的一半,且每次循环过后都会将gap再缩小一半
- 获得增量gap之后将 i 设置为gap的值
- 每次的比较实际上都是两个数进行比大小的
- i 用于记录靠右边数字的索引
- 每次循环都把 i 的值给 index 变量存着,这样如果一个数需要和前面多个数进行比较的时候可以改变index来修改右边数的索引
- j 用于记录左边数字的索引
- 如果
arr[j] > arr[index]
的话就将两数换位置,并修改index:index = j;
- 下一轮如果
j -= gap
符合条件的话,这时候左边数的索引 j 就已经向左偏移了 gap 位了,而右边数索引index也相应偏移了 gap 位。这样可以做到一个数不停地和间隔gap位的前面的数进行插入排序比较 - 如果找到了一个左边数比右边数小的话,因为是用来插入排序,所以可以直接
break
来退出当次循环
- 如果
代码实现
import java.util.Arrays;
/**
* @author 小火娃
* @project_name: my_project
* @package_name: com.xiaohuowa.shell
*/
public class ShellSort {
public static void main(String[] args) {
// int[] arr = new int[]{2,9,4,7,3,3,6,5};
int[] arr = new int[]{15,5,2,7,12,6,1,4,3,9,8,10};
System.out.println("排序前数组:\t\t" + Arrays.toString(arr));
// 临时变量
int temp = 0;
// 记录比较次数
int time = 1;
int index= 0;
// 外层gap用于控制增量
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
// i用于在一轮排序中拿到靠右边的数字
for (int i = gap; i < arr.length; i++) {
// index 用于记录一次比较中右边数字的索引位置
index = i;
// j 用于在一轮排序中拿到靠左边的数字的索引
for (int j = i - gap; j >= 0; j -= gap) {
// 如果左边数字比右边大的话就换位
if (arr[j] > arr[index]) {
temp = arr[j];
arr[j] = arr[index];
arr[index] = temp;
// 换位之后把 j 赋值给右边数字的索引
// 这样当循环 j-=gap 的时候,就可以让改变后的右边索引和改变后的左边索引的两数进行比较了
index = j;
} else {
// 因为用的是插入排序,所以左边只要比右边小了,之后的循环就可以停了
break;
}
}
}
System.out.println("第" + time++ + "趟排序结果:" + Arrays.toString(arr));
}
System.out.println("排序完成后数组:\t" + Arrays.toString(arr));
}
}