希尔排序是插入排序的一种,又称“缩小增量排序”,是插入排序算法的一种更高效的改进版本
从图中可以看出每一趟排序中都分成 gap 组,每组都有 gap + 1 个元素,对每一组中的 arr[j] 和 arr[j - gap] 进行比较,如果 arr[j] < arr[j - gap] 则相互交换值
gap 初始值为原数组长度的一半,随后在其他趟次排序中 gap 值变为原来的一半,直到 gap 的值变为 0 后,数组中的元素变得有序
选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组
对分好组的每一组数据完成插入排序
减小增长量,最小减为1,重复第二步操作,知道增长量为0
public void shellSort(int[] arr){ int gap = arr.length / 2; while (gap > 0) { for (int i = gap; i < arr.length; i++) { //遍历各组中所有的元素(共gap组,每组有gap+1个元素),步长为gap for (int j = i - gap; j >= 0; j -= gap) { //如果当前元素大于加上步长gap后的那个元素,则交换值 if (arr[j] > arr[j + gap]){ exchange(arr,j,j + gap); } } } //增量gap逐步进行缩小 gap = gap / 2; } } public void exchange(int[] arr, int j, int i) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
public void shellSort2(int[] arr){ int gap = arr.length / 2; while (gap > 0) { //从第gap个元素,主格对比所在的组进行直接插入排序 for (int i = gap; i < arr.length; i++) { int j = i; int temp = arr[j]; if (arr[j] < arr[j - gap]){ while (j - gap >= 0 && temp < arr[j - gap]){ //移动 arr[j] = arr[j - gap]; j -= gap; } //当退出while循环后,就给temp找到了插入的位置 arr[j] = temp; } } //增量gap逐步进行缩小 gap = gap / 2; } } public void exchange(int[] arr, int j, int i) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
通过测试发现,在处理大批量数据时,希尔排序的性能确实高于插入排序
最优时间复杂度:根据步长序列的不同而不同
最坏时间复杂度:O(N2)
对于相同的两个数,可能由于分在不同的组中而导致它们的顺序发生变化。如图解中的两个5,在排完序后两者的位置发生了变化。所以希尔排序是不稳定的