冒泡排序需外层n-1轮、内层每轮范围递减,交换条件为arr[j] > arr[j+1](升序),且j+1
冒泡排序的核心逻辑怎么写才不出错
冒泡排序本质是重复比较相邻元素并交换,让较大(或较小)的值像气泡一样“浮”到一端。关键不是背代码,而是理解每轮
for循环的边界和交换条件。
- 外层循环控制“轮数”,共
n-1轮就够了(最后一轮只剩一个元素无需比较)- 内层循环控制“当前轮中比较的范围”,每轮后末尾已有序,所以每次上限减 1:用
j ,别写成j- 交换只在
arr[j] > arr[j + 1]时发生(升序),注意下标别越界——j + 1要小于n手写时最容易踩的数组越界和索引错误
新手常把内层循环写成
for (int j = 0; j ,然后在循环里访问arr[j+1],导致访问arr[n]——这是未定义行为,可能崩溃或输出乱码。
- 正确写法必须保证
j + 1 ,即j ;再结合每轮缩小范围,就是j- 如果用
std::vector,记得用.size()获取长度,并强转为int或用有符号类型比较,避免无符号整数下溢(比如0 - 1变成极大正数)- 调试时可在循环开头加
std::cout 快速定位越界位置用 vector 还是原生数组?参数传递怎么选
对新手更安全的是传
std::vector,避免指针和长度分离带来的管理负担;但如果练基本功,用原生数组要显式传长度,不能只传& int arr[](它会退化为指针,丢失大小)。
- 推荐函数签名:
void bubbleSort(std::vector或& arr) void bubbleSort(int arr[], int n)- 别写
void bubbleSort(int arr[])—— 编译器不检查长度,你无法知道数组多大- 如果函数内需要拷贝一份做测试,用
std::vector,别用temp = arr; memcpy操作 vector 内部指针(不安全且没必要)要不要加优化:提前终止的 flag 怎么设才有效
如果某轮没发生任何交换,说明已有序,可以提前退出。但 flag 的初始化和重置位置很关键,放错地方会让优化失效。
立即学习“C++免费学习笔记(深入)”;
- flag 必须在每轮外层循环开始前设为
false,并在发生交换时设为true- 检查时机在内层循环结束后:
if (!swapped) break;- 注意不要在内层循环里就 break 外层——c++ 没有标签 break,得靠 flag 控制
- 这个优化对已排序或近似有序数据明显,但最坏情况(逆序)下仍为 O(n²),别误以为加了 flag 就变快了
实际写的时候,先跑通无 flag 版本,再加 flag;测试用例至少包括空数组、单元素、已排序、完全逆序、含重复数这五种情况。边界比算法本身更容易出问题。
