图解希尔排序的交换法和移位法
②从每组的第二个元素开始,依次和前面的所有元素比较大小, 和下标为0的元素同组的第二个元素的下标为0+增量(这里用gap表示),所以从gap开始:
③这里第一组的元素分别为8和3,不满足顺序,进行交换,然后gap后移,直到遍历完所有元素,此时每个组内的元素有序:
④缩小增量为原来的一半,5/2=2,重新进行分组:
⑤重复②③步骤,使每个组内的元素有序:
⑥再次缩小增量为原来的一半,2/2=1,重新分组,此时所有的元素都在一个组内
⑦从第二个元素开始依次和前面的元素比较,不满足顺序则交换,当所有元素交换完后,即排序完成,如下图:
代码实现:
public static int[] transShellSort(int[] arr) {
int tmp = 0;
int len = arr.length;
//增量从数组长度/2开始,之后每次都/2,只要得到的增量大于0,就一直循环
for (int gap = len / 2; gap > 0; gap /= 2) {
//从每组的第二个元素开始,依次和前面的所有元素比较大小,
// 和下标为0的元素同组的第二个元素的下标为0+gap,所以从gap开始
for (int i = gap; i < arr.length; i++) {
//j从i的前一个元素开始,直到遍历i前面的所有同组元素
for (int j = i - gap; j >= 0; j -= gap) {
//这里虽然定义j=i-gap,但这只是初始j的值,当j-=gap后这个等式便不再成立,
// 所以交换时不能直接将arr[j]和arr[i]的值交换
if (arr[j] > arr[j + gap]) {
tmp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = tmp;
}
}
}
}
return arr;
}
和交换法相比,移位法是对每个组直接进行插入排序。还是采用上面那组元素:
我们以增量缩小为2时举例,此时所有元素分为两组,分别为[3,1,0,9,7] 和 [5,6,8,4,2]
分别对两组元素直接进行插入排序,具体流程可以看《》中关于插入排序的讲解。
同样,当所有的元素分到一个组,即增量为1时,进行排序后的结果就是最终的排序结果。
代码实现:
public static int[] moveShellSort(int[] arr) {
int tmp = 0;
int len = arr.length;
for (int gap = len / 2; gap > 0; gap /= 2) {
//从第gap个元素开始,逐个对其所在的组进行直接插入排序
for (int i = gap; i < len; i++) {
int j = i;
//这里的tmp就相当于插入排序中的insertVal,而j-gap就相当于insertIndex
tmp = arr[j];
//gap所在的组,前面的数如果大于待插入的数,那么表示没有找到插入位置,
// 其中arr[j]和arr[j-gap]为同组相邻的两个数
if (arr[j] < arr[j - gap]) {
while (j - gap >= 0 && arr[j - gap] > tmp) {
arr[j] = arr[j - gap];
//下标前移量为步长
j -= gap;
}
//当跳出while循环时,表示找到了插入位置
//当j-gap小于0时,tmp的位置下标就是j-gap+gap=j
arr[j] = tmp;
}
}
}
return arr;
}