冒泡排序核心是外层控制n-1轮遍历,内层相邻比较交换;推荐vector引用传参;加swapped标记可优化至O(n);实际开发应优先使用std::sort。

冒泡排序的核心逻辑怎么写
冒泡排序本质是重复遍历数组,每次比较相邻两个元素,把较大(升序)的“浮”到末尾。关键不是背代码,而是理解每轮 for 循环的作用:外层控制轮数(最多 n-1 轮),内层做相邻比较和交换。
常见错误是内层循环边界写成 i ,导致越界或重复比较。正确写法是让内层上限随轮数递减:<code>j ,因为每轮后末尾 <code>i+1 个位置已有序。
示例片段:
for (int i = 0; i < n - 1; ++i) {
for (int j = 0; j < n - i - 1; ++j) {
if (arr[j] > arr[j + 1]) {
std::swap(arr[j], arr[j + 1]);
}
}
}用 std::vector 还是原始数组传参
用 std::vector 更安全、更符合现代 C++ 习惯,避免手动传数组长度;但要注意传参方式——必须传引用(std::vector<int>&),否则函数内修改不生效。
立即学习“C++免费学习笔记(深入)”;
原始数组(如 int arr[])无法直接获知长度,除非额外传 size_t n,或者用模板推导(template<size_t N> void bubble_sort(int (&arr)[N])),但后者只适用于栈上定义的定长数组。
推荐做法:
- 日常开发优先用
std::vector<int>& - 算法题中若给定 C 风格数组,老老实实加一个
size_t len参数 - 别用
int*加长度,容易忘检查空指针
如何提前终止优化性能
冒泡排序最差时间复杂度是 O(n²),但最好情况(已有序)可以降到 O(n),前提是加入“是否发生交换”的标记。
没这个标记时,即使输入已排好序,仍会执行全部 n-1 轮;加了标记后,某轮零交换就可直接 break。
实操要点:
- 每轮开始前设
bool swapped = false - 只要发生一次
std::swap,就把swapped置为true - 本轮结束若
swapped == false,break外层循环 - 注意不要把
swapped声明在最外层——它必须每轮重置
为什么不用 std::sort 而手写冒泡
实际项目里几乎从不手写冒泡排序。它仅适合教学、调试验证或极特殊嵌入式约束(比如栈空间紧张且数据量恒为 5~10)。
std::sort 是混合排序(introsort),平均 O(n log n),且对小数组自动切到插入排序,还支持自定义比较器。拿它和冒泡比,就像拿汽车和脚踏车比通勤效率。
手写冒泡真正该关注的,是理解稳定排序、原地排序、比较次数与交换次数的区别——这些概念在分析其他算法时反复出现。一旦你开始纠结“要不要加哨兵”或“能不能改成双向冒泡”,说明你已经踩进算法思维的深水区了。


















