有关于排序算法
本文围绕提供的 Java 排序算法代码,按「基础排序算法」「进阶排序算法」「快速排序算法」三大类,深入剖析每种算法的核心思想、代码逻辑细节、关键设计亮点、时间复杂度、空间复杂度及适用场景。所有讲解均紧密结合代码实现,让理论与实践深度融合。
基础排序算法
基础排序算法通常是入门级实现,核心逻辑简单直观,时间复杂度多为 $O(n^2)$,适用于小规模数据排序。本节包含冒泡排序、选择排序、插入排序及希尔排序(插入排序的优化版)。
冒泡排序
核心思想
通过相邻元素的两两比较与交换,将最大(或最小)的元素逐步“冒泡”到数组的末尾。每一轮遍历都会确定一个未排序区间的最值元素,遍历 n-1 轮后完成排序。代码中加入了 sorted 标志位优化,避免已排序数组的无效遍历。
代码逻辑拆解
1 | public void bubbleSort(int[] nums) { |
- 外层循环控制轮次
- 内层循环比较相邻元素
sorted标志优化:若无交换则提前结束
复杂度与适用场景
- 时间复杂度:最好 $O(n)$,最坏 $O(n²)$
- 空间复杂度:$O(1)$
- 适用场景:小规模数据、接近有序的数组
选择排序
核心思想
每轮从未排序区间找到最小元素,与未排序区间第一个元素交换,逐步扩大已排序区间。
代码逻辑拆解
1 | public void selectionSort(int[] nums) { |
- 每轮只交换一次,减少交换次数
复杂度与适用场景
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 适用场景:小规模数据、交换代价高的场景
插入排序
核心思想
将数组分为已排序和未排序区间,依次将未排序元素插入到已排序区间的正确位置。
代码逻辑拆解
1 | public void insertionSort(int[] nums) { |
- 关键字
key保存当前元素 - 元素后移腾出插入位置
复杂度与适用场景
- 时间复杂度:最好 O(n),最坏 O(n²)
- 空间复杂度:O(1)
- 适用场景:小规模、接近有序的数据
希尔排序
核心思想
插入排序的优化版,通过递减步长分组插入排序,使数组逐步接近有序。
代码逻辑拆解
1 | public static void shellSort(int[] arr) { |
- 步长
gap初始为 n/2,每次减半 - 分组执行插入排序
复杂度与适用场景
- 时间复杂度:O(n^(3/2))
- 空间复杂度:O(1)
- 适用场景:中大规模数据、空间敏感场景
进阶排序算法
归并排序
核心思想
分治思想:将数组递归拆分为两个子数组,排序后再合并。
代码逻辑拆解
1 | public static void mergeSort(int[] arr) { |
- 临时数组
temp避免重复创建 - 合并过程保证稳定性
复杂度与适用场景
- 时间复杂度:O(n log n)
- 空间复杂度:O(n)
- 适用场景:大规模数据、要求稳定排序
快速排序
核心思想
选基准、分区间,递归排序左右子区间。
代码逻辑拆解
1 | public void quickSort(int[] arr) { |
- 双指针分区
- 基准选择可优化(如三数取中)
复杂度与适用场景
- 时间复杂度:平均 O(n log n),最坏 O(n²)
- 空间复杂度:O(log n)
- 适用场景:大规模数据、实际效率高
堆排序
核心思想
构建大顶堆,交换堆顶与堆尾,调整堆。
代码逻辑拆解
1 | public static void heapSort(int[] arr) { |
- 从最后一个非叶子节点开始构建堆
- 下沉调整保证堆性质
复杂度与适用场景
- 时间复杂度:O(n log n)
- 空间复杂度:O(1)
- 适用场景:大规模数据、空间敏感、Top K 问题
线性时间排序算法
计数排序
核心思想
统计元素出现次数,根据计数数组重构有序序列。
不稳定版实现
1 | public void countingSort_unStable(int[] nums) { |
稳定版实现
1 | public void countingSort_stable(int[] nums) { |
复杂度与适用场景
- 时间复杂度:O(n + max)
- 空间复杂度:O(n + max)
- 适用场景:非负整数、取值范围小、需稳定排序
基数排序
核心思想
按位(个位、十位…)进行多轮桶排序。
代码逻辑拆解
1 | public void radixSort(int[] arr) { |
- 低位优先(LSD)
- 使用计数排序作为稳定子排序
复杂度与适用场景
- 时间复杂度:O(d × (n + r))
- 空间复杂度:O(n + r)
- 适用场景:非负整数、位数较少的大规模数据
总结:各排序算法核心特性对比
| 排序算法 | 时间复杂度(平均) | 空间复杂度 | 稳定性 | 核心优势 | 适用场景 |
|---|---|---|---|---|---|
| 冒泡排序 | O(n²) | O(1) | 稳定 | 实现简单 | 小规模、接近有序 |
| 选择排序 | O(n²) | O(1) | 不稳定 | 交换次数少 | 小规模、交换代价高 |
| 插入排序 | O(n²) | O(1) | 稳定 | 接近有序时高效 | 小规模、动态数据 |
| 希尔排序 | O(n^(3/2)) | O(1) | 不稳定 | 优于基础O(n²) | 中大规模数据 |
| 归并排序 | O(n log n) | O(n) | 稳定 | 效率稳定 | 大规模、需稳定 |
| 快速排序 | O(n log n) | O(log n) | 不稳定 | 原地排序、实际快 | 大规模、无稳定性要求 |
| 堆排序 | O(n log n) | O(1) | 不稳定 | 原地、可获最值 | 大规模、空间敏感 |
| 计数排序 | O(n + max) | O(n + max) | 稳定 | 线性时间 | 非负整数、范围小 |
| 基数排序 | O(d×(n+r)) | O(n+r) | 稳定 | 线性时间 | 非负整数、位数少 |