冒泡排序外层循环应为i从0到n-2(共n-1轮),内层循环j从0到n-2-i;因每轮后最大元素归位,后续轮次无需比较已排序部分,避免越界和冗余。

冒泡排序的正确循环边界怎么写
很多初学者写的冒泡排序跑不通,核心问题出在内外层循环的终止条件上。外层控制轮数,内层控制每轮比较范围,不收缩会导致越界或重复比较。
- 外层循环
i从0到n-1(共n轮),但其实只需n-1轮:最后一轮只剩一个元素,无需比较 → 应设为i - 内层循环
j每轮都要缩小范围:第i轮后,末尾i+1个元素已就位,所以j最大只能到n - 2 - i(保证arr[j+1]合法) - 常见错误是写成
j 或 <code>j 固定值,一跑就 <code>std::out_of_range或结果错乱
如何提前退出优化性能
冒泡排序最怕“明明排好了还硬跑完”。原生实现没检测机制,O(n²) 成定式;加个标志位就能在最好情况下降到 O(n)。
- 每轮开始前设
bool swapped = false - 只要发生一次
swap(arr[j], arr[j+1]),就把swapped置为true - 该轮结束若
swapped == false,直接break外层循环 - 注意:这个优化对随机数据效果有限,但对近乎有序的输入(比如日志按时间追加后微调)非常实用
用 std::vector 还是裸数组传参
用裸数组(int arr[])传参会退化成指针,丢失长度信息;而 std::vector 自带 .size(),更安全也更现代。
- 函数签名推荐:
void bubble_sort(std::vector<int>& arr)</int>—— 引用避免拷贝,可原地修改 - 如果非要用数组,必须额外传长度:
void bubble_sort(int arr[], int n),且调用时得手动算sizeof(arr)/sizeof(arr[0]),极易出错 -
std::vector在 C++11 后已是基础工具,别为省几行代码倒退到 C 风格
为什么交换不用 std::swap 就容易翻车
手写临时变量交换看似简单,但遇到自定义类型、移动语义或异常安全场景,自己写的三行交换可能崩得悄无声息。
立即学习“C++免费学习笔记(深入)”;
- 原始写法:
int tmp = a; a = b; b = tmp;—— 对int没问题,但对std::string或大对象,效率低且不支持移动 - 正确做法:无条件用
std::swap(a, b),它会自动选择最优路径(拷贝 or 移动) - 如果类自己实现了
swap成员函数,std::swap会优先调用它(ADL 查找),这是标准库设计的底层保障 - 漏掉
#include <utility>会导致编译失败,错误信息常是‘swap’ is not a member of ‘std’
边界收缩、提前退出、容器选择、交换方式——这四个点卡住的人最多。写一遍能跑不等于写对了,尤其当输入换成 std::vector<std::string> 或加了 -O2 编译后,某些“侥幸通过”的写法会立刻暴露。










