希尔排序

希尔排序

排序步骤

1、分组,以任意长度进行分组(这个长度我们称作增量gap);通常以总长度的一半这个数为依据进行分组,每间隔 gap 个数即为一组

2、组内排序;组内使用插入排序法进行排序

3、重新设置间隔分组;此次间隔数一般为原来的间隔数 gap 的基础上减半

4、组内排序

....... 

重复如上操作,最终,间隔数会减半到1,实现整体的插入排序,整体序列变为有序

希尔排序_第1张图片

什么不直接使用插入排序法?

希尔排序实际上是对插入排序的一种优化。插入排序在面对大规模的杂乱的数据时,需要进行多次交换,较为复杂;而希尔排序将大规模的数据减半,极大缩小了需要排序数据的规模,同时在最终的整体的数据进行排序时,整体数据近乎有序,此时进行插入排序的效率好

解析说明

希尔排序的效率取决于增量的选取,时间复杂度并不是一个定值

1) 最好情况:序列是正序排列,在这种情况下,需要进行的比较操作需(n-1)次。后移赋值操作为0次。即O(n)
2) 最坏情况:O(nlog2n)
3) 平均时间复杂度:O(nlog2n)

开始时,gap 取值较大,子序列中的元素较少,排序速度快,克服了直接插入排序的缺点

其次,gap值逐渐变小后,虽然子序列的元素逐渐变多,但大多元素已基本有序,所以继承了直接插入排序的优点,能以近线性的速度排好序

因此,希尔排序的时间复杂度相对于O(n²)好一些

最优的空间复杂度为开始元素已排序,则空间复杂度为 0;

最差的空间复杂度为开始元素为逆排序,则空间复杂度为 O(N);

平均的空间复杂度为O(1)

希尔排序代码

import org.junit.Test;

public class ShellSort {

    @Test
    public void test(){
        int[] arr = new int[]{12, 15, 4, 5, 8, 35};
        shellSprt(arr);
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }


    public static int[] shellSprt(int[] arr){
        int gap = arr.length /2;//一开始时的间距数
        int temp = 0;//插入排序的临时数

        while(gap > 0){//最后一遍排序的gap值为1
            for (int i = gap; i < arr.length; i++) {//每组的第一个数被认为是有序。因此从第二组数开始进行插入排序
                temp = arr[i];//当前需要插入的数
                for (int j = i; j >= gap; j -= gap) {//每组之间的每个数之间都相差gap个数
                    if(temp < arr[j - gap]){//插入排序向前比较
                        arr[j] = arr[j - gap];
                    }else{
                        break;//找到插入的位置则退出
                    }
                    arr[j - gap] =temp;//需要插入的位置
                }
            }
            gap /= 2;//gap不断减半直到其值为1
        }

        return arr;
    }
}

引用

【算法】排序算法之希尔排序 - 知乎 (zhihu.com)

排序:希尔排序(算法) - 简书 (jianshu.com)

你可能感兴趣的:(算法作业,java,算法,排序算法)