一、插入排序的实现

1.什么是插入排序呢

插入排序的工作方式像许多人排序一手扑克牌。开始时,我们的左手为空并且桌子上的牌面向下。然后,我们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较。拿在左手上的牌总是排序好的,原来这些牌是桌子上牌堆中顶部的牌

2.具体步骤

第一轮:从第二位置的 6 开始比较,比前面 7 小,交换位置。

在这里插入图片描述

第二轮:第三位置的 9 比前一位置的 7 大,无需交换位置。

在这里插入图片描述

第三轮:第四位置的 3 比前一位置的 9 小交换位置,依次往前比较。
在这里插入图片描述

第四轮:第五位置的 1 比前一位置的 9 小,交换位置,再依次往前比较。
在这里插入图片描述

就这样依次比较到最后一个元素。

3.使用循环不变式证明算法的正确性

循环不变式的概念
简单了说就是每次循环都有某种性质,且该性质一直保持不变,直到循环结束。

循环不变式的三个性质:

1.初始化:循环的第一次迭代之前,它为真。
2.保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。
3.终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法时正确的。

对于插入排序,如何证明这三个性质

初始化:插入排序初始只有1个元素arr[0],所以该子数组是有序的
保持:每次插入元素到子数组中,该子数组一直保持有序性
终止:循环的终止条件是遍历到了最后一个将要插入的元素,此时插入过后,子数组已经拥有了原数组的所有数据,且保持有序

因此算法正确。

4.插入排序代码实现

import java.util.Arrays;

/**
 * @author:抱着鱼睡觉的喵喵
 * @date:2021/2/23
 * @description: 插入排序
 */
public class InsertSort {

    public static void main(String[] args) {
        int arr[] = {9,1,4,2,8};
        InsertSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void InsertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int insertVal = arr[i];
            int insertIndex =i - 1;
            while (insertIndex >= 0 && insertVal < arr[insertIndex]) {
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            arr[insertIndex + 1] = insertVal;
        }
    }
}

5.插入排序算法的分析

1.时间复杂度:最坏的情况就是原数组的数据是降序排列,最好的情况当然就是已经有序(升序)
最坏的情况:O(n^2)
最好的情况:O(n)
所以平均时间复杂度位O(n^2)

2.空间复杂度:O(1)

3.插入排序是稳定的;适用场景:数据规模较小


二、插入排序的优化

于插入排序,如果比较操作的代价比交换操作大的话,可以采用二分查找法来减少比较操作的次数。

1.二分查找算法概述(折半查找法):

二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x.

2.代码实现


import java.util.Arrays;

/**
 * @author:抱着鱼睡觉的喵喵
 * @date:2021/3/4
 * @description: 使用二分法优化直接插入
 */
public class DichotomizeInsertSort {
    public static void main(String[] args) {
        int arr[] = {
           2, 5, 8, -11, 6,-19, 7, 8
        };
        InsertSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void InsertSort(int arr[]) {
        int insertValue,mid = 0;
        int i,j,insertIndex;
        for (int k = 1; k < arr.length; k++) {
            i = 0;
            insertIndex  = k;
            j = k - 1;
            insertValue = arr[k];
            while (i <= j) {
                mid = (i + j) / 2;
                if (arr[mid] < insertValue) {
                    i = mid + 1;
                } else {
                    j = mid - 1;
                }
            }

            for (int s = insertIndex - 1; s >= i; s--) {
                arr[s + 1] = arr[s];
            }
            arr[i] = insertValue;
        }
    }

    
}

3.复杂度分析
时间复杂度:O(n^2)

二分插入排序只是减少了比较的次数,而数据的移动次数还是不变的;
本质上来说:直接插入排序和二分插入排序性能上差不了多少

posted on 2021-03-05 18:09  凸凸大军的一员  阅读(157)  评论(0编辑  收藏  举报