- 希尔排序通过加大插入排序元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项能够大幅度移动,当这些数据项过一趟序之后,希尔排序算法减少数据项的间隔再进行排序。依次进行下去,进行这些排序时数据项之间的间隔被称为增量。
- 假设增量为d下面采用图解 就可以知道具体的详解
图片采用知乎上面的图片
假设数组是
第一趟希尔排序,设增量d=5
第一趟就有了 五个数组 【11,16,31】,【23,25】,【12,36】,【9,30】,【18,47】
第二趟希尔排序,增量d=3
第二趟就有了三个数组【9,11,25,47】,【18,23,31,36】,【12,16,30】
第三趟希尔排序,增量d=1
排序完成 ,每次都采用的插入排序,例如第一次取出来的数组是【16,11,31】采用插入排序后的是【11,16,31】一次计算就会出现第一次希尔排序后出现的五个数组
下面是java代码
@Test
public void shellSort() {
// 增量每次都是/2
int[] arr = {43, 32, 1, 34, 61, 12, 52, 39, 18, 17, 90, 30, 99, 67, 83, 2, 34, 53, 61, 47, 83, 32};
for (int step = arr.length / 2; step > 0; step /= 2) {
//从增量那组开始进行插入排序,直到完毕
for (int i = step; i < arr.length; i++) {
// 其中i-step就是上一个元素 如step是本节点的话 i-step就是上一个节点
if (arr[i] < arr[i - step]) {
// 将本节点的数据先放到一个临时位置
int temp = arr[i];
// 上一个节点的位置k
int k = i - step;
// 采用插入排序的算法
while (k >= 0 && arr[k] > temp) {//当还有多余的节点并且本节点的数据小于上一个节点 就会进入循环
// 两个数据交换 上一个节点的数据等于本节点的数据
arr[k + step] = arr[k];
//
k -= step;
}
// 将本节点的临时位置中的数据拿出来,从新赋值新的节点中
arr[k + step] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
输出
严格意义上的希尔排序
@Test
public void shellSort1() {
// 增量每次都是/2
int[] a = {43, 90, 1, 34, 61, 12, 52, 39, 18, 17};
// 数组的长度
int n = a.length;
// 首先是每次除以二 按照希尔排序的法则 选出一个增量 gap就是增量
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = 0; i < gap; i++) {//创建变量 i 并且循环是小于增量的时候进行自增
// j = i+ gap就是一次循环的时候的位置 开始是以第二个位置开始 用的插入排序的法则,假设左边的都是有顺序的
for (int j = i + gap; j < n; j += gap) {//外循环一次 内部循环一圈
// j-gap 当前下标减去增量的左边的数
// 采用插入排序 假设左边的都是有序的 那么当当前位置的数小于增量左边第一个的数 那么就进入循环
if (a[j] < a[j - gap]) {
// 将当前位置的数 存进临时变量
int temp = a[j];
// k是当前下标相对应的增量左边的那个数
int k = j - gap;
// 当前下标相对应的增量左边的那个数的下标不为负数,并且它大于当前下标的数 进入循环
while (k >= 0 && a[k] > temp) {
// 交换位置
a[k + gap] = a[k];
k = k - gap;
}
// 交换位置
a[k + gap] = temp;
}
}
}
}
System.out.println(Arrays.toString(a));
}
输出
可以看出第二个代码 采用的是插入排序算法实现的,所以有的面试官会问希尔排序和插入排序的关系,从上面的第二个代码就可以发现,希尔排序是基于插入排序实现的
总结
- 希尔排序将增量应用带插入排序,然后逐渐减少增量
- n-增量排序表示每隔n个元素进行排序
- 每次在一个数组中采用增量获取出来的新的数组都是采用的插入排序来排出新的信泽数组的