简单排序 · 冒泡
冒泡排序 图解题解
这道题到底在问什么
给定一个数组,把它从小到大排好序。冒泡排序:每一趟从左到右扫一遍,相邻两个一比,左边比右边大就交换,这样一趟下来最大的那个会被「顶」到最右边。重复若干趟,直到整个数组有序。
- 输入
- nums = [5,2,4,1,3]
- 输出
- [1,2,3,4,5]
最优解:一步一步想明白
- 3记住两件事:一是相邻比较、大的右移;二是每趟结束都会有一格被锁定在它的最终位置。下面绿色就是已经锁定、排好的格子。
- 4第 1 趟开始。绿色那 0 格是前几趟已经锁定排好的,这一趟只在下标 0 到 4 之间相邻比较。
- 5比相邻的两根:下标 0 是 5,下标 1 是 2。左边 5 比右边 2 大,要交换。
- 65 比 2 大,两根换位:现在下标 0 是 2,下标 1 是 5。大的那根又往右挪了一步。
- 7比相邻的两根:下标 1 是 5,下标 2 是 4。左边 5 比右边 4 大,要交换。
- 85 比 4 大,两根换位:现在下标 1 是 4,下标 2 是 5。大的那根又往右挪了一步。
- 9比相邻的两根:下标 2 是 5,下标 3 是 1。左边 5 比右边 1 大,要交换。
- 105 比 1 大,两根换位:现在下标 2 是 1,下标 3 是 5。大的那根又往右挪了一步。
- 11比相邻的两根:下标 3 是 5,下标 4 是 3。左边 5 比右边 3 大,要交换。
- 125 比 3 大,两根换位:现在下标 3 是 3,下标 4 是 5。大的那根又往右挪了一步。
- 13第 1 趟跑完,本趟最大的 5 已经浮到下标 4,这一格锁定(变绿),以后不再参与比较。
- 14第 2 趟开始。绿色那 1 格是前几趟已经锁定排好的,这一趟只在下标 0 到 3 之间相邻比较。
- 15比相邻的两根:下标 0 是 2,下标 1 是 4。左边 2 不比右边 4 大,不用换。
- 162 没比 4 大,顺序本来就对,这两根不动,继续往右比下一对。
- 17比相邻的两根:下标 1 是 4,下标 2 是 1。左边 4 比右边 1 大,要交换。
- 184 比 1 大,两根换位:现在下标 1 是 1,下标 2 是 4。大的那根又往右挪了一步。
- 19比相邻的两根:下标 2 是 4,下标 3 是 3。左边 4 比右边 3 大,要交换。
- 204 比 3 大,两根换位:现在下标 2 是 3,下标 3 是 4。大的那根又往右挪了一步。
- 21第 2 趟跑完,本趟最大的 4 已经浮到下标 3,这一格锁定(变绿),以后不再参与比较。
- 22第 3 趟开始。绿色那 2 格是前几趟已经锁定排好的,这一趟只在下标 0 到 2 之间相邻比较。
- 23比相邻的两根:下标 0 是 2,下标 1 是 1。左边 2 比右边 1 大,要交换。
- 242 比 1 大,两根换位:现在下标 0 是 1,下标 1 是 2。大的那根又往右挪了一步。
- 25比相邻的两根:下标 1 是 2,下标 2 是 3。左边 2 不比右边 3 大,不用换。
- 262 没比 3 大,顺序本来就对,这两根不动,继续往右比下一对。
- 27第 3 趟跑完,本趟最大的 3 已经浮到下标 2,这一格锁定(变绿),以后不再参与比较。
- 28第 4 趟开始。绿色那 3 格是前几趟已经锁定排好的,这一趟只在下标 0 到 1 之间相邻比较。
- 29比相邻的两根:下标 0 是 1,下标 1 是 2。左边 1 不比右边 2 大,不用换。
- 301 没比 2 大,顺序本来就对,这两根不动,继续往右比下一对。
- 31第 4 趟跑完,本趟最大的 2 已经浮到下标 1,这一格锁定(变绿),以后不再参与比较。
- 32当右边都锁定后,剩下最左边那格自然也就到位了。整排柱子从矮到高排好:[1,2,3,4,5]。
⚠️ 容易写错的地方
✗ 错:内层每趟都从头比到尾
✓ 对:内层范围用 n-1-i,跳过已锁定的右段
每趟末尾已有一格排好,再去比它纯属浪费
✗ 错:用 < 比较导致不稳定或排成倒序
✓ 对:判断条件用 a[j] > a[j+1] 才换
相等不交换才能保持稳定;用错符号会排成从大到小
✗ 错:数组已经有序时还白跑满 n-1 趟
✓ 对:加 swapped 标记,一趟没换就 break
对接近有序的数据能把最好情况优化到 O(n)
完整代码(Python / C++ / Java)
Python
def bubble_sort(nums):
n = len(nums)
for i in range(n - 1): # 最多跑 n-1 趟
swapped = False
for j in range(n - 1 - i): # 已锁定的右段不再比
if nums[j] > nums[j + 1]: # 左大于右就交换
nums[j], nums[j + 1] = nums[j + 1], nums[j]
swapped = True
if not swapped: # 一趟没换过=已有序
break
return numsC++
void bubbleSort(vector<int>& a) {
int n = a.size();
for (int i = 0; i < n - 1; i++) {
bool swapped = false;
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
swap(a[j], a[j + 1]);
swapped = true;
}
}
if (!swapped) break;
}
}Java
void bubbleSort(int[] a) {
int n = a.length;
for (int i = 0; i < n - 1; i++) {
boolean swapped = false;
for (int j = 0; j < n - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
swapped = true;
}
}
if (!swapped) break;
}
}复杂度
时间
O(n²)
最坏要跑 n-1 趟,每趟比较接近 n 次,相乘是平方级
空间
O(1)
只在原数组里两两交换,不开额外数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 冒泡排序 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
冒泡排序是稳定排序吗?+
是稳定的。只有当左边严格大于右边(a[j] > a[j+1])时才交换,相等的两个元素不会换位,所以相同值的相对顺序保持不变。
最好情况和最坏情况的时间复杂度分别是多少?+
最坏(完全倒序)是 O(n²);最好(已经有序)若加了 swapped 提前退出,只跑一趟没有交换就结束,是 O(n)。不加优化则恒为 O(n²)。
冒泡排序和选择排序的区别?+
都是 O(n²),但冒泡靠相邻交换、是稳定的且能提前终止;选择排序每趟找最小直接放到位、交换次数更少但不稳定。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 冒泡排序 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。