大家好!今天我们来学习一个简单又经典的排序算法——冒泡排序,并且用C++语言实现它。冒泡排序的名字听起来很有趣,它的核心思想就像水中的气泡会向上浮一样,小的元素会逐渐“冒”到数组的顶端,最终让整个数组变得有序。

一、冒泡排序的基本思想

冒泡排序的核心是重复比较相邻的两个元素,如果它们的顺序错误就交换位置。具体来说:
- 从数组的第一个元素开始,依次比较相邻的两个元素。
- 如果前一个元素比后一个元素大,就交换它们的位置。
- 这样一轮比较下来,数组中最大的元素会“冒泡”到数组的末尾。
- 重复上述过程,每一轮都能确定一个最大元素的最终位置,直到整个数组有序。

二、举个例子理解过程

假设我们有一个数组:[5, 2, 9, 1, 5, 6],我们用冒泡排序来让它有序。

第一轮(确定最大元素9的位置):
- 比较5和2:5>2,交换 → [2, 5, 9, 1, 5, 6]
- 比较5和9:5<9,不交换
- 比较9和1:9>1,交换 → [2, 5, 1, 9, 5, 6]
- 比较9和5:9>5,交换 → [2, 5, 1, 5, 9, 6]
- 比较9和6:9>6,交换 → [2, 5, 1, 5, 6, 9]
此时最大元素9已“冒泡”到数组末尾,无需再比较。

第二轮(确定第二大元素6的位置):
- 比较2和5:2<5,不交换
- 比较5和1:5>1,交换 → [2, 1, 5, 5, 6, 9]
- 比较5和5:相等,不交换
- 比较5和6:5<6,不交换
此时第二大元素6已确定位置。

后续轮次类似,直到所有元素有序。

三、C++代码实现

下面是冒泡排序的C++代码实现,附带详细注释:

#include <iostream>
using namespace std;

// 冒泡排序函数:参数为数组和数组长度
void bubbleSort(int arr[], int n) {
    // 外层循环:控制需要进行多少轮比较(n个元素需n-1轮)
    for (int i = 0; i < n - 1; ++i) {
        bool swapped = false; // 标记本轮是否发生交换
        // 内层循环:每轮比较相邻元素,范围为数组前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 = true;          // 标记发生了交换
            }
        }
        // 优化:如果本轮没有交换,说明数组已完全有序,提前退出
        if (!swapped) {
            break;
        }
    }
}

// 主函数:测试冒泡排序
int main() {
    int arr[] = {5, 2, 9, 1, 5, 6}; // 待排序数组
    int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度

    cout << "排序前数组:";
    for (int i = 0; i < n; ++i) {
        cout << arr[i] << " ";
    }
    cout << endl;

    bubbleSort(arr, n); // 调用冒泡排序函数

    cout << "排序后数组:";
    for (int i = 0; i < n; ++i) {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

四、代码解释

  1. 外层循环for (int i = 0; i < n - 1; ++i)
    控制排序的轮数。由于n个元素最多需要n-1轮(每轮确定一个最大元素的位置),所以循环次数为n-1。

  2. 内层循环for (int j = 0; j < n - i - 1; ++j)
    控制每轮的比较次数。每轮结束后,最大元素已“冒泡”到末尾,因此下一轮无需比较最后i个元素(i为当前轮次),比较范围缩小到n - i - 1

  3. 交换逻辑int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp;
    使用临时变量temp交换相邻元素,确保交换过程中数据不丢失。

  4. 优化点bool swapped = false
    如果某一轮没有发生交换,说明数组已完全有序,可提前退出外层循环,避免无效比较,提升效率。

五、运行结果

上述代码运行后,输出如下:

排序前数组:5 2 9 1 5 6 
排序后数组:1 2 5 5 6 9 

六、复杂度分析

  • 时间复杂度
  • 最坏情况(完全逆序):O(n²)(需完整n-1轮,每轮比较n-i次)。
  • 最好情况(已排序):O(n)(优化后仅需1轮,无交换直接退出)。
  • 平均情况:O(n²)。

  • 空间复杂度:O(1)(仅使用1个临时变量,原地排序)。

  • 稳定性:稳定排序(相等元素不会交换位置)。

七、总结

冒泡排序是学习排序算法的入门首选,它的核心思想简单直观,容易理解。虽然效率不如快速排序、归并排序等高级算法,但通过它能帮助我们掌握“比较交换”的基本排序逻辑。如果你想进一步优化,可以尝试调整数组的初始化、修改交换条件等。动手实践是理解算法的最好方式,不妨尝试修改代码中的数组元素,看看不同情况下冒泡排序的表现吧!

小夜