冒泡排序是原地算法,通过外层控制n−1轮排序、内层逐对比较交换实现;每轮后最大值归位,边界收缩,仅用常数额外空间完成就地腾挪。

冒泡排序的嵌套循环结构,本质是用两层控制实现“逐轮筛选 + 原地对调”的过程。外层控制轮数,内层负责当轮的相邻比较与交换;所有操作都在原数组上进行,不额外申请空间——这就是它被称为“原地算法”的关键。
外层循环:决定排序轮次和边界收缩
外层循环变量(如 i)代表已完成排序的元素个数。每执行一轮,最大(或最小)元素就“冒泡”到末尾固定位置,因此下一轮无需再检查最后 i 个位置。
- 数组长度为 n 时,最多需 n−1 轮——因为最后一个元素自然有序
- 第 i 轮中,内层只需遍历前 n−1−i 对相邻元素(索引从 0 到 n−2−i)
- 例如 7 个元素的数组,第 0 轮比 6 次,第 1 轮比 5 次,第 2 轮比 4 次……直到第 6 轮无需比较
内层循环:执行相邻比较与条件交换
内层循环(如 j)在当前有效范围内,挨个取 arr[j] 和 arr[j+1] 进行比较。是否交换,只取决于二者大小关系和目标序(升序则左 > 右时交换)。
- 交换不是无条件发生,而是由 if (arr[j] > arr[j+1]) 触发
- 交换动作本身极简:tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp;,全程只动数组内部值
- 每轮内循环结束,当前未排序段的最大值必出现在该段末尾——这是相邻交换累积效果的确定结果
原地对调如何体现“零空间开销”
整个过程不创建新数组、不复制子序列、不借助栈或队列缓冲。所有数据移动都通过三个变量完成:两个索引指针(j, j+1)定位位置,一个临时变量(tmp)暂存值。
- 哪怕数组含百万整数,额外内存仅需常数级(几个 int 类型变量)
- 交换前后,数组地址不变,元素物理位置只在相邻索引间互换
- 这种“就地腾挪”特性,使冒泡排序天然适配内存受限场景(如嵌入式系统基础排序)
实战中容易忽略的关键细节
初学者写嵌套循环常出错,多因没理清索引边界或混淆轮次逻辑。注意以下几点可避免典型 bug:
- 内层循环上限必须是 sz − 1 − i,不能写成 sz − i(否则 j+1 会越界)
- 外层循环上限是 sz − 1,不是 sz(最后一轮只剩一个元素,无需比较)
- 若某轮内循环一次交换都没发生,说明已整体有序,可提前 break——加个 flag 变量就能实现优化
- C 语言中传数组进函数后,sizeof(arr) 不等于原数组长度,必须由调用方显式传入 sz

















