Java 冒泡排序:最简单的排序,没有之一
Java 冒泡排序:最简单的排序,没有之一
面试官让手写排序?掏出冒泡,至少能及格
引言
冒泡排序(Bubble Sort)是所有排序里最像”废话文学”的那个——原理简单到不用脑子:大的往后冒,小的往前浮,一趟一趟比,直到整个数组有序。
但别因为它简单就轻视——冒泡写不对的人,比写对的人多。尤其是两层循环的边界 + 提前终止优化,能筛掉一半”背代码党”。
这篇文章,我会把冒泡拆到不能再拆:
- 用 ASCII 图演示每一趟的真实变化
- 推导为什么最优情况是 O(n) 而不是 O(n²)
- 列出 5 个高频易错点(不是 3 个)
- 配套 LeetCode 真题 912 和 冒泡变形题
读完这篇,冒泡排序的所有面试坑,你都能避开。
1. 核心思想:像水泡一样往上浮
冒泡的精髓用一句话讲:每趟把当前未排序部分的最大元素”冒”到末尾。
1.1 通俗理解
想象一排水泡,最重的水泡往下沉,最轻的往上浮。但冒泡排序反过来——大的往后走,因为大的元素通过相邻交换会逐渐移动到最右端。
1.2 ASCII 图解演示
以数组 [5, 2, 8, 4, 7] 为例,看完整排序过程:
1 | |
1.3 三个关键观察
- 每趟结束后,末尾的元素一定是有序的——最大的已经”沉底”了
- 第 i 趟只需要比较到 n-1-i——因为后面 i 个已经排好
- 如果某趟没有发生任何交换,说明数组已经有序——可以提前终止(这就是最优 O(n) 的来源)
2. 完整 Java 实现
1 | |
3. 复杂度证明(不是只背结论)
3.1 时间复杂度
最坏情况(O(n²)):数组完全逆序
- 第 1 趟需要 n-1 次比较
- 第 2 趟需要 n-2 次比较
- …
- 第 n-1 趟需要 1 次比较
- 总比较次数 = (n-1) + (n-2) + … + 1 = n(n-1)/2 = O(n²)
最好情况(O(n)):数组已经有序
- 第 1 趟遍历一次,发现没有交换 → swapped = false → break
- 只跑了 1 趟,总比较次数 = n-1 = O(n)
平均情况(O(n²)):
- 数组随机分布,期望需要约 n²/4 次比较
- 仍是 O(n²) 量级
3.2 空间复杂度
- 只使用了常数个额外变量(i, j, swapped, temp)
- **O(1)**,原地排序
3.3 稳定性
- 比较条件是
arr[j] > arr[j + 1](严格大于,没有等号) - 相同元素不会交换
- 稳定排序
4. 五个高频易错点(面试必看)
易错点 1:外层循环写 i < n
1 | |
原理:n 个元素只需要 n-1 次就能排好(第 n 趟只剩 1 个元素,无需再排)。
易错点 2:内层循环忘记减 i
1 | |
易错点 3:忘记加 swapped 标志
1 | |
易错点 4:比较条件写成 >=
1 | |
易错点 5:用 i + 1 取数组越界
1 | |
5. 适用场景与禁区
5.1 适用场景
- 数据量极小(n < 100):冒泡虽然慢,但代码简单,常数小
- 基本有序的数组:配合 swapped 优化,O(n) 跑完
- 教学演示:理解排序的最直观入门
- 嵌入式系统:对稳定性有要求且内存极小时
5.2 不适用场景
- 大数据量(n > 1000):O(n²) 跑不动
- 生产环境排序:直接用
Arrays.sort()或Collections.sort() - 对性能敏感的实时系统:选择快排或堆排
6. 面试常见变形(附解题思路)
变形 1:鸡尾酒排序(双向冒泡)
思路:从左到右冒大 + 从右到左冒小交替进行
1 | |
优点:对基本有序的数组比单向冒泡更高效。
变形 2:冒泡找第 k 大元素
思路:只跑 k 趟冒泡,第 k 趟结束后,末尾第 k 个就是第 k 大
1 | |
适用:k 较小时(k < n/2),比全排序后取第 k 位更省时间。
变形 3:奇偶排序(适合并行)
思路:分奇数位和偶数位两轮交替比较
1 | |
优点:两轮独立,可并行处理(GPU 排序常用)。
7. LeetCode 真题实战
题目 1:912. 排序数组(中等)
描述:给你一个整数数组 nums,请你将该数组升序排列。
冒泡解法:直接套用上面的 bubbleSort 模板。
复杂度分析:
- 时间 O(n²),空间 O(1)
- 在 LeetCode 上 n=50000,冒泡会超时(只能过部分测试用例)
实战建议:这道题冒泡能写对边界条件就算过关,但提交时用快排或堆排才能 AC。
题目 2:剑指 Offer 45. 把数组排成最小的数
这道题不用冒泡,但可以用冒泡的”交换”思想:
- 自定义比较器:
"3" + "12"vs"12" + "3"→ 前者小 - 然后用任意稳定排序(冒泡也行)即可
总结
一句话精髓
冒泡 = 相邻比较 + 大的往后 + 提前终止。
三个关键洞察
- 最优 O(n) 是靠 swapped 标志换来的,没这个标志永远是 O(n²)
- 稳定排序靠的是严格大于号
>,不是>= - 工程上几乎不用,但面试会考(考的是细节掌握)
下一步行动
- 把上面 5 个易错点逐个手写一遍,确保每个都不会错
- 尝试用冒泡解 LeetCode 912,看看到第几个测试用例超时
- 鸡尾酒排序手写一遍,对比单向冒泡的差异