排序之(2)希尔排序

希尔排序

链接: 插入排序.

基本思想:

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为“缩小增量排序”,同时该算法是冲破O(n2)的第一批算法之一。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

基本步骤:

我们来看下希尔排序的基本步骤,在此我们选择增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2…1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。
(注明:以下图片参考其他博客)
在这里插入图片描述

代码实现:

生成指定长度、最小值和最大值的数组:

    private static int[] buildArrar(int length, int min, int max) {
        int [] array=new int[length];
        for (int i = 0; i < length; i++) {
            array[i]=(int)Math.floor(Math.random()*(max-min+1))+min;
        }
        return array;
    }

希尔排序:

    private static void shellSort(int[] arr) {
        int length = arr.length;
        int temp;
        int j;
        int gap = length / 2;
        while (gap >= 1) {
            for (int i = gap; i < length; i++) {
                if (arr[i] < arr[i - gap]) {
                    temp = arr[i];
                    for (j = i - gap; j >= 0 && temp < arr[j]; j -= gap) {
                        arr[j + gap] = arr[j];
                    }
                    arr[j + gap] = temp;
                }
            }
            gap/=2;
        }
    }

希尔排序另外一种实现:

该种代码实现和上述图中的过程保持一致,每一次只比较按增量分开的同一个数组;

    private static void shellSort1(int[] arr) {
        int length = arr.length;
        int temp;
        int k;
        int gap = length / 2;
        while (gap >= 1) {
            for (int i = 0; i < gap; i++) {
                for (int j = i + gap; j < length; j += gap) {
                    if (arr[j] < arr[j - gap]) {
                        temp = arr[j];
                        for (k = j - gap; k >= 0 && temp < arr[k]; k -= gap) {
                            arr[k + gap] = arr[k];
                        }
                        arr[k + gap] = temp;
                    }
                }
            }
            gap /= 2;
        }
    }

排序结果

    public static void main(String[] args) {
        int[] array = buildArrar(10, 1, 10);
        //排序前打印
        System.out.println("排序前:");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }

        //生成数组arr,然后利用Ayyays里的排序算法进行排序打印结果,为了和插入排序结果进行比较,看插入排序结果是否正确。
        System.out.println("");
        System.out.println("正确排序:");
        int[] arr = new int[array.length];
        for (int i = 0; i < arr.length; i++) {
            arr[i]=array[i];
        }
        Arrays.sort(arr);
        for (int i = 0; i < array.length; i++) {
            System.out.print(arr[i]+" ");
        }

        //希尔排序
        shellSort(array);

        //希尔排序结果
        System.out.println("");
        System.out.println("排序后:");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
    }

打印结果

在这里插入图片描述

时间复杂度:

shell排序的时间复杂度是根据选中的 增量d 有关的,所以分析shell排序的时间复杂度是个比较麻烦的事;这里只给出答案,不推算了;

     在最优的情况下,时间复杂度为:O(n ^ (1.3) )   (元素已经排序好顺序)

     在最差的情况下,时间复杂度为:O(n ^ 2);

空间复杂度:

从代码中可以看到,排序过程中只要一个辅助空间gap用于存储增量,temp用于存储未排序数,所需要的变量个数固定,和数组长度N无关,所以空间复杂度O(1)。
length变量可用也可以不用。

稳定性:

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小,插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值