冒泡排序算法

冒泡排序

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

其具体工作流程如下:

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

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

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

重复过程:针对剩余的、未排序的元素(不包含上一轮已经就位的最大元素),重复执行步骤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;
}
相关推荐
怕浪猫12 小时前
用了两年 AI 编程工具后,我重新理解了什么是「资深工程师」
算法·面试·架构
hetao173383712 小时前
2026-08-27~29 hetao1733837 的刷题记录
c++·算法
云淡风轻~窗明几净13 小时前
宇宙管理学猜想
算法·图论
春风解人意13 小时前
从零开始学习嵌入式P28----线程
c语言·学习·算法
luj_176813 小时前
合法避税与投资评估实战指南
c语言·开发语言·网络·经验分享·算法
Bruce_Liuxiaowei13 小时前
驴滑块拼图游戏:从19世纪的纸片谜题到数学博弈论
人工智能·算法
一直C13 小时前
Linux系统编程|信号进阶 + SystemV IPC(消息队列、共享内存)
linux·c语言·开发语言·算法·青少年编程·vim
鹿角片ljp15 小时前
LeetCode 141. 环形链表|从 HashSet 到快慢指针 O (1) 空间最优解
算法·leetcode·链表
薛定e的猫咪15 小时前
(NeurIPS 2022)GraphGPS:MPNN 与全局注意力的融合之道
人工智能·深度学习·学习·算法
AI服务老曹15 小时前
车牌识别算法接入AI视频分析平台的流程和误报优化
人工智能·算法·音视频