算法之希尔排序

希尔排序

插入排序的改进,定义一个增量gap,从第1个元素开始,每次增加gap个,然后用插入排序对这几个值排好序,下次我缩小gap,再对新的值排好序,直到gap=1,再用插入排序排好序。

public class ShellSort {
    public static void main(String[] args) {
        int[] arr = {9, 6, 1, 3, 5, 2, 4, 7, 8};
        sort(arr);
    }

    public static void sort(int[] arr) {
        // 记录比较次数
        int num = 0;
        // 记录交换次数
        int swapNum = 0;
        for (int gap = arr.length/2; gap > 0 ; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                for (int j = i; j > gap - 1; j -= gap) {
                    num++;
                    if (arr[j] < arr[j - gap]) {
                        swap(arr, j, j - gap);
                        swapNum ++;
                    } else {
                        break;
                    }
                }
            }
        }

        print(arr);
        System.out.println("比较"+(num)+"次");
        System.out.println("交换"+(swapNum)+"次");
    }

    /**
     * 交换元素位置
     * @param arr 数组
     * @param i 位置1
     * @param j 位置2
     */
    static void swap(int[] arr, int i, int j) {
        // 记录原最小值,用于和最小值互换
        int temp = arr[i];
        // 数组中原最小值换为新的最小值
        arr[i] = arr[j];
        // 最小值的位置换为原最小值
        arr[j] = temp;
    }

    static void print(int arr[]) {
        Arrays.stream(arr).forEach(num->{
            System.out.print(num + " ");
        });
        System.out.println();
    }
}

这样虽然比插入排序效率高,但这个变量gap值并不是一个最合适的值,如果取Knuth序列,效率将更高。

h = 1

h = 3 * h + 1

当最大间隔大于数组长度的 1 3 \frac{1}{3} 31,将不适用这个序列。

public class ShellSort1 {
    public static void main(String[] args) {
        int[] arr = {9, 6, 1, 3, 5, 2, 4, 7, 8};
        sort(arr);
    }

    public static void sort(int[] arr) {
        // 记录比较次数
        int num = 0;
        // 记录交换次数
        int swapNum = 0;
        // 找出数组最大的间隔
        int h = 1;
        while (h <= arr.length/3) {
            h = h * 3 + 1;
        }
				// 间隔从最大的开始依次减小 前一个位置等于(h - 1) / 3
        for (int gap = h; gap > 0; gap = (gap - 1) / 3) {
            for (int i = gap; i < arr.length; i++) {
                for (int j = i; j > gap - 1; j -= gap) {
                    num++;
                    if (arr[j] < arr[j - gap]) {
                        swap(arr, j, j - gap);
                        swapNum++;
                    } else {
                        break;
                    }
                }
            }
        }

        print(arr);
        System.out.println("比较"+(num)+"次");
        System.out.println("交换"+(swapNum)+"次");
    }

    /**
     * 交换元素位置
     * @param arr 数组
     * @param i 位置1
     * @param j 位置2
     */
    static void swap(int[] arr, int i, int j) {
        // 记录原最小值,用于和最小值互换
        int temp = arr[i];
        // 数组中原最小值换为新的最小值
        arr[i] = arr[j];
        // 最小值的位置换为原最小值
        arr[j] = temp;
    }

    static void print(int arr[]) {
        Arrays.stream(arr).forEach(num->{
            System.out.print(num + " ");
        });
        System.out.println();
    }
}

看一下希尔排序的时间复杂度,最外层循环,当gap趋近于n时,执行次数为 n ( n − 1 ) 3 \frac{n}{\frac{(n-1)}{3}} 3(n1)n = 3 n n − 1 \frac{3n}{n-1} n13n ≈ \approx 3,所以这个常数项可以忽略不计,再看第二层循环,大约执行n次,第三次循环最多的情况大约执行n次,所以最差时间复杂度为 O ( n 2 ) O(n^2) O(n2),最好情况和插入排序一样,数组是有序的话,内存循环只执行一次,所以最好时间复杂度为 O ( n ) O(n) O(n),程序没有用到额外的空间,所以空间复杂度为 O ( 1 ) O(1) O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YoungJ5788

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值