vlambda博客
学习文章列表

十大经典排序(八)--希尔排序

希尔排序思路:

        希尔排序也是一种插入排序(对插入排序不熟的同学可以看)

        由于插入排序不管数组分布如何,在排序过程中总是一步一步的对元素进行比较,移动,插入,比如[5,4,3,2,1,0]这种倒序序列,数组末端的0要回到首位置很是费劲,比较和移动元素均需n-1次

        基于这种情况,希尔排序采用跳跃分组的方式,现将原数组按某个跨度分组,然后对每个分组进行插入排序,这样的话后面的元素就能直接交换插入到前面去,之后再缩小跨度、分组、插入排序直至跨度为1,完成整个排序


题外话:希尔与插入排序的不同之处在于,它会优先比较距离排序较远的元素,这样可以大大减少远处数据插入到前面所需要的移动次数


为什么叫希尔排序?

  • 因为这个方法是一个叫希尔的大哥提出的十大经典排序(八)--希尔排序


十大经典排序(八)--希尔排序

算法步骤:

  1. 设定一个原始跨度k,将原数组分组,第一组元素下标为[0, 0+k, 0 + 2k...],第二组元素下标为[1, 1+k, 1+2k...],依次类推

  2. 对每组元素进行插入排序

  3. 缩小跨度k,重复1、2操作,直至k = 1,数组变成一个组,再对这个组进行排序即可

这里找来一张图方便大家理解:里面的增量就是上面描述的跨度



代码:

 1public static void sort(int[] arr) {
2    //设置跨度gap,每次循环缩小gap
3    for (int gap = arr.length / 2; gap > 0; gap /= 2) {
4        //从第gap个元素,逐个对其所在组进行直接插入排序操作
5        for (int i = gap; i < arr.length; i++) {
6            int j = i;
7            while (j - gap >= 0 && arr[j] < arr[j - gap]) {
8                //插入排序采用交换法
9                swap(arr, j, j - gap);
10                j -= gap;
11            }
12        }
13    }
14}
15
16//这里交换数组元素采用类似异或法的思想
17// 有兴趣同学可以玩玩异或法实现
18private static void swap(int arr[], int i, int j) {
19    arr[i] = arr[i] + arr[j];
20    arr[j] = arr[i] - arr[j];
21    arr[i] = arr[i] - arr[j];
22}

时间复杂度:O(n1.3~n2) 

空间复杂度:O(1)


以上仅是个人思路解法,觉得还不错欢迎点赞关注分享


往期精彩推荐