一、冒泡排序简介
冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地遍历待排序的数列,依次比较相邻的元素,并根据需要交换它们的位置。这样较大的元素像气泡一样逐渐“冒泡”到数列的末端,最终将整个数列排好顺序。
关键点:
- 比较相邻元素:每次比较两个相邻元素,如果它们的顺序错误(通常是前一个比后一个大),就交换它们。
- 冒泡过程:每一轮遍历会将当前未排序部分的最大元素推到最右侧。
- 逐步缩小比较范围:每次遍历完成后,右边的部分已经是排序好的,因此可以忽略已排序的元素,逐渐缩小比较范围。
冒泡排序的步骤:
- 从第一个元素开始,依次比较相邻元素。
- 若前面的元素比后面的元素大,则交换它们的位置。
- 这样大的元素不断“冒泡”到数组的末尾。
- 重复这个过程,直到数组完全有序。
二、冒泡排序演示排序过程
示例:排序数组 [5, 3, 8, 4, 2]
初始状态:
[5, 3, 8, 4, 2]
第一轮遍历:
- 比较 5 和 3,交换它们,得到 [3, 5, 8, 4, 2]
- 比较 5 和 8,不交换,得到 [3, 5, 8, 4, 2]
- 比较 8 和 4,交换它们,得到 [3, 5, 4, 8, 2]
- 比较 8 和 2,交换它们,得到 [3, 5, 4, 2, 8]
第二轮遍历:
- 比较 3 和 5,不交换,得到 [3, 5, 4, 2, 8]
- 比较 5 和 4,交换它们,得到 [3, 4, 5, 2, 8]
- 比较 5 和 2,交换它们,得到 [3, 4, 2, 5, 8]
第三轮遍历:
- 比较 3 和 4,不交换,得到 [3, 4, 2, 5, 8]
- 比较 4 和 2,交换它们,得到 [3, 2, 4, 5, 8]
第四轮遍历:
- 比较 3 和 2,交换它们,得到 [2, 3, 4, 5, 8]
最终排序结果:
[2, 3, 4, 5, 8]
三、冒泡排序的时间复杂度分析
冒泡排序的时间复杂度分析主要依赖于其在最坏情况下、最好情况下和平均情况下的表现。
1. 最坏情况时间复杂度
最坏情况发生在输入数组是逆序排列的情况下。在这种情况下,冒泡排序需要进行最大次数的比较和交换操作。
排序过程:
第一轮遍历会比较 n - 1 对元素,第二轮遍历比较 n - 2 对元素,依此类推。因此,冒泡排序需要进行 n-1 轮遍历,每一轮遍历会进行最多的交换操作。
计算比较次数:
- 第一轮:n-1 次比较。
- 第二轮:n-2 次比较。
- 第三轮:n-3 次比较。
- …
- 最后一轮:1 次比较。
因此,所有比较的总数为:

这就是一个等差数列的求和,即 O(n²)。
最坏情况时间复杂度:O(n²)
2.最好情况时间复杂度
最好情况发生在输入数组已经是有序的情况下。为了优化冒泡排序,我们可以加入一个标志位来检查每一轮是否发生了交换。如果没有发生交换,说明数组已经排好序,可以提前结束排序。
排序过程:
在最好情况下,冒泡排序将进行 n-1 次比较,但由于没有交换,算法会在第一次遍历后提前结束。
计算比较次数:
- 第一轮:n-1 次比较。
- 第二轮:没有交换,提前结束。
因此,最好情况下只需要 O(n) 次比较。
最好情况时间复杂度:O(n)
3.平均情况时间复杂度
平均情况指的是输入数组中的元素顺序是随机的。计算平均时间复杂度时,我们假设每一轮排序的交换和比较大致是均匀分布的。
排序过程:
平均情况下,冒泡排序会执行与最坏情况类似的操作,但有可能发生一些交换。虽然交换次数较少,但每一轮的比较次数仍然接近最坏情况的比较次数。
计算过程与最坏情况类似:
- 第一轮:n-1 次比较。
- 第二轮:n-2 次比较。
- 第三轮:n-3 次比较。
- …
- 最后一轮:1 次比较。
总比较次数为:

因此,平均时间复杂度仍然是 O(n²)。
平均情况时间复杂度:O(n²)
4. 优化后的冒泡排序
如果我们优化冒泡排序,使用一个布尔变量 swapped 来标记每一轮是否进行了交换:
- 如果某一轮没有交换,说明数组已经有序,可以提前终止排序,减少不必要的比较。
- 这种优化可以将最佳情况的时间复杂度减少到 O(n),但最坏情况和平均情况的时间复杂度仍然是 O(n²)。
5.空间复杂度
冒泡排序是原地排序算法,不需要额外的存储空间来存放临时数据。因此,它的空间复杂度是 O(1)。
四、完整示例
#include <iostream>
using namespace std;
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) { // 外循环控制轮数
for (int j = 0; j < n - i - 1; j++) { // 内循环进行相邻元素的比较
if (arr[j] > arr[j + 1]) {
// 交换相邻元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
bubbleSort(arr, n);
cout << "Sorted array: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
优化:
标准的冒泡排序会在每一轮都进行完整的比较,但实际上,如果某一轮没有发生任何交换,那么可以认为数组已经排序好,排序可以提前终止。这样的优化会让最好的情况变成 O(n) 时间复杂度。
void bubbleSortOptimized(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
bool swapped = false; // 用于检查是否发生了交换
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
if (!swapped) {
break; // 如果没有交换,提前退出循环
}
}
}
1550

被折叠的 条评论
为什么被折叠?



