冒泡排序算法

冒泡排序

冒泡排序的核心思想非常直观,就像水中的气泡一样,较轻(小)的元素会逐渐上浮到水面(列表前端),而较重(大)的元素会逐渐下沉到底部(列表后端)。

其具体工作流程如下:

比较相邻元素:从列表的第一个元素开始,比较每一对相邻的两个元素。

交换位置:如果前一个元素比后一个元素大(在升序排序中),就交换它们的位置。

一轮遍历结束 :对列表中所有相邻元素对重复上述步骤,直到处理完最后一对。此时,列表中最大 的元素就会被移动到列表的最后位置。

重复过程:针对剩余的、未排序的元素(不包含上一轮已经就位的最大元素),重复执行步骤1-3。

这个过程会持续进行,每一轮都会将一个未排序部分的最大值放到正确的位置,直到整个列表有序

算法排序过程:

以数组 [38, 27, 43, 3, 9, 82, 10] 进行升序排序为例,其前两轮的详细过程如下:

第一轮遍历:

  • 比较 38 和 27:38 > 27 → 交换 → [27, 38, 43, 3, 9, 82, 10]
  • 比较 38 和 43:38 < 43 → 不交换 → [27, 38, 43, 3, 9, 82, 10]
  • 比较 43 和 3:43 > 3 → 交换 → [27, 38, 3, 43, 9, 82, 10]
  • 比较 43 和 9:43 > 9 → 交换 → [27, 38, 3, 9, 43, 82, 10]
  • 比较 43 和 82:43 < 82 → 不交换 → [27, 38, 3, 9, 43, 82, 10]
  • 比较 82 和 10:82 > 10 → 交换 → [27, 38, 3, 9, 43, 10, 82]
  • 结果 :最大元素 82 已经移动到正确位置。

第二轮遍历:

  • 比较 27 和 38:27 < 38 → 不交换 → [27, 38, 3, 9, 43, 10, 82]
  • 比较 38 和 3:38 > 3 → 交换 → [27, 3, 38, 9, 43, 10, 82]
  • 比较 38 和 9:38 > 9 → 交换 → [27, 3, 9, 38, 43, 10, 82]
  • 比较 38 和 43:38 < 43 → 不交换 → [27, 3, 9, 38, 43, 10, 82]
  • 比较 43 和 10:43 > 10 → 交换 → [27, 3, 9, 38, 10, 43, 82]
  • 结果 :第二大元素 43 已经就位。

后续轮次继续此过程,直到所有元素有序。如果在某一轮遍历中没有发生任何交换,说明列表已经完全有序,可以提前结束算法。

算法分析:

冒泡排序虽然实现简单,易于理解,但其效率并不高,尤其在处理大量数据时。

时间复杂度

最坏情况 O(n²):当输入的列表完全逆序时,需要进行 n-1 轮遍历,每轮都要进行大量的比较和交换。

平均情况 O(n²):在处理随机顺序的列表时,其时间复杂度也是平方级别的。

最好情况 O(n):当输入的列表已经有序时,经过优化的冒泡排序只需进行一轮遍历(没有发生任何交换)即可完成,时间复杂度为线性。

空间复杂度

O(1) :冒泡排序只需要常数级别的额外空间来存储临时变量(用于交换元素),是一种原地排序算法。

稳定性

稳定 :冒泡排序是一种稳定排序算法。因为只有当相邻两个元素前大于后时才会交换,如果两个元素相等,它们的相对位置不会改变。

cpp 复制代码
#include <stdio.h>

// 冒泡排序函数
void bubbleSort(int arr[], int n) {
    // 外层循环控制排序轮数 (n-1 轮即可保证全部有序)
    for (int i = 0; i < n - 1; i++) {
        int swapped = 0; // 标志位,记录本轮是否发生交换

        // 内层循环进行相邻元素比较
        // 每经过一轮,最大的元素会"冒泡"到末尾,所以 j 的范围是 n-i-1
        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 = 1; // 标记发生了交换
            }
        }

        // 如果本轮没有发生任何交换,说明数组已经有序,可以提前结束
        if (!swapped) {
            break;
        }
    }
}

// 打印数组的辅助函数
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

// 主函数,用于测试
int main() {
    int data[] = {38, 27, 43, 3, 9, 82, 10};
    int n = sizeof(data) / sizeof(data[0]); // 计算数组长度

    printf("排序前: ");
    printArray(data, n);

    bubbleSort(data, n);

    printf("排序后: ");
    printArray(data, n);

    return 0;
}
相关推荐
毅炼5 小时前
hot100打卡——day17
java·数据结构·算法·leetcode·深度优先
Tisfy5 小时前
LeetCode 3010.将数组分成最小总代价的子数组 I:排序 OR 维护最小次小
算法·leetcode·题解·排序·最小次小值
Learn Beyond Limits5 小时前
文献阅读:A Probabilistic U-Net for Segmentation of Ambiguous Images
论文阅读·人工智能·深度学习·算法·机器学习·计算机视觉·ai
m0_736919105 小时前
编译器命令选项优化
开发语言·c++·算法
naruto_lnq6 小时前
C++中的工厂方法模式
开发语言·c++·算法
千逐-沐风6 小时前
SMU-ACM2026冬训周报2nd
算法
m0_748233176 小时前
C#与C语言:5大核心语法共性
java·jvm·算法
痴儿哈哈6 小时前
C++与硬件交互编程
开发语言·c++·算法
小O的算法实验室7 小时前
2024年ESWA SCI1区TOP,异构无人机配送问题的集成多目标优化方法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进