Python数据结构(十二):插入排序详解

Python数据结构(十二):插入排序详解

本文是Python数据结构系列的第十二篇,我们将深入探讨基本排序算法中的插入排序。插入排序是一种简单直观的排序算法,通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

一、插入排序的基本概念

插入排序(Insertion Sort)是一种简单的排序算法。它的工作原理:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。因此需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

插入排序的名称由来

这个算法的名字直接反映了它的工作原理:"插入"未排序元素到已排序序列的正确位置。算法的核心思想就是通过"插入"操作来逐步构建有序序列。

插入排序的基本思想

插入排序的基本思想可以概括为:将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,将其插入到已排序部分的正确位置,直到所有元素都插入完毕。

插入排序的直观理解:

想象一下整理手中的扑克牌:我们从左到右依次将每张牌插入到已整理牌堆中的正确位置,保持手中的牌始终有序。

二、插入排序的算法原理

2.1 算法步骤

插入排序的算法步骤可以详细描述如下:

  1. 初始状态:将第一个元素视为已排序序列
  2. 取出元素:取出下一个未排序元素作为待插入元素
  3. 扫描比较:从已排序序列的末尾开始向前扫描
  4. 移动元素:如果已排序元素大于待插入元素,将该元素向后移动一位
  5. 插入元素:找到合适位置后,将待插入元素插入
  6. 重复过程:重复步骤2-5,直到所有元素都插入完毕

2.2 排序过程演示

以下是一个具体的排序过程示例:

初始数组: [64, 34, 25, 12, 22, 11, 55]

第一轮插入:

  • 将第一个元素64视为已排序:[64]
  • 取出第二个元素34,与64比较,34<64,将64后移,插入34
  • 结果: [34, 64, 25, 12, 22, 11, 55]

第二轮插入:

  • 已排序部分:[34, 64]
  • 取出第三个元素25,从后向前比较:25<64,64后移;25<34,34后移;插入25
  • 结果: [25, 34, 64, 12, 22, 11, 55]

第三轮插入:

  • 已排序部分:[25, 34, 64]
  • 取出第四个元素12,从后向前比较并移动元素,插入12
  • 结果: [12, 25, 34, 64, 22, 11, 55]

继续这个过程...

最终结果: [11, 12, 22, 25, 34, 55, 64]

三、Python实现插入排序

3.1 基础实现

python 复制代码
def insertion_sort(arr):
    """
    插入排序基础实现
    :param arr: 待排序的列表
    :return: 排序后的列表
    """
    # 从第二个元素开始,第一个元素视为已排序
    for i in range(1, len(arr)):
        # 当前待插入的元素
        key = arr[i]
        # 已排序部分的最后一个元素索引
        j = i - 1
        
        # 从后向前扫描,找到插入位置
        while j >= 0 and key < arr[j]:
            # 将大于key的元素向后移动
            arr[j + 1] = arr[j]
            j -= 1
        
        # 插入key到正确位置
        arr[j + 1] = key
    
    return arr

# 测试插入排序
arr = [64, 34, 25, 12, 22, 11, 55]
print(f'原始数组: {arr}')
print(f'插入排序后: {insertion_sort(arr.copy())}')

3.2 实现细节

外层循环
python 复制代码
for i in range(1, len(arr)):
  • 从第二个元素开始遍历(索引1)
  • i表示当前待插入元素的索引
  • 每次循环处理一个未排序元素
待插入元素
python 复制代码
key = arr[i]
  • 保存当前待插入的元素值
  • 后续移动操作会覆盖该位置,需要先保存
内层循环
python 复制代码
j = i - 1
while j >= 0 and key < arr[j]:
  • j从已排序部分的最后一个元素开始
  • 向前扫描,直到找到插入位置或到达开头
  • 条件:j有效且当前元素大于key
元素移动
python 复制代码
arr[j + 1] = arr[j]
j -= 1
  • 将大于key的元素向后移动一位
  • j向前移动,继续比较前一个元素
插入操作
python 复制代码
arr[j + 1] = key
  • 找到插入位置后,将key放入
  • j+1是因为while循环结束时j指向小于key的元素或-1

四、插入排序的时间复杂度分析

4.1 时间复杂度计算

最好情况(数组已排序)
  • 每次只需比较一次,不需要移动
  • 比较次数:n-1次
  • 移动次数:0次
  • 时间复杂度:O(n)
最坏情况(数组完全逆序)
  • 每次需要比较和移动所有已排序元素
  • 比较次数:1 + 2 + ... + (n-1) = n(n-1)/2
  • 移动次数:n(n-1)/2
  • 时间复杂度:O(n²)
