【算法基础】插入排序算法 - JAVA

一、算法基础

1.1 什么是插入排序

插入排序是一种简单直观的排序算法,它的工作原理类似于我们打牌时整理手牌的过程。插入排序的核心思想是将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入到已排序部分的适当位置。

1.2 插入排序的基本思想

  1. 将第一个元素视为已排序部分
  2. 取出下一个元素,在已排序部分找到合适的插入位置
  3. 将已排序部分中大于该元素的所有元素后移一位
  4. 将该元素插入到正确的位置
  5. 重复步骤2~4,直到所有元素都插入到正确的位置

1.3 时间复杂度

  • 最佳情况:O(n),当数组已经排好序时
  • 最坏情况:O(n²),当数组逆序排列时
  • 平均情况:O(n²)
  • 空间复杂度:O(1),原地排序算法

二、插入排序的实现

2.1 标准实现

java 复制代码
public class InsertionSort {
    public static void sort(int[] arr) {
        int n = arr.length;
        
        // 从第二个元素开始,第一个元素被视为已排序
        for (int i = 1; i < n; i++) {
            // 取出当前元素
            int key = arr[i];
            int j = i - 1;
            
            // 将比key大的元素向后移动
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            
            // 将key插入到正确位置
            arr[j + 1] = key;
        }
    }
}

2.2 优化实现(针对部分有序数组)

java 复制代码
public class OptimizedInsertionSort {
    public static void sort(int[] arr) {
        int n = arr.length;
        
        // 找到第一个逆序位置
        int startIndex = 1;
        for (int i = 0; i < n - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                startIndex = i + 1;
                break;
            }
        }
        
        // 从startIndex开始进行插入排序
        for (int i = startIndex; i < n; i++) {
            int key = arr[i];
            int j = i - 1;
            
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            
            arr[j + 1] = key;
        }
    }
}

2.3 二分查找优化

在插入过程中,可以使用二分查找来加速查找插入位置:

java 复制代码
public class BinaryInsertionSort {
    public static void sort(int[] arr) {
        int n = arr.length;
        
        for (int i = 1; i < n; i++) {
            int key = arr[i];
            
            // 使用二分查找找到插入位置
            int insertPos = binarySearch(arr, 0, i - 1, key);
            
            // 将元素后移
            if (insertPos < i) {
                System.arraycopy(arr, insertPos, arr, insertPos + 1, i - insertPos);
                arr[insertPos] = key;
            }
        }
    }
    
    // 二分查找最小的不小于key的元素位置
    private static int binarySearch(int[] arr, int low, int high, int key) {
        while (low <= high) {
            int mid = low + (high - low) / 2;
            
            if (arr[mid] > key) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        
        return low;
    }
}

三、插入排序的特点分析

3.1 优点

  1. 实现简单:算法逻辑直观,容易理解和实现
  2. 稳定排序:相同元素的相对位置在排序后保持不变
  3. 原地排序:不需要额外空间
  4. 对小规模数据高效:当数据量小时,常数因子小,效率高
  5. 对近乎有序的数据非常高效:接近O(n)时间复杂度
  6. 在线算法:可以一边读取数据一边排序

3.2 缺点

  1. 时间复杂度高:对于大规模数据,O(n²)的时间复杂度较高
  2. 不适合逆序数组:在逆序数组上性能最差
  3. 不适合频繁交换元素的场景:在交换代价高的情况下可能效率低下

四、实际应用示例

4.1 完整示例程序

java 复制代码
public class InsertionSortDemo {
    public static void main(String[] args) {
        // 示例数组
        int[] arr = {12, 11, 13, 5, 6, 7};
        
        System.out.println("原始数组:");
        printArray(arr);
        
        // 执行插入排序
        insertionSort(arr);
        
        System.out.println("排序后数组:");
        printArray(arr);
    }
    
    // 插入排序算法
    public static void insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; i++) {
            int key = arr[i];
            int j = i - 1;
            
            // 将比key大的元素向后移动
            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j--;
            }
            
            // 将key插入到正确位置
            arr[j + 1] = key;
        }
    }
    
    // 打印数组
    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }
}

4.2 排序过程示例

假设我们对数组 [5, 2, 4, 6, 1, 3] 进行插入排序:

  1. 初始状态:**5**, 2, 4, 6, 1, 3(粗体表示已排序部分)
  2. 插入2:**2, 5**, 4, 6, 1, 3(2比5小,所以插入到5前面)
  3. 插入4:**2, 4, 5**, 6, 1, 3(4比5小,比2大,所以插入到位置2)
  4. 插入6:**2, 4, 5, 6**, 1, 3(6比所有已排序元素都大,保持原位)
  5. 插入1:**1, 2, 4, 5, 6**, 3(1比所有已排序元素都小,插入到开始位置)
  6. 插入3:**1, 2, 3, 4, 5, 6**(3比2大,比4小,插入到位置2)

五、总结

插入排序是一种简单但实用的排序算法,尤其在以下场景中表现出色:

  1. 数据规模较小
  2. 数据已经部分有序
  3. 需要稳定排序
  4. 需要在线处理数据

虽然在最坏情况下时间复杂度为O(n²),但其简单性和在特定场景下的优势使其成为实际应用中的重要选择。在标准库中,很多高级排序算法在处理小规模子数组时,会转而使用插入排序,因为此时插入排序的常数因子优势明显。

相关推荐
CarIise4 分钟前
Spring MVC 请求参数绑定与常用注解
java·spring·mvc
Mister Leon4 分钟前
Nvidia Orin AGX实战之从量化到蒸馏:在 Orin 上落地的大模型压缩实战
人工智能·算法·机器学习
aqiu1111116 分钟前
蓝桥杯真题复盘:Fibonacci 数列与黄金分割(C++ 算法详解)
c++·算法·蓝桥杯
phoenix@Capricornus11 分钟前
LDA 协方差矩阵(MATLAB `fitcdiscr`)
算法·matlab·矩阵
青少儿编程课堂15 分钟前
蓝桥杯·全国青少年信息素养大赛·电子学会C/C++考级:拓扑排序课程表排课解析
c++·python·算法·bfs·信息学竞赛
一条泥憨鱼16 分钟前
AI Agent 安全实践:从 MCP 工具调用到 Java 权限校验
java·人工智能·安全
Nebula_g22 分钟前
云禾外卖补充—项目整体后端运行逻辑-对流程的更深层次理解
java·开发语言·网络·数据库·状态模式·javase
萧瑟余晖22 分钟前
Spring Security 6.x新特性与架构演进详解
java·spring·架构
\光辉岁月/28 分钟前
1.Object类
java·面向对象·object类
鸽鸽程序猿40 分钟前
【项目】【在线判题系统】公共功能
java·spring boot·maven