一句话总结:
冒泡排序就像排队——个子高的同学不断往后冒泡,直到全体从矮到高排好队。优化就是让老师别傻盯着,发现队伍已经整齐就提前放学!
一、基础版冒泡排序(老实人版)
原理:
- 从头开始比较相邻两个同学
- 如果左边比右边高,就交换位置
- 每轮结束,最高的同学冒到最后
- 重复直到全体有序
Kotlin 代码:
fun bubbleSortBasic(arr: IntArray) {
for (i in 0 until arr.size - 1) { // 外层:要排n-1轮
for (j in 0 until arr.size - 1 - i) { // 内层:每轮少比一个(最后的已排好)
if (arr[j] > arr[j + 1]) { // 前一个比后一个大
val temp = arr[j] // 交换位置(矮个前移)
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
}
举个栗子 🌰:
初始数组:[5, 3, 8, 2]
第1轮结束:[3, 5, 2, 8] (8冒到最后)
第2轮结束:[3, 2, 5, 8] (5冒到倒数第二)
第3轮结束:[2, 3, 5, 8] (3冒到位)
缺点:
- 即使数组已经有序,仍然傻乎乎跑完所有轮
- 每轮都要从头比到尾,不管后面是否已排好
二、优化版冒泡排序(聪明版)
优化 1:提前放学(发现无交换就停止)
fun bubbleSortOptimized(arr: IntArray) {
var swapped: Boolean
for (i in 0 until arr.size - 1) {
swapped = false // 每轮开始重置标志
for (j in 0 until arr.size - 1 - i) {
if (arr[j] > arr[j + 1]) {
val temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
swapped = true // 发生交换就标记
}
}
if (!swapped) break // 一轮无交换 → 全体有序 → 收工!
}
}
优化 2:记录最后交换位置(减少无效比较)
fun bubbleSortSuperOptimized(arr: IntArray) {
var lastSwapIndex = arr.size - 1
var currentSwapIndex: Int
repeat(arr.size) { // 最多还是n轮
currentSwapIndex = -1 // 初始化
for (j in 0 until lastSwapIndex) {
if (arr[j] > arr[j + 1]) {
val temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
currentSwapIndex = j // 记录最后一次交换的位置
}
}
if (currentSwapIndex == -1) break // 无交换直接结束
lastSwapIndex = currentSwapIndex // 下一轮只比到这里
}
}
优化效果:
- 如果数组已经有序 → 只跑一轮(时间复杂度从O(n²) → O(n))
- 后半段已排好 → 后面不再比较(减少内层循环次数)
三、性能对比(假设数组长度n)
| 情况 | 基础版 | 优化版1 | 优化版2 |
|---|---|---|---|
| 完全逆序 | O(n²) | O(n²) | O(n²) |
| 完全有序 | O(n²) | O(n) | O(n) |
| 部分有序 | O(n²) | 介于O(n)-O(n²) | 更接近O(n) |
四、使用场景
-
优点:
- 代码简单,适合教学
- 对小规模数据或接近有序的数据表现不错
-
缺点:
- 大规模数据效率低(时间复杂度硬伤)
- 实际开发中更常用快速排序、归并排序
举个真实场景:
- 手机通讯录里100个联系人按名字排序 → 可以用
- 给10万个用户ID排序 → 快跑,别用冒泡!
五、终极口诀
冒泡排序两重天,
优化只需两板斧:
一轮无交换,提前收工;
记录最后位,少做白工!
简单场景用它行,
海量数据请绕道。