Menu
CoddyTech

冒泡排序

最后更新

冒泡排序反复遍历列表,比较每一对相邻元素,如果顺序不对就交换它们。每完成一整轮,剩余元素中的最大值就会“冒泡”到末尾的正确位置,所以每一轮需要查看的元素都少一个。点击上方的“播放”观察比较和交换的过程,也可以一步一步地执行。

它是最容易理解的排序算法之一,非常适合作为入门的第一个算法,但它 O(n²) 的运行时间让它不适合处理大规模输入。

时间和空间复杂度

情况复杂度说明
最好情况O(n)已经有序,并带有提前退出的检查
平均情况O(n²)随机顺序
最坏情况O(n²)完全逆序
空间O(1)原地排序,只需一个临时变量
稳定性稳定相等的元素保持原有的相对顺序

分步说明

步骤发生了什么
1从数组开头开始。
2把当前元素和下一个元素比较。
3如果顺序不对,就交换它们。
4向右移动一位,重复直到末尾(这是一轮)。
5重复多轮,每一轮都在末尾再确定一个元素。
6当一整轮都没有发生交换时停止。

示例演算

对 [5, 2, 4, 1] 排序:

轮次数组操作
1[2, 4, 1, 5]交换 5,2,再交换 5,4,再交换 5,1;5 冒泡到末尾。
2[2, 1, 4, 5]2,4 顺序正确;交换 4,1;4,5 顺序正确;4 已就位。
3[1, 2, 4, 5]交换 2,1;其余已经有序;2 已就位。
4[1, 2, 4, 5]一整轮没有发生交换,说明数组已经有序,算法结束。

什么时候使用冒泡排序

适合使用的情况不适合使用的情况
教学或学习比较排序的原理对大规模输入排序,O(n²) 太慢了
输入很小或几乎有序(加上提前退出后接近 O(n))需要最快的通用排序,应使用快速排序或归并排序
需要一个稳定、原地、代码量极少的排序数据顺序随机,并且对性能有要求
用一轮检查一个短列表是否已经有序写入代价很高(例如闪存),选择排序的交换次数更少

Bubble Sort 代码

简洁、可运行的 Bubble Sort 实现,提供 Python, JavaScript, Java, C++, C, Pseudocode 版本。选择一种语言,复制代码,或在 Coddy 在线编辑器中直接打开。

Bubble Sort 的 Python 代码

Python
1def bubble_sort(a):2    n = len(a)3    for i in range(n - 1):4        swapped = False5        for j in range(n - 1 - i):6            if a[j] > a[j + 1]:7                a[j], a[j + 1] = a[j + 1], a[j]8                swapped = True9        if not swapped:10            break  # no swaps means the list is already sorted11    return a12
13
14nums = [5, 1, 4, 2, 8]15print("Before:", nums)16bubble_sort(nums)17print("After: ", nums)
在 Python 在线编辑器中运行这段代码

冒泡排序常见问题

冒泡排序的时间复杂度是多少?
由于两层嵌套循环,冒泡排序在平均和最坏情况下的运行时间是 O(n²)。加上提前退出的优化后,在已经有序的数组上可以达到 O(n)。它只占用 O(1) 的额外空间。
冒泡排序是稳定的吗?

是的。冒泡排序只在相邻元素严格逆序时才交换,所以相等的元素永远不会互相越过,会保持原有的相对顺序。

为什么叫冒泡排序?

每一轮中,未排序部分的最大值都会一步步移向数组末尾,就像气泡浮上水面一样,所以叫“冒泡”排序。

冒泡排序和插入排序有什么区别?
两者都是 O(n²)、稳定且原地的排序,但移动数据的方式不同:冒泡排序反复交换相邻的逆序对,而插入排序依次取出每个元素,把它向前移到已排序前缀中的正确位置。插入排序通常写入次数更少,实际运行更快,在几乎有序的数据上尤其明显。
什么时候该用冒泡排序而不是快速排序?
在实际工作中几乎从不。除了极小的输入,快速排序 O(n log n) 的平均时间都远胜冒泡排序的 O(n²)。只有当列表非常小或几乎有序,或者教学时需要最简单的稳定排序时,冒泡排序才值得一用。
提前退出的优化会改变冒泡排序的最坏情况吗?
不会。记录每一轮是否发生了交换,可以让冒泡排序提前停止,在已有序的输入上达到 O(n);但完全逆序的数组仍然需要做完所有比较,所以最坏情况仍是 O(n²)。这个优化只对最好情况和几乎有序的情况有帮助。
Coddy 编程语言插图

在 Coddy 掌握算法

开始