插入排序的实现思路

简介: 插入排序是一种简单直观的排序算法,通过将每个元素插入已排序序列的合适位置实现排序。具有简单高效、稳定、空间复杂度低等优点,适用于小规模或接近有序的数据排序。

插入排序(Insertion Sort)是一种简单直观的排序算法,其核心思想是将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到已排序部分的适当位置,直到整个数组有序。以下是详细的实现思路和示例说明:

基本原理

  1. 数组分区:将数组视为两部分:左侧为已排序部分,右侧为未排序部分。初始时,已排序部分仅包含第一个元素。
  2. 遍历未排序部分:从第二个元素开始,逐个取出未排序部分的元素。
  3. 插入操作:将取出的元素与已排序部分的元素从后向前比较,找到合适的位置插入,确保已排序部分始终有序。
  4. 重复步骤2-3:直到未排序部分的所有元素都插入到已排序部分。

实现步骤

  1. 初始化:将数组的第一个元素视为已排序部分(长度为1)。
  2. 遍历未排序元素:从第二个元素(索引 i=1)开始,遍历到最后一个元素(索引 i=n-1)。
  3. 保存当前元素:将当前元素 arr[i] 保存到临时变量 key
  4. 寻找插入位置:从已排序部分的末尾(索引 j=i-1)开始向前比较,将大于 key 的元素后移一位,直到找到第一个不大于 key 的位置。
  5. 插入元素:将 key 插入到该位置。

示例演示

假设我们要对数组 [5, 3, 8, 4, 6] 进行升序排序:

  1. 初始状态[5 | 3, 8, 4, 6](竖线左侧为已排序部分)
  2. 处理 3
    • 已排序部分:[5]
    • 未排序部分:[3, 8, 4, 6]
    • 取出 3,与 5 比较,5 > 3,将 5 后移,插入 3
    • 结果:[3, 5 | 8, 4, 6]
  3. 处理 8
    • 已排序部分:[3, 5]
    • 未排序部分:[8, 4, 6]
    • 取出 8,与 5 比较,5 < 8,直接插入。
    • 结果:[3, 5, 8 | 4, 6]
  4. 处理 4
    • 已排序部分:[3, 5, 8]
    • 未排序部分:[4, 6]
    • 取出 4,与 85 比较,后移 85,插入 4
    • 结果:[3, 4, 5, 8 | 6]
  5. 处理 6
    • 已排序部分:[3, 4, 5, 8]
    • 未排序部分:[6]
    • 取出 6,与 85 比较,后移 8,插入 6
    • 最终结果:[3, 4, 5, 6, 8]

代码实现

以下是插入排序的Python实现:

def insertion_sort(arr):
    for i in range(1, len(arr)):
        key = arr[i]  # 当前要插入的元素
        j = i - 1     # 已排序部分的最后一个元素索引

        # 将大于key的元素后移
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1

        # 插入key
        arr[j + 1] = key

    return arr

# 测试
arr = [5, 3, 8, 4, 6]
print("排序前:", arr)
print("排序后:", insertion_sort(arr))

复杂度分析

  • 时间复杂度
    • 最好情况:数组已经有序,只需遍历一次,时间复杂度为 $O(n)$。
    • 最坏情况:数组完全逆序,每次插入都需移动所有已排序元素,时间复杂度为 $O(n^2)$。
    • 平均情况:时间复杂度为 $O(n^2)$。
  • 空间复杂度:$O(1)$(原地排序,只需要常数级额外空间)。
  • 稳定性:插入排序是稳定的,因为相等元素不会被交换位置。

适用场景

  • 小规模数据:插入排序在数据量较小时效率较高。
  • 接近有序的数据:如果数组接近有序,插入排序的时间复杂度接近 $O(n)$。
  • 在线排序:可以在接收数据的同时进行排序(每次插入一个新元素)。

优化思路

  • 二分插入排序:使用二分查找来减少比较次数,将时间复杂度优化到 $O(n \log n)$(比较操作),但移动操作仍需 $O(n^2)$。
  • 希尔排序:通过分组插入的方式,进一步提高效率(时间复杂度可优化到 $O(n^{1.3})$)。

