C语言排序——冒泡排序
原理
通过连续地比较与交换相邻元素实现排序。这个过程就像气泡从底部升到顶部一样,因此得名冒泡排序。
从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左元素 > 右元素”就交换它俩。遍历完成后,最大的元素会被移动到数组的最右端。
设数组的长度为 𝑛 :
- 首先,对 𝑛 个元素执行“冒泡”, 将数组的最大元素交换至正确位置,
- 接下来,对剩余 𝑛 − 1 个元素执行“冒泡”, 将第二大元素交换至正确位置。
- 以此类推,经过 𝑛 − 1 轮“冒泡”后, 前 𝑛 − 1 大的元素都被交换至正确位置。
- 仅剩的一个元素必定是最小元素,无须排序,因此数组排序完成。
示例
“4 1 3 1 5 2”
第一轮:
- 比较第一个元素“4”和第二个元素“1”,因为 4>1,所以交换它们的位置,序列变为“1 4 3 1 5 2”。
- 接着比较第二个元素“4”和第三个元素“3”,4>3,交换位置,序列变为“1 3 4 1 5 2”。
- 再比较第三个元素“4”和第四个元素“1”,4>1,交换位置,序列变为“1 3 1 4 5 2”。
- 继续比较第四个元素“4”和第五个元素“5”,4<5,不交换。
- 最后比较第五个元素“5”和第六个元素“2”,5>2,交换位置,序列变为“1 3 1 4 2 5”。
第二轮:
- 比较第一个元素“1”和第二个元素“3”,1<3,不交换。
- 比较第二个元素“3”和第三个元素“1”,3>1,交换位置,序列变为“1 1 3 4 2 5”。
- 比较第三个元素“3”和第四个元素“4”,3<4,不交换。
- 比较第四个元素“4”和第五个元素“2”,4>2,交换位置,序列变为“1 1 3 2 4 5”。
第三轮:
- 比较第一个元素“1”和第二个元素“1”,不交换。
- 比较第二个元素“1”和第三个元素“3”,1<3,不交换。
- 比较第三个元素“3”和第四个元素“2”,3>2,交换位置,序列变为“1 1 2 3 4 5”。
第四轮:
- 比较第一个元素“1”和第二个元素“1”,不交换。
- 比较第二个元素“1”和第三个元素“2”,1<2,不交换。
- 比较第三个元素“2”和第四个元素“3”,2<3,不交换。
第五轮:
- 比较第一个元素“1”和第二个元素“1”,不交换。
- 比较第二个元素“1”和第三个元素“2”,1<2,不交换。
序列为“1 1 2 3 4 5”。
代码(C)
/* 冒泡排序 */
void bubbleSort(int nums[], int size) {
// 外循环:未排序区间为 [0, i]
for (int i = 0; i < size - 1; i++) {
// 外循环控制排序的轮数。每一轮会将当前未排序区间中的最大元素“冒泡”到未排序区间的最右端,
// 所以每一轮结束后,未排序区间的范围会缩小。
// 当 i = 0 时,未排序区间为整个数组 [0, size - 1];当 i = 1 时,未排序区间变为 [0, size - 2],以此类推。
// 总共需要进行 size - 1 轮循环,因为当进行到第 size - 1 轮时,最后一个元素已经在正确的位置上了。
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < size - 1 - i; j++) {
// 内循环在每一轮中遍历未排序区间,比较相邻的元素,如果前一个元素大于后一个元素,就交换它们的位置。
// 通过不断地比较和交换,每一轮都会将未排序区间中的最大元素移动到未排序区间的最右端。
// j < size - 1 - i 的原因是,随着外循环的进行,每一轮结束后,未排序区间的范围会缩小,
// 已经排好序的元素不需要再参与比较和交换。
if (nums[j] > nums[j + 1]) {
// 如果当前元素大于下一个元素,则进行交换。
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
}
}
}
}
复杂度
时间复杂度:最差情况为
空间复杂度:为
效率优化版冒泡
如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。
/* 冒泡排序(标志优化) */
void bubbleSortWithFlag(int nums[], int size) {
// 外循环:未排序区间为 [0, i]
for (int i = 0; i < size - 1; i++) {
bool flag = false;
// flag 标志变量用于判断在本轮内循环中是否发生了交换。初始化为 false,表示假定本轮没有交换发生。
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < size - 1 - i; j++) {
if (nums[j] > nums[j + 1]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
flag = true;
// 如果当前元素大于下一个元素,则进行交换,并将 flag 设置为 true,表示发生了交换。
}
}
if (!flag)
break;
// 如果在本轮内循环中没有发生交换(即 flag 为 false),说明数组已经有序,直接退出外循环。
}
}

