You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Python中第三种Insertionsort实现速度远快于其他版本?

Python三版插入排序性能差异原因解析

问题背景

三个实现均属于插入排序范畴,理论时间复杂度同为O(n²),但在长度为10000的随机整数列表上测试时,性能差距达到两个数量级以上,测试输出结果如下:

Function finished in 2.2218 second(s)
Function finished in 3.4489 second(s)
Function finished in 0.0 second(s)

测试所用的排序实现与计时代码如下:

import time
import numpy as np

def insertionsort1(array):
    n = len(array)
    for i in range(n):
        index = 0
        while array[i] > array[index]:
            index +=1
        element = array.pop(i)
        array[index:index] = [element]
    return array


def insertionsort2(arr):
    n = len(arr)
    for i in range(1, n):
        for j in range(i):
            if arr[i] <= arr[j]:
                cache = arr.pop(i)
                arr[j:j] = [cache]
    return arr

def insertionsort3(arr):
    n = len(arr)
    for i in range(n-1):
        pos = i+1
        while pos > 0 and arr[pos] < arr[pos-1]:
            arr[pos], arr[pos-1] = arr[pos-1], arr[pos]
            pos -= 1
    return arr

def timeit(func, arr, n_runs):
    times = []
    for i in range(n_runs):
        start = time.time()
        _ = func(arr)
        end = time.time()
        times.append(end - start)
    avg_time = sum(times) / len(times)
    print(f'Function finished in {round(avg_time, 4)} second(s)')

array = list(np.random.randint(1, 10000, size=10000))
timeit(insertionsort1, array, 1)
timeit(insertionsort2, array, 1)
timeit(insertionsort3, array, 1)

性能差异核心原因

时间复杂度O(n²)仅描述算法操作次数随数据规模增长的量级,实际运行速度由单次操作的开销、实际执行的总操作次数共同决定,三个版本的性能差距来自三个核心层面:

  • 前两个版本重度依赖高开销的列表动态操作
    Python列表是基于连续内存块实现的动态数组,非尾部位置的pop(i)、切片插入arr[a:a] = [x]操作,都需要把操作位置之后的所有元素整体挪动内存位置,单次操作耗时和列表长度正相关。前两个版本每次插入元素都要执行一次弹出+一次切片插入,等于在比较的O(n²)开销之外,又叠加了一层O(n²)的内存移动开销,常数项被拉得极高。第三个版本全程只做相邻元素的交换,单次交换仅涉及两个值的读写,没有整块内存挪动的额外成本,单次操作的开销比前两个版本低一到两个数量级。
  • 前两个版本存在明显的逻辑冗余
    insertionsort1每次找插入位置都从列表头0索引开始遍历,完全没有利用插入排序“插入位左侧永远有序”的特性,做了大量重复比较;insertionsort2找到插入位置完成插入后没有终止内层j循环,插入操作已经改变了列表的索引映射,后续循环比较的已经不是最初要插入的元素,会产生大量无意义的比较甚至额外的重复操作。
  • 测试代码的复用逻辑放大了性能差距
    计时逻辑每次都传入同一个原始列表对象,没有在单次测试后重置打乱数组。前两个函数执行完成后,列表已经被修改为有序状态,第三个函数实际处理的是完全有序的输入。插入排序在完全有序场景下仅需要O(n)次比较,不需要做任何交换操作,耗时极短,被四舍五入显示为0.0s。如果每次测试都传入重新打乱的同规模随机数组,第三个版本的实际耗时大概在2~3秒区间,依然比前两个版本快数倍,但不会出现0秒的极端结果。

内容的提问来源于stack exchange,提问作者moritz.burmester

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:48:25