插入排序虽然在大数据集上效率不高,但因其简单易实现、空间效率高和稳定性,在特定场景下仍有应用价值。

目录
相关文章
|
5月前
|
缓存 Java
对比 synchronized 和 volatile
`synchronized` 和 `volatile` 是 Java 并发编程中的两个关键机制,各有侧重。`synchronized` 用于实现线程的互斥访问,保证原子性、可见性和有序性,适用于需要锁的场景;而 `volatile` 更轻量,仅确保变量的可见性和有序性,适用于状态标志等无需复合操作的场景。两者可互补使用,如双重检查单例中结合二者优势。合理选择有助于提升并发性能与代码安全性。
249 0
|
传感器 人工智能 监控
无人驾驶拖拉机
无人驾驶拖拉机
860 1
|
5月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
995 0
|
5月前
|
存储 弹性计算 数据挖掘
阿里云2核4G5M带宽199元云服务器测评:价格、性能、适用场景与续费优势详解
阿里云目前活动中推出的“2核4G5M带宽199元1年”云服务器,是当下深受初创企业用户喜爱的云服务器。本文将从价格优势、性能优势和续费优势等几个方面,详细解析这款阿里云199元云服务器的各项特点,帮助大家更好地了解这款云服务器的性能和应用场景,以供选择参考。
|
5月前
|
存储 Java 容器
偏向锁
偏向锁是JVM为提升单线程环境下锁性能而引入的优化机制。其核心思想是将锁偏向首个获取它的线程,避免无竞争时的同步开销,从而提高执行效率。适用于锁由同一线程多次获取、无并发竞争的场景。一旦出现多线程竞争,偏向锁会撤销并升级为更高级别的锁。合理使用可显著提升性能,但在高并发环境下需谨慎配置。
121 0
|
5月前
|
存储 安全 Java
synchronized 锁升级
JDK 6 引入的 synchronized 锁升级机制,通过偏向锁、轻量级锁和重量级锁的动态切换,优化了多线程同步性能。该机制根据竞争情况逐步升级锁状态,减少线程阻塞和系统调用开销,从而提升并发效率。
227 0
|
5月前
|
数据安全/隐私保护
解释对称加密、非对称加密、哈希摘要
加密技术分为对称加密与非对称加密。对称加密使用同一密钥进行加解密,速度快但需严保管密钥;非对称加密则用公钥加密、私钥解密,安全性高但速度较慢。哈希摘要用于验证数据完整性,代表原始数据特征。
171 0
|
5月前
|
Java Spring
聊聊你对SpringBoot框架的理解 ?
SpringBoot是Spring家族中流行的子项目,旨在简化Spring框架开发的繁琐配置。它主要提供三大功能:starter起步依赖简化依赖管理,自动配置根据条件创建Bean,以及内嵌Web服务器支持Jar包运行,极大提升了开发效率。
176 0
|
5月前
|
缓存 Java
自旋锁
自旋锁是一种轻量级同步机制,适用于多线程环境。其核心思想是线程在获取锁失败时不阻塞,而是通过忙等待(自旋)不断尝试获取锁,从而避免上下文切换的开销。常见实现依赖CAS原子操作,适用于锁持有时间短、并发度高的场景,如计数器更新或缓存操作。但长时间自旋会浪费CPU资源,因此更适合多核环境下使用。Java中可通过`AtomicBoolean`实现简单自旋锁,JVM也对其进行了自适应优化。合理使用可提升性能,但需注意控制自旋时间和竞争粒度。
204 0
|
5月前
|
消息中间件 缓存 NoSQL
如何解决缓存雪崩?
缓存雪崩是指大量缓存同时失效,导致请求直接冲击数据库,可能引发系统崩溃。其核心解决思路是**避免缓存集中失效或服务不可用**,并通过多层防护机制降低数据库压力。主要措施包括:为缓存key设置**随机过期时间**、按业务分组设置不同过期策略、对热点数据设置**永不过期**;通过**缓存集群部署**提升服务可用性;在数据库层进行**限流、读写分离和扩容**;并结合**本地缓存、熔断降级、缓存预热、持久化恢复**等手段,构建多级防护体系,确保系统稳定运行。
187 0

热门文章

最新文章