zoukankan      html  css  js  c++  java
  • 16-希尔排序

    1. 引入

    插入排序存在的问题: 现在有这么一个数组,arr={2,3,4,5,6,1};现在需要插入的数 1 (最小),过程是:

    {2,3,4,5,6,6} → {2,3,4,5,5,6} → {2,3,4,4,5,6} → {2,3,3,4,5,6} → {2,2,3,4,5,6} → {1,2,3,4,5,6}
    

    [结论] 当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响。

    2. 概述

    • 希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序
    • 基本思想
      • 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序
      • 随着增量逐渐减少,每组包含的关键词越来越多
      • 增量减至1时,整个文件恰被分成一组,算法便终止
    • 较之于〈插入排序〉效率高的原因:
      • 在间隔大的时候,挪动的次数少
      • 在间隔小的时候,挪动的距离短

    3. 标配

    • 平均时间复杂度:O(n^1.3)
    • 最坏时间复杂度:O(n^2)
    • 最好时间复杂度:O(n)
    • 空间复杂度:O(1),内排序
    • 不稳定 // 比方说有俩 1,排之前 ..., a1, ..., b1, ... 排之后可能会出现 b1, a1, ...

    4. 举例

    • 希尔排序的思想是使数组中任意间隔为 h 的元素都是有序的。这样的数组被称为h 有序数组。换句话说,一个h 有序数组就是h 个互相独立的有序数组编织在一起组成的一个数组
    • 在进行排序时,如果 h 很大,我们就能将元素移动到很远的地方,为实现更小的 h 有序创造方便。用这种方式,对于任意以 1 结尾的 h 序列,我们都能将数组排序 → 这就是希尔排序。

    5. 代码实现

    public class ShellSort {
        public static void main(String[] args) {
            int[] arr = {9, 6, 11, 3, 5, 12, 8, 7, 10, 15, 14, 4, 1, 13, 2};
            print(arr);
            sortBySwap(arr);
            print(arr);
        }
    
        public static void sortBySwap(int[] arr) {
            // 比每次按半劈效率高
            // Knuth 序列: h = 1, h = 3 * h - 1
            int h = 1;
            // 退出时 h 等于 arr.length 分割时的最大间隔
            while (h <= arr.length / 3) h = h * 3 + 1;
            /*
             * i = gap;
             * - 相隔 gap 个的元素构成一个数组,对这些 [子数组(h数组)] 进行插入排序
             * - 回忆插入排序的思想,外层 for 循环为啥 i 上来就是 1?
             *     把 n 个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只
             *     包含 1 个元素,无序表中包含有 n-1 个元素 (这其中第一个元素在原始
             *     数组中的索引不就是 1 吗),排序过程中每次从无序表中取出第一个元素,
             *     把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的
             *     适当位置,使之成为新的有序表。
             * - Shell = 插排思想 + [h数组]
             *     → i 初始化为 [h数组] 中的无序表的第 1 个元素,也就是 i = gap。
             * -----------------------------------------------------------------
             * i++;
             * - i+=gap 只能实现第 1 个子数组有序,应该把间隔为 gap 的子数组都排序
             * - 多个 [h数组] 编制在一起构成原始数组,i++ 直到 length-1,则保证了对
             *     每个 [h数组] 的元素都进行了插入排序
             * - 外层的一个循环周期(gap次)之后,就会使每个 [h数组] 中的有序表元素数+1
             * -----------------------------------------------------------------
             * j > gap-1
             * - 因为条件的右半部分是 a[j] < a[j-gap]
             *     如果条件左边写的是 j > 0,再配合着 a[j-gap] 可不就数组下标越界了吗?
             * - 又因为这是 [h数组], 每个 [h数组] 的第1个元素:0, 1, ... , gap-1
             *     故结合 a[j-gap],j 最小应等于 gap -> a[j-gap] = a[0]
             */
            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 && arr[j] < arr[j-gap]; j -= gap)
                        swap(arr, j, j-gap);
        }
    
        public static void sortByMove(int[] arr) {
            int insertIndex, insertValue;
            for (int gap = arr.length >> 1; gap > 0; gap/=2) {
                for (int i = gap; i < arr.length; i++) {
                    insertIndex = i;
                    insertValue = arr[insertIndex];
                    while (insertIndex > gap-1 && insertValue < arr[insertIndex-gap]) {
                        arr[insertIndex] = arr[insertIndex-gap];
                        insertIndex -= gap;
                    }
                    arr[insertIndex] = insertValue;
                }
            }
        }
    
        public static void print(int[] arr) {
            for (int i = 0; i < arr.length; i++)
                System.out.print(arr[i] + " ");
            System.out.println();
        }
    
        public static void swap(int[] arr, int a, int b) {
            int temp = arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }
    }
    

    6. sortBySwap全过程

  • 相关阅读:
    avrdude: stk500_getsync(): not in sync: resp=0x00
    PCB封装技术
    C/C++基础问题归集
    mf210v 端口的映射
    alsamixer 在音频子系统的使用
    rp2836 网卡以及串口与接插件位置关系
    RP2837 IN1-IN2 对应关系 2路DI
    RP2837 OUT1-OUT2 对应关系 2路DO
    RP2836 板卡信息标识
    RP2836 OUT0-OUT7 对应关系
  • 原文地址:https://www.cnblogs.com/liujiaqi1101/p/12327604.html
Copyright © 2011-2022 走看看