【排序】插入排序,抓一手好牌|Java 刷题打卡

178 阅读2分钟

本文正在参加「Java主题月 - Java 刷题打卡」,详情查看活动链接

一、前言

插入排序:是一种简单直观的排序算法

这个算法把数组分为 有序区无序区,每次都从无序区中拿出一个元素,插入到有序区正确的位置上,使有序区保持有序。 不断重复这个操作,直到整个数组都有序。

就像抓牌,每抓到一张排,将其插入合适的位置。

举栗,动图如下: insertionSort.gif



二、知识点

知识点,如下:

  1. 时间复杂度
  2. 逆序对
  3. 实现:简单实现

(1)时间复杂度

  • 最好情况:顺序,时间复杂度 O(N)

  • 最坏情况:逆序,时间复杂度 O(N ^ 2)

  • 稳定性:稳定。

    例如,原数组 {4, 1, 4}

    不稳定:排序过程中,第二个 4 排在了 第一个 4 前面。

排序总图,如图:

2021-05-2318-41-48.png


(2)逆序对

逆序对(inversion:对于下标 i < j,如果 arr[i] > a[j],则称 (i, j) 是一对逆序对。

举个栗子,序列 {34, 8, 64, 51, 32, 21} 有多少逆序对?

9对:

(34, 8), (34, 32), (34, 21), (64, 51), 

(64, 32), (64, 21), (51, 32), (51, 21), (32, 21)

可得定理:

  • 定理:任意 N 个不同元素组成的序列平均具有 N(N-1)/4 个逆序对
  • 定理:任何仅以交换相邻两元素来排序的算法,其平均时间复杂度为 O(N^2)

那么逆序对,有什么用呢?

  1. 代表了,需要交换的次数。

  2. 为提高算法效率提供基础

那么要提高算法效率,必须:

  1. 每次消去不止 1个逆序对

  2. 每次交换相隔较远的 2个元素


(3)实现

思路:摸进一张牌,放在队尾,然后循环比较前一张,直至大小(顺序相反),跳出循环,然后将拿到的牌放定。

代码如下:

public class InsertSort {

    // Time: O(n^2), Space: O(1)
    public void sort(int[] arr) {
        if (arr == null || arr.length == 0) return;
        for (int i = 1; i < arr.length; ++i) {
            int cur = arr[i];
            int j = i - 1;
            while (j >= 0 && arr[j] > cur) {
                arr[j+1] = arr[j];
                --j;
            }
            arr[j+1] = cur;
        }
    }
}