📑冒泡排序介绍
冒泡排序是一种简单但效率较低的排序算法。它重复地比较相邻的两个元素,如果顺序不对则交换它们,直到所有元素都被比较过一次。这样每一轮比较过后,最大的元素就会"冒泡"到最后面。接着,算法将会忽略最后一个元素,重复上述比较和交换的过程,直到所有元素都按照顺序排列。
⭐ 冒泡排序算法的步骤如下:
- 从数组的第一个元素开始,依次比较相邻的两个元素。
- 如果前一个元素大于后一个元素,交换它们的位置。
- 继续比较下一对相邻元素,直到最后一个元素。
- 重复以上步骤,每一轮比较都会将最大的元素"冒泡"到最后面。
- 当比较结束时,此时数组已经排好序,排序结束。
动图演示如下:
🌤️代码实现
🌳C语言版
// 交换函数,用于交换数组中两个元素的位置
void swap(int* arr, int i, int j) {
int tmp = arr[i]; // 将第一个元素的值存储在临时变量 tmp 中
arr[i] = arr[j]; // 将第二个元素的值赋给第一个元素的位置
arr[j] = tmp; // 将临时变量 tmp 的值赋给第二个元素的位置
}
// 冒泡排序函数,用于对数组进行排序
void bobbleSort(int* arr, int n) {
// 外层循环控制需要遍历的轮数,共进行 n-1 次遍历
for (int i = 0; i < n - 1; i++) {
// 内层循环进行相邻元素的比较和交换
// j 的范围是从 0 到 n-i-1,这样每次内层循环可以比较并将最大值移动到最后
for (int j = 0; j < n - i - 1; j++) { // j 进循环的条件容易出错,特殊标记下
// 如果前一个元素比后一个元素大,交换它们
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1); // 调用交换函数进行交换
}
}
}
}
🌳java版
// 交换函数,用于交换数组中两个元素的位置
private static void swap(int[] array, int i, int j) {
int tmp = array[i]; // 将第一个元素的值存储在临时变量 tmp 中
array[i] = array[j]; // 将第二个元素的值赋给第一个元素的位置
array[j] = tmp; // 将临时变量 tmp 的值赋给第二个元素的位置
}
// 冒泡排序函数,用于对数组进行排序
public static void bubbleSort(int[] array) {
// 外层循环控制需要遍历的轮数
for (int i = 0; i < array.length; i++) {
// 内层循环进行相邻元素的比较和交换
for (int j = i + 1; j < array.length; j++) {
// 如果前一个元素比后一个元素大,交换它们
if (array[i] > array[j]) {
swap(array, i, j); // 调用交换函数进行交换
}
}
}
}
🌤️做个简单的优化
可以在内层循环中定义一个变量 flag:用于检测这一轮内层循环是否发生了交换。初始值设为 1。
如果在一轮内层循环中没有发生交换(flag 仍为 1),说明数组已经有序,跳出循环即可。
🌳C语言版
// 交换函数,用于交换数组中两个元素的位置
void swap(int* arr, int i, int j) {
int tmp = arr[i]; // 将第一个元素的值存储在临时变量 tmp 中
arr[i] = arr[j]; // 将第二个元素的值赋给第一个元素的位置
arr[j] = tmp; // 将临时变量 tmp 的值赋给第二个元素的位置
}
// 冒泡排序函数,用于对数组进行排序
void bobbleSort(int* arr, int n) {
// 外层循环控制需要遍历的轮数,共进行 n-1 次遍历
for (int i = 0; i < n - 1; i++) {
int flag = 1; // 标记用于检测这一轮是否发生了交换
// 内层循环进行相邻元素的比较和交换
// j 的范围是从 0 到 n-i-1,这样每次内层循环可以比较并将最大值移动到最后
for (int j = 0; j < n - i - 1; j++) { // j 进循环的条件容易出错,特殊标记下
// 如果前一个元素比后一个元素大,交换它们
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1); // 调用交换函数进行交换
flag = 0; // 发生交换后,将标记设置为 0
}
}
// 如果没有发生交换,说明数组已经有序,提前退出排序
if (flag) {
break;
}
}
}
🌳java版
// 交换函数,用于交换数组中两个元素的位置
private static void swap(int[] array, int i, int j) {
int tmp = array[i]; // 将第一个元素的值存储在临时变量 tmp 中
array[i] = array[j]; // 将第二个元素的值赋给第一个元素的位置
array[j] = tmp; // 将临时变量 tmp 的值赋给第二个元素的位置
}
public static void bubbleSort(int[] array) {
// 外层循环控制需要遍历的轮数,共进行 array.length 次遍历
for (int i = 0; i < array.length; i++) {
boolean flg = true; // 标记用于检测这一轮是否发生了交换
// 内层循环进行相邻元素的比较和交换
// j 的范围是从 i+1 到 array.length,注意这里的起始点是 i+1
for (int j = i + 1; j < array.length; j++) {
// 如果前一个元素比后一个元素大,交换它们
if (array[i] > array[j]) {
swap(array, i, j); // 调用交换函数进行交换
flg = false; // 发生交换后,将标记设置为 false
}
}
// 如果没有发生交换,说明数组已经有序,提前退出排序
if (flg) {
break;
}
}
}
🌤️复杂度和稳定性分析
时间复杂度分析:在最坏的情况下,冒泡排序需要进行n-1轮比较,每轮比较需要进行n-i次。因此,总的比较次数为(n-1) + (n-2) + … + 2 + 1 = n(n-1)/2,近似为O(n2)。
空间复杂度分析:使用了常数个变量,因此空间复杂度为O(1)
什么是稳定性?
答:稳定性指的是相同的数据所在的位置经过排序后是否发生变化。换句话说就是大小相同的两个值在排序之前和排序之后的先后顺序不变,这就是稳定的。
稳定性分析:冒泡排序将小的元素往前调或者把大的元素往后调;比较的是相邻的两个元素,交换也发生在这两个元素之间;因为相等的元素不会进行交换,所以稳定。
总结: 冒泡排序的时间复杂度为O(N2),空间复杂度为O(1),而且是稳定的排序。