插入排序

插入排序

网上找的动图

img

插入排序就像码牌。

  • 每次拿到一个新的牌到手里,都从右往左地比较一下,

    比如手里有1,2,4,5,抓到一张3,那就先和5比,3小于5,把5往后挪一下,3占到5原来的位置;

    3再和4比,发现3比4小,把4往后挪一下,3占4原来的位置;

    3再和2比,发现3比2大,那么3就到此停住,站住自己的位置(由此说明插入排序是稳定的)。因为2以前都是有序的。

所以插入排序就是认为,数组里的数分为有序的部分无序的部分。最开始只有第一个数是有序的,然后从第二个数开始遍历,每一个数都和前面有序的部分做比较交换,并找到属于自己的位置。最后所有的数都进入有序的部分,排序结束。

算法实现

static void sort(int[] arr) {
    if (null == arr) {
        return;
    }
    for (int i = 1; i < arr.length; i++) {
        for (int j = i; j > 0; j--) {
            // 每个数都和前面的数作比较,如果后面的数比前面的小,则交换
            if (arr[j] < arr[j - 1]) {
                swap(arr, j, j - 1);
            }
        }
    }
}

static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

这种写法很直接,直接比较交换。

换一种写法(从网上摘的)

static int[] insertSort(int[] sourceArr) {
    if (null == sourceArr) {
        return null;
    }
    // 对 arr 进行拷贝,不改变参数内容
    int[] targetArr = Arrays.copyOf(sourceArr, sourceArr.length);

    // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
    for (int i = 1; i < sourceArr.length; i++) {

        // 记录要插入的数据
        int temp = targetArr[i];

        // 从已经排序的序列最右边的开始比较,找到比其小的数
        int j = i;
        while (j > 0 && temp < targetArr[j - 1]) {
            targetArr[j] = targetArr[j - 1];
            j--;
        }
        // 存在比其小的数,把这个数插入到第j个槽上
        if (j != i) {
            targetArr[j] = temp;
        }
    }

    return targetArr;
}

换一种说法,对数组排序,等价于:对数组的0~倒数第二个数排序,然后把最后一个元素插入到这个有序数组中。其实这个说法就很像递归了。存在子问题,问题规模在变小。

递归的形式

static void recursiveSort(int[] arr) {
    recursiveSort(arr, 0);
}

static void recursiveSort(int[] arr, int i) {
    if (i >= arr.length) {
        return;
    }
    // 0~i插入排序
    int j = i;
    int temp = arr[i];
    while (j > 0 && temp < arr[j - 1]) {
        arr[j] = arr[j - 1];
        j--;
    }
    if (i != j) {
        arr[j] = temp;
    }
    // arr的0~i部分已经排好序了,子问题就是计算i+1位置的数的排序
    recursiveSort(arr, i + 1);
}
原文地址:https://www.cnblogs.com/SimonZ/p/15468606.html