希尔排序,也称递减增量排序算法,1959年Shell发明。是插入排序的一种高速而稳定的改进版本。希尔排序是非稳定排序算法。希尔排序是先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
将待排序数组按照步长gap进行分组,然后将每组的元素利用直接插入排序的方法进行排序;每次再将gap折半减小,循环上述操作;当gap=1时,利用直接插入,完成排序。
可以看到步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。一般来说最简单的步长取值是初次取数组长度的一半为增量,之后每次再减半,直到增量为1。更好的步长序列取值可以参考维基百科。
①. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;(一般初次取数组半长,之后每次再减半,直到增量为1)
②. 按增量序列个数k,对序列进行k 趟排序;
③. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
在上面这幅图中: 初始时,有一个大小为 10 的无序序列。
在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组。
接下来,按照直接插入排序的方法对每个组进行排序。
在第二趟排序中,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组。
按照直接插入排序的方法对每个组进行排序。
在第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组。 按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。
需要注意一下的是,图中有两个相等数值的元素 5 和 5 。我们可以清楚的看到,在排序过程中,两个元素位置交换了。 所以,希尔排序是不稳定的算法。
public class ShellSort {
public static void sort(int[] arr) {
int gap = arr.length / 2;
for (;gap > 0; gap = gap/2) {
for (int j = 0; (j + gap) < arr.length; j++) { //不断缩小gap,直到1为止
for (int k = 0; (k + gap) < arr.length; k+=gap) { //使用当前gap进行组内插入排序
if (arr[k] > arr[k+gap]) { //交换操作
arr[k] = arr[k] + arr[k+gap];
arr[k+gap] = arr[k] - arr[k+gap];
arr[k] = arr[k] - arr[k+gap];
System.out.println(" Sorting: " + Arrays.toString(arr));
}
}
}
}
}
}
不稳定排序算法,希尔排序第一个突破O(n2)的排序算法;是简单插入排序的改进版;它与插入排序的不同之处在于,它会优先比较距离较远的元素,直接插入排序是稳定的;而希尔排序是不稳定的,希尔排序的时间复杂度和步长的选择有关,常用的是Shell增量排序,也就是N/2的序列,Shell增量序列不是最好的增量序列,其他还有Hibbard增量序列、Sedgewick 增量序列等,具体可以参考动力节点在线的视频课程给出的详细内容。
提枪策马乘胜追击04-21 20:01
代码小兵92504-17 16:07
代码小兵98804-25 13:57
杨晶珍05-11 14:54