返回算法课程
排序入门

冒泡排序Bubble Sort

反复比较相邻元素,把较大的值一步步推向右端。

18 分钟前置:数组 · 循环 · 元素交换

01先从一个问题出发

把一排身高不同的人从矮到高排列。每次只允许相邻两个人交换位置,该如何保证最终有序?

一个具体的例子

[5, 2, 4, 1] → 比较 5 和 2 后交换 → [2, 5, 4, 1] → 5 一路向右,第一轮结束得到 [2, 4, 1, 5]。

02最直接的办法,为什么慢?

枚举所有排列,检查哪一个升序。

暴力 · O(n · n!)

有 n! 种排列,每个候选还要线性检查。我们完全忽略了局部大小关系。

03一步步,推导出优化思路

1

把全局问题变成局部问题

若数组无相邻逆序对,它就是有序的。因此只需要找到并消除相邻逆序。

2

发现一轮扫描的保证

较大值每次向右移动,完整一轮后,本轮最大值必然到达末尾。

3

缩小工作区间

末尾元素已经就位,下轮少比较一个位置。如果一轮无交换,整段已经有序。

贯穿算法的不变量

每轮结束后,右侧已处理区间有序,且其中所有值不小于左侧未处理区间。

04让每一步,都看得见

试着先预测下一步,再点击「下一步」验证。变量、动画与代码会同步变化。

Bubble Sort交互演示
STEP 01 / 48
35
0
18
1
52
2
27
3
43
4
12
5
60
6
31
7
当前处理已处理 / 已确定未处理
01

从左到右观察数组。橙色表示当前比较,绿色表示已确定的位置。

bubble_sort.py参考实现 · 当前第 2 行
正在载入代码编辑器…

动画展示参考实现的执行轨迹。切换语言时,当前操作会定位到对应代码行。

05复杂度,来自具体的工作量

时间复杂度
O(n2)O(n^2)

最坏比较 (n−1)+(n−2)+…+1 = n(n−1)/2 次。有提前退出时,已排序输入只扫描一轮,为 O(n)。

辅助空间
O(1)O(1)

原地交换只需要临时变量,辅助空间 O(1)。示例为了保留输入复制了数组,所以示例函数总额外空间是 O(n);动画快照另外占用空间。

拖动 n,看看增长速度

06看到什么,应该想到它?

这些特征值得停下来想一想:

关键词只是线索,继续检查适用条件

07这些细节,容易踩坑

01

比较范围越界

访问 j+1 时,j 必须小于本轮 end。

02

稳定性的条件

只在左值严格大于右值时交换;相等元素不交换,保留原来次序。

03

不要用于大规模排序

二次复杂度增长很快,工程中应考虑归并、快速排序或语言标准库。

08把想法带进真实题目

先说出模式和适用条件,再开始写代码。

09不用背模板,回答这几个问题

01第一轮完成后,能保证什么?

02带提前退出的冒泡排序,已排序数组的时间复杂度是?

03为什么比较时使用 > 而不是 ≥?

你已经走完了这次推导。

能用自己的话解释复杂度和不变量,再标记为掌握。

把知识连起来