七大经典排序算法——冒泡排序

文章目录


📑冒泡排序介绍

冒泡排序是一种简单但效率较低的排序算法。它重复地比较相邻的两个元素,如果顺序不对则交换它们,直到所有元素都被比较过一次。这样每一轮比较过后,最大的元素就会"冒泡"到最后面。接着,算法将会忽略最后一个元素,重复上述比较和交换的过程,直到所有元素都按照顺序排列。

⭐ 冒泡排序算法的步骤如下:

  1. 从数组的第一个元素开始,依次比较相邻的两个元素。
  2. 如果前一个元素大于后一个元素,交换它们的位置。
  3. 继续比较下一对相邻元素,直到最后一个元素。
  4. 重复以上步骤,每一轮比较都会将最大的元素"冒泡"到最后面。
  5. 当比较结束时,此时数组已经排好序,排序结束。

动图演示如下:

🌤️代码实现

🌳C语言版

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版

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语言版

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版

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),而且是稳定的排序。


☁️结语

请给自己些耐心,不要急于求成。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!


都看到这里啦!真棒(*^▽^*)

可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家

如有纰漏或错误,欢迎指正


相关推荐
ChiaWei Lee5 分钟前
【C语言】深入理解指针(三):C语言中的高级指针应用
c语言·开发语言
最后一个bug6 分钟前
教你快速理解linux中的NUMA节点探测是干什么用的?
linux·c语言·开发语言·arm开发·嵌入式硬件
易元8 分钟前
设计模式-代理模式
java·后端
trust Tomorrow12 分钟前
每日一题-力扣-2278. 字母在字符串中的百分比 0331
算法·leetcode
JaneYork15 分钟前
接口设计,接口返回信息,当账号不存在时候,应该返回200还是500,是直接返回R.fail()还是throw exception
java·spring boot
qianmoq19 分钟前
轻松掌握Java多线程 - 第二章:线程的生命周期
java·后端
风象南21 分钟前
Spring Boot 实现文件断点续传
java·spring boot·后端
Lecea_L27 分钟前
你能在K步内赚最多的钱吗?用Java解锁最大路径收益算法(含AI场景分析)
java·人工智能·算法
Tony8828 分钟前
热题100 - 394. 字符串解码
java·算法
cwtlw31 分钟前
JavaRedis和数据库相关面试题
java·数据库·笔记·面试