3、直接插入排序

厨子大约 3 分钟数据结构算法算法基地面试排序算法

直接插入排序

袁记菜馆内

袁厨:好嘞,我们打烊啦,一起来玩会扑克牌吧。

小二:好啊,掌柜的,咱们玩会斗地主吧。

相信大家应该都玩过扑克牌吧,我们平常摸牌时,是不是一边摸牌,一边理牌,摸到新牌时,会将其插到合适的位置。这其实就是我们的插入排序思想。

直接插入排序:将一个记录插入到已经排好序的有序表中,从而得到一个新的有序表。通俗理解,我们首先将序列分成两个区间,有序区间和无序区间,我们每次在无序区间内取一个值,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间一直有序。下面我们看一下动图吧。

注:为了更清晰表达算法思想,则采用了挖掉待排序元素的形式展示,后面也会采取此形式表达。

动画模拟

直接插入排序
直接插入排序

直接插入排序代码

代码

Java

class Solution {
    public int[] sortArray(int[] nums) {
        //注意 i 的初始值为 1,也就是第二个元素开始
        for (int i = 1; i < nums.length; ++i) {
            //待排序的值
            int temp = nums[i];
            //需要注意
            int j;
            for (j = i-1; j >= 0; --j) {
                //找到合适位置
                if (temp < nums[j]) {
                    nums[j+1] = nums[j];
                    continue;
                }
                //跳出循环
                break;
            }
            //插入到合适位置,这也就是我们没有在 for 循环内定义变量的原因
            nums[j+1] = temp;
        }
        return nums;
    }
}

Python

from typing import List
class Solution:
    def sortArray(self, nums: List[int])->List[int]:
        # 注意 i 的初始值为 1 ,也就是第二个元素开始
        for i in range(1, len(nums)):
            # 待排序的值
            temp = nums[i]
            # 需要注意
            j = i - 1
            while j >= 0:
                # 找到合适位置
                if temp < nums[j]:
                    nums[j + 1] = nums[j]
                    j -= 1
                    continue
                # 跳出循环
                break
            # 插入到合适位置,这也就是我们没有在循环内定义变量的原因
            nums[j + 1] = temp
        return nums

时间复杂度分析

最好情况时,也就是有序的时候,我们不需要移动元素,每次只需要比较一次即可找到插入位置,那么最好情况时的时间复杂度为 O(n)。

最坏情况时,即待排序表是逆序的情况,则此时需要比较 2+3+....+n = (n+2)(n-1)/2,移动次数也达到了最大值,3 +4+5+....n+1 = (n+4)(n-1)/2,时间复杂度为 O(n^2).

我们每次插入一个数据的时间复杂度为 O(n),那么循环执行 n 次插入操作,平均时间复杂度为 O(n^2)。

空间复杂度分析

根据动画可知,插入排序不需要额外的存储空间,所以其空间复杂度为 O(1)

稳定性分析

我们根据代码可知,我们只会移动比 temp 值大的元素,所以我们排序后可以保证相同元素的相对位置不变。所以直接插入排序为稳定性排序算法。