最经典的排序算法,通过相邻元素两两比较,让大数逐步后移、小数逐步前移,如同水中气泡上浮。
冒泡排序(Bubble Sort)是中职阶段最常用、考查频率最高的排序算法。因其排序过程如同水中气泡上浮,大数逐步向后漂浮、小数逐步向前漂浮,故而得名冒泡排序。
对无序数组进行多轮遍历,每一轮都相邻两个元素两两对比,如果两个元素不满足排序规则(升序:前大后小需交换;降序:前小后大需交换),就交换两个元素的位置。
相邻元素中,前一个数 > 后一个数 → 交换位置。每一轮排序结束后,当前未排序区间的最大值会"沉"到末尾。
作用:控制排序总轮次
n 个元素的数组,最多需要 n-1 轮排序。因为每一轮至少确定一个元素的最终位置,n-1 轮后剩下的那个元素自然有序。
作用:控制每一轮的相邻对比次数
每完成一轮,末尾已有序元素增加一个,因此对比次数逐轮减少。第 i 轮对比次数为 n-1-i。
冒泡排序的核心操作只有两个——比较和交换。下面通过动态图结合代码,直观理解这两个关键节点:
下面通过完整的动画演示,一步步展示数组 int[] arr = { 9, 5, 1, 4, 3 } 的冒泡排序全过程。左侧是数组动画,右侧是同步高亮的 C# 代码,帮助你将算法逻辑与代码行一一对应。
流程图是理解算法逻辑的重要工具。下面是冒泡排序(升序)的完整流程图,帮助你梳理从开始到结束的每一步判断和操作:
看流程图要抓住三个关键:外层循环条件(轮次)、内层循环条件(每轮对比次数)、判断交换条件(升序用 >,降序用 <)。这三个点也是高考选择题和程序填空题的高频考点。
本工具支持 C# 代码的在线编辑、运行和调试。你可以直接修改代码,点击"运行"按钮查看输出结果。如果代码有错误,系统会自动检测并提示错误信息,帮助你定位问题。
下面提供两道练习题,请结合上面的在线调试工具完成。做完后可以运行代码验证答案是否正确。
1using System; 2class Program 3{ 4 static void Main() 5 { 6 int[] arr = { 9, 5, 1, 4, 3 }; 7 int len = arr.Length; 8 9 // 错误1:外层循环条件错误 10 for (int i = 0; i < len; i++) // 错! 11 { 12 // 错误2:内层循环条件错误 13 for (int j = 0; j < len - i; j++) // 错! 14 { 15 // 错误3:判断条件方向反了 16 if (arr[j] < arr[j + 1]) // 错! 17 { 18 int temp = arr[j]; 19 arr[j] = arr[j + 1]; 20 arr[j + 1] = temp; 21 } 22 } 23 } 24 25 Console.WriteLine("排序结果:"); 26 foreach (int item in arr) 27 Console.Write(item + " "); 28 } 29}
1using System; 2class Program 3{ 4 static void Main() 5 { 6 int[] arr = { 9, 5, 1, 4, 3 }; 7 int len = arr.Length; 8 int temp; 9 10 for (int i = 0; i < 空1; i++) 11 { 12 for (int j = 0; j < 空2; j++) 13 { 14 if (arr[j] 空3 arr[j + 1]) // 降序判断 15 { 16 temp = 空4; 17 arr[j] = arr[j + 1]; 18 arr[j + 1] = temp; 19 } 20 } 21 } 22 23 Console.WriteLine("降序排序结果:"); 24 foreach (int item in arr) 25 Console.Write(item + " "); 26 } 27}
j < len-1-i,每轮少比一次。>,降序用 <。| 复杂度类型 | 情况分类 | 结果 | 详细说明 |
|---|---|---|---|
| 时间复杂度 | 最差情况(完全逆序) | O(n²) |
每一轮都需要全部对比 + 大量交换操作 |
| 最优情况(已有序) | O(n²) |
普通冒泡无有序优化,依然完整执行双层循环 | |
| 平均情况 | O(n²) |
中职考题统一记忆标准,都是平方级 | |
| 空间复杂度 | 所有情况 | O(1) |
仅使用 1 个临时交换变量 temp,属于原地排序,不占用额外数组空间 |
| 稳定性 | 稳定排序 | — | 相等元素不会交换位置,相对顺序保持不变 |
很多同学会误以为"数组已经有序时冒泡排序只需要O(n)"——不对!那是经过"标记优化"的冒泡排序。普通标准版冒泡排序无论数组是否有序,都会完整执行 n-1 轮,因此最优时间复杂度仍然是 O(n²)。考试时题目说"冒泡排序"默认指标准版,不考虑优化版本。
i < len - 1。n 个元素只需要 n-1 轮。如果写 len,会多循环一轮,虽然结果可能没错(因为内层循环会变成 0 次),但概念上是错误的,考试会扣分。
j < len - 1 - i。因为每次比较的是 j 和 j+1,如果 j 到 len-1,j+1 就越界了!末尾少写一个 -1 会导致"索引超出数组界限"的运行时错误。
arr[j] > arr[j+1](大的往后走),降序用 arr[j] < arr[j+1](小的往后走)。记忆技巧:想让哪边的数"冒"到末尾,就用相反的符号——升序让大数冒到末尾,所以用大于号。
temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp;。常见错误是把第一步写成 arr[j] = arr[j+1],这样 arr[j] 的原始值就丢失了,交换就失败了。一定要先用 temp 保存!
外层:for(i=0; i<n-1; i++) —— 轮次 = 元素数 - 1
内层:for(j=0; j<n-1-i; j++) —— 每轮对比数 = 总数 - 1 - 已排好的轮次
判断:if(arr[j] > arr[j+1]) —— 升序大于才交换(降序小于才交换)
for (int i = 0; i < len - 1; i++) — 控制轮次for (int j = 0; j < len - 1 - i; j++) — 控制每轮对比>,降序用 <,交换用三行 temp 模板