平均情况
  • 大约需要n²/4次比较和移动
  • 时间复杂度:O(n²)

4.2 空间复杂度

  • 插入排序是原地排序算法
  • 只需要常数级别的额外空间
  • 空间复杂度:O(1)

4.3 时间复杂度总结

情况 比较次数 移动次数 时间复杂度
最好 n-1 0 O(n)
最坏 n(n-1)/2 n(n-1)/2 O(n²)
平均 ≈n²/4 ≈n²/4 O(n²)

五、插入排序的特点

5.1 优点

  1. 简单易懂:算法思想直观,容易理解和实现
  2. 原地排序:只需要常数级别的额外内存空间
  3. 稳定排序:相等元素的相对位置不会改变
  4. 适应性好:对部分有序数据效率很高
  5. 在线算法:可以边接收数据边排序

5.2 缺点

  1. 效率低下:平均时间复杂度为O(n²),不适合大规模数据
  2. 移动频繁:需要大量元素移动操作
  3. 不适合链表:随机访问特性在链表上效率低

5.3 适用场景

  1. 小规模数据:数据量很小(n < 100)时效率高
  2. 部分有序数据:数据基本有序时性能接近O(n)
  3. 稳定排序需求:需要保持相等元素相对顺序
  4. 在线排序:数据逐个到达时需要实时排序

六、插入排序与其他排序算法的比较

6.1 与冒泡排序比较

特性 插入排序 冒泡排序
比较次数 最好n-1,最坏n(n-1)/2 最好n-1,最坏n(n-1)/2
交换/移动次数 最好0,最坏n(n-1)/2 最好0,最坏n(n-1)/2
稳定性 稳定 稳定
适应性 对部分有序数据适应性很强 有一定适应性
实际性能 通常比冒泡排序快 通常较慢

6.2 与选择排序比较

特性 插入排序 选择排序
比较次数 最好n-1,最坏n(n-1)/2 固定n(n-1)/2
移动次数 最好0,最坏n(n-1)/2 最多n-1次交换
稳定性 稳定 不稳定
适应性 对部分有序数据适应性很强 无适应性
实际性能 通常比选择排序快 通常较慢

总结

插入排序是最基础、最直观的排序算法之一,虽然在大规模数据上效率不高,但在特定场景下仍有其价值。

核心要点回顾:

  1. 基本思想:构建有序序列,逐个插入未排序元素
  2. 算法复杂度:最好O(n),最坏O(n²),平均O(n²)
  3. 稳定性:插入排序是稳定排序算法
  4. 适应性:对部分有序数据效率很高
  5. 原地排序:空间复杂度O(1)

算法特点总结:

  1. 简单性:算法思想简单,易于理解和实现
  2. 稳定性:保持相等元素的相对顺序
  3. 适应性:能利用输入数据的已有顺序
  4. 在线性:可以处理动态到达的数据

学习意义:

插入排序不仅是排序算法的基础,也体现了许多高级算法的核心思想。理解插入排序对于学习更复杂的算法(如希尔排序、归并排序)有重要意义。

在实际编程中,虽然对于大规模数据会使用更高效的排序算法,但在小规模数据、部分有序数据或需要稳定排序的场景下,插入排序仍然是合理的选择。

在下一篇中,我们将探讨高级排序算法,包括希尔排序、快速排序和归并排序,这些算法在效率上比基本排序算法有显著提升,适合处理大规模数据。

注意:本文是Python数据结构系列的第十二篇,重点讲解插入排序的基本概念和实现。在实际编程中,应根据具体需求选择合适的排序算法,理解各种算法的特点和适用场景是成为优秀程序员的重要基础。

相关推荐
Prince-Peng4 小时前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
2301_790300964 小时前
Python单元测试(unittest)实战指南
jvm·数据库·python
VCR__4 小时前
python第三次作业
开发语言·python
韩立学长4 小时前
【开题答辩实录分享】以《助农信息发布系统设计与实现》为例进行选题答辩实录分享
python·web
码农水水4 小时前
得物Java面试被问:消息队列的死信队列和重试机制
java·开发语言·jvm·数据结构·机器学习·面试·职场和发展
-Try hard-5 小时前
数据结构:链表常见的操作方法!!
数据结构·算法·链表·vim
2401_838472515 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
u0109272715 小时前
使用Python进行网络设备自动配置
jvm·数据库·python
工程师老罗5 小时前
优化器、反向传播、损失函数之间是什么关系,Pytorch中如何使用和设置?
人工智能·pytorch·python
wengqidaifeng5 小时前
数据结构---顺序表的奥秘(下)
c语言·数据结构·数据库