插入排序算法

2022/09/17 排序算法 共 1646 字,约 5 分钟

插入排序是一种较为简单和朴素的排序方法,它依次对序列中未排序的元素进行处理,将其插入到已排序序列中正确的位置。

基本原理

假设我们有一组无序的元素,我们可以把它分成两个部分,一部分需要按照从小到大的顺序排列,另一部分则保持无序状态。那么,我们只需要每次从无序部分中拿出一个元素,并把它插入到有序部分中合适的位置即可。

而寻找合适插入位置的过程,可以简化为在有序部分中找到一个位置 $i$,使位置 $i$ 处的元素小于等于要插入的元素,并且位置 $i+1$ 处的元素大于要插入的元素即可。

算法实现

以下是插入排序算法的 Python 代码实现(支持动画演示):

import algviz

def insertSort(nums_):
    viz = algviz.Visualizer(delay=2)
    nums = viz.createVector(data=nums_, cell_size=(40,200), histogram=True, show_index=False)
    # 直接从第二个元素开始。
    for ed in range(1, len(nums_)):
        i = ed - 1; j = ed
        nums.mark(algviz.color_silver, ed, len(nums), hold=True); viz.display(1)
        while i >= 0:
            nums.mark(algviz.color_red, j)
            if nums[i] <= nums[j]:
                nums.mark(algviz.color_gold, i); viz.display(1)
                break
            else:
                nums.mark(algviz.color_green, i, hold=True); viz.display(1)
                i -= 1
        if i + 1 != j:
            # 将元素插入到其左边第一个不大于它的元素后面
            nums.insert(i + 1, nums.pop(j))
            nums.removeMark(algviz.color_green); viz.display()
        nums.removeMark(algviz.color_silver)
    viz.display()

insertSort([5, 3, -2, 3, -1, 1, 4])

您可以在本地安装 algviz 后直接运行该代码片段!环境配置请参考:安装步骤

动画演示

让我们看一下动画中的例子!为了方便观察,这里将数组分成两个部分:有序部分和无序部分(使用灰色标记)。算法每轮处理无序部分中最左侧的一个元素(标记为红色),并将该元素和有序部分中的元素按照从右到左的顺序依次进行比较。如果有序部分中被比较的元素大于该元素,那么它被标记为绿色,算法继续向左搜索;否则,它被标记为黄色,同时算法停止搜索,并将要处理的元素插入到当前位置。随着算法的运行,我们可以观察到,数组中无序部分越来越少,最终我们得到一个完全有序的数组!

insertion_sort_example

算法特点

复杂度

在插入排序的实现过程中需要两层循环,第一层循环依次处理数组中每个未排序的元素,第二层为要处理的元素寻找合适的插入位置,因此算法的整体时间复杂度为 $O(n^2)$。

插入排序算法可以直接在输入的序列上进行操作,不需要额外的储存空间,因此算法的空间复杂度为 $O(1)$。

应用场景

插入排序算法属于基于比较的排序算法,且排序结果具有稳定性(即:逻辑上相等的元素在原始输入序列中的相对位置不会改变)。在目前储存空间较为廉价,而 CPU 的运行速度遇到瓶颈的情况下,该算法不适用于大规模序列的排序,但由于算法实现简单,其时间复杂度中的常数项较小,因此算法在一些小规模问题上可能会运行得更快。

算法优化

仔细想一下,在搜索合适插入位置的环节,我们是否有优化机会呢?

当然是有的!由于是在有序数组中进行搜索,所以我们可以使用更快的二分搜索算法替代原始的顺序搜索算法,大家感兴趣的话可以自己尝试一下。

但需要提醒的是,虽然二分查找算法的时间复杂度为 $O(log_2^n)$,但由于插入排序算法每次都需要 $O(n)$ 的时间复杂度来移动要插入的元素,因此算法的整体时间复杂度并不会降低。


本文遵守 Attribution-NoDerivs 2.0 Generic许可协议。 Attribution-NoDerivs 2.0 Generic

搜索: