排序算法之--插入排序

318 阅读1分钟

插入排序

插入排序也是一种比较直观和容易理解的排序算法,通过构建有序序列,将未排序中的数据插入到已排序中序列,最终未排序全部插入到有序序列,达到排序效果。 主要步骤:

  • 将原始数据的第一个元素当成已排序序列,然后将除了第一个元素的后面元素当成未排序序列。
  • 从后面未排序元素中从前到后扫描,挨个取出元素,在已排序的序列中从后往前扫描,将从未排序序列中取出的元素插入到已排序序列的指定位置。
  • 当未排序元素数量为0时,则排序完成。

动图演示

beeaa3c9683c4bf183d9eff7a20ae79c_tplv-k3u1fbpfcp-zoom-1.gif


    /**
     * 插入排序
     *
     * @param array
     */
    public void inserSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int sortItem = array[i];
            int j = i;
            // 将当前元素插入到前面的有序元素里,将当前元素与前面有序元素从后往前挨个对比,然后将元素插入到指定位置。
            while (j > 0 && sortItem < array[j - 1]) {
                array[j] = array[j - 1];
                j--;
            }
            // 若当前元素在前面已排序里面不是最大的,则将它插入到前面已经确定了位置里。
            if (j != i) {
                array[j] = sortItem;
            }
        }

    }

运行:

  @Test
    public void addition_isCorrect() throws Exception {
        int[] array = new int[]{3, 2, 5, 8, 1, 9, 4, 6, 7};
        for (int i : array) {
            System.out.print(i + " ");
        }
        System.out.println("\n");
        selectSort(array);
        bubbleSort(array);
        inserSort(array);
        for (int i : array) {
            System.out.print(i + " ");
        }

    }

时间复杂度就是O(n^2),因为基本上每个元素都要处理多次,需要反复将已排序元素移动,然后将数据插入到指定的位置

优化一

可以看出,上面的写法性能很差,主要是交换次数太多了。

解决思路:将 交换 改成 挪动

  • 将待插入的元素备份。
  • 将头部元素中比待插入元素大的都往后 挪动一位。
  • 将备份元素插入合适的位置。

image.png

/**
     * 插入排序
     *
     * @param array 
     */
    public void inserSort2(int[] array) {
        for (int begin = 1; begin < array.length; begin++) {
            int element = array[begin];
            int cur = begin;
            // 将当前元素插入到前面的有序元素里,将当前元素与前面有序元素从后往前挨个对比,然后将元素插入到指定位置。
            while (cur > 0 && element < array[cur - 1]) {
                array[cur] = array[--cur];
            }
            array[cur] = element;
        }

    }

优化二

可以通过优化 比较次数来达到优化目的。 从头开始扫描每个元素,每当扫描到一个元素,就将它插入到头部合适的位置,使得头部数据依然有序。

之前找到合适的位置都是通过for循环遍历一遍,时间复杂度是O(n)。我们可以通过优化这查找位置的方法来提升时间。

注意到 头部序列其实是排序好的,所以我们可以通过二分搜索来查找合适的位置。 二分查找的时间复杂度是O(logN)。

/**
     * 找到index元素待插入的位置
     * <p>
     * 已经排好的区域是[0,index)
     *
     * @param index 待插入元素的位置
     * @return 应该插入的位置
     */
    private int search(int[] array, int index) {
        int v = array[index];
        int begin = 0;
        int end = index;
        while (begin < end) {
            int mid = (begin + end) >> 1;
            if (v < array[mid]) {
                end = mid;
            } else {
                begin = mid + 1;
            }
        }
        return begin;

    }

注意上面的代码和二分搜索有点不一样。搜索插入的位置,应该是最近大于待插入元素的位置。 知道应该插入的位置之后,我们还需要将从该位置到尾部的数据都往后移动一位,腾出位置插入目标值。

 private void insert(int[] array, int begin, int insertIndex) {
        //备份
        int element = array[begin];
        //将[insertIndex,begin)位置像后挪
        for (int i = begin; i > insertIndex; i--) {
            array[i] = array[i - 1];
        }
        array[insertIndex] = element;
    }

整体代码是:

 private void inserSort3(int[] array) {
        for (int begin = 1; begin < array.length; begin++) {
            //头部是有序的,使用二分查找,复杂度就是O(logn)
            int insertIndex = search(array, begin);
            insert(array, begin, insertIndex);
        }
    }

    private void insert(int[] array, int begin, int insertIndex) {
        //备份
        int element = array[begin];
        //将[insertIndex,begin)位置像后挪
        for (int i = begin; i > insertIndex; i--) {
            array[i] = array[i - 1];
        }
        array[insertIndex] = element;
    }

    /**
     * 找到index元素待插入的位置
     * <p>
     * 已经排好的区域是[0,index)
     *
     * @param index 待插入元素的位置
     * @return 应该插入的位置
     */
    private int search(int[] array, int index) {
        int v = array[index];
        int begin = 0;
        int end = index;
        while (begin < end) {
            int mid = (begin + end) >> 1;
            if (v < array[mid]) {
                end = mid;
            } else {
                begin = mid + 1;
            }
        }
        return begin;

    }

juejin.cn/post/690600… juejin.cn/post/694175…