冒泡排序:从基础实现到供应链任务排序

冒泡排序是一种基础排序算法。它通过相邻元素两两比较,把较大的元素逐步交换到数组末尾。实际项目里很少直接使用冒泡排序处理大数据量,但它适合用来理解排序的基本思想、稳定性、时间复杂度和提前终止优化。

整体流程

冒泡排序流程

基础实现

假设有一组仓库拣货任务,需要按优先级从小到大排序:

1
int[] priorities = {8, 3, 2, 6, 7, 9};

冒泡排序实现:

1
2
3
4
5
6
7
8
9
10
11
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

每一轮结束后,当前未排序区间中的最大值会被交换到末尾。因此内层循环的边界是 arr.length - i - 1

提前终止优化

如果某一轮没有发生交换,说明数组已经有序,可以提前结束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void bubbleSortWithBreak(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
boolean swapped = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) {
break;
}
}
}

这个优化对“基本有序”的数据有明显收益。例如仓库任务列表已经按创建时间大致排好,只是少量紧急任务插入,提前终止可以减少无效比较。

边界条件与测试

排序算法最容易出错的地方不是核心循环,而是边界条件。至少要覆盖空数组、单元素数组、已经有序、完全逆序、存在重复值这几类输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
int[][] cases = {
{},
{1},
{1, 2, 3},
{5, 4, 3, 2, 1},
{3, 1, 3, 2}
};

for (int[] item : cases) {
bubbleSortWithBreak(item);
System.out.println(Arrays.toString(item));
}
}

在供应链任务排序里,重复值尤其常见。比如两个拣货任务优先级相同,或者两个订单承诺发货时间一致。冒泡排序在只使用 > 交换时是稳定的,相同优先级任务不会改变原有顺序。这一点可以帮助我们理解“稳定排序”为什么对业务有意义:同优先级时保留创建顺序,能减少人工理解成本。

供应链业务例子

假设 WMS 中有少量待处理任务,需要在内存中按优先级排序:

1
2
3
4
5
public class PickTask {
private String taskNo;
private int priority;
private LocalDateTime createdAt;
}

如果任务数量只有十几个,冒泡排序可以作为教学示例理解排序过程。但在真实系统中,不建议自己手写冒泡排序处理任务列表,应该优先使用 JDK 提供的排序:

1
2
3
tasks.sort(Comparator
.comparingInt(PickTask::getPriority)
.thenComparing(PickTask::getCreatedAt));

业务代码更应该关注排序规则是否正确:优先级、创建时间、仓库、波次、客户等级等字段的优先顺序。

生产系统里怎么选择排序方式

生产系统通常不应该把大量数据查到 JVM 里再排序。供应链系统的数据规模很容易放大:订单可能是几十万级,库存流水可能是千万级,仓库任务在促销期间也会快速增长。

更常见的选择是:

  1. 数据库排序:适合按索引字段分页查询,例如 created_atprioritystatus
  2. 搜索引擎排序:适合复杂筛选和全文检索,例如订单号、客户名称、商品名称组合查询。
  3. JDK 内置排序:适合已经筛选出的小批量候选集,例如 100 条待分配任务做二次排序。
  4. 手写排序:主要用于学习、面试和解释算法过程,不建议作为业务主实现。

也就是说,冒泡排序的工程价值在于训练基本功,而不是替代成熟排序能力。真正写业务代码时,要先判断数据量、排序字段、分页方式和索引条件。

复杂度和稳定性

冒泡排序特点:

  1. 最好时间复杂度:O(n),前提是加了提前终止且数据已经有序。
  2. 平均和最坏时间复杂度:O(n^2)
  3. 空间复杂度:O(1)
  4. 稳定性:稳定。相等元素不会因为 > 比较而交换相对顺序。

稳定性在业务里有意义。例如两个拣货任务优先级相同,稳定排序可以保留原来的创建顺序。

小结

冒泡排序适合理解排序思想,不适合大规模生产数据。供应链系统里的订单、库存、任务、流水通常数量很大,生产代码应该使用数据库排序、索引排序或 JDK 内置排序。学习冒泡排序的重点,是理解相邻比较、边界缩小、提前终止和稳定性。