跳至正文
View Categories

1 min read

主要内容 #

  1. 算法讲解
  2. 例程
  3. 复杂度分析

1. 算法讲解 #

冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢”浮”到数列的顶端。

1.1 计算步骤 #

1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3. 针对所有的元素重复以上的步骤,除了最后一个。
4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

1.2 过程模拟 #

原始数据     [ 49  38  65  97  76  13  27  49 ]

第1次排序    [(38__49) 65  97  76  13  27  49 ] // AA__BB 表示数字发生了交换
            [ 38 (49  65) 97  76  13  27  49 ]
            [ 38  49 (65  97) 76  13  27  49 ]
            [ 38  49  65 (76__97) 13  27  49 ]
            [ 38  49  65  76 (13__96) 27  49 ]
            [ 38  49  65  76  13 (27__96) 49 ]
            [ 38  49  65  76  13  27 (49__96)] // 最大值 96 已经移动到了最右边

第2次排序    [(38  49) 65  76  13  27  49  96 ]
            [ 38 (49  65) 76  13  27  49  96 ]
            [ 38  49 (65  76) 13  27  49  96 ]
            [ 38  49  65 (13__76) 27  49  96 ]
            [ 38  49  65  13 (27__76) 49  96 ]
            [ 38  49  65  13  27 (49__67) 96 ] // 第 2 大值 67 已经找到了
            [ 38  49  65  13  27  49 (67  96)] // 可以省略

第3次排序    [(38  49) 65  13  27  49  67  96 ]
            [ 38 (49  65) 13  27  49  67  96 ]
            [ 38  49 (13__65) 27  49  67  96 ]
            [ 38  49  13 (27__65) 49  67  96 ]
            [ 38  49  13  27 (49__64) 67  96 ] // 第 3 大值 64 已经找到了
            [ 38  49  13  27  49 (64  67) 96 ] // 可以省略
            [ 38  49  13  27  49  64 (67  96)] // 可以省略

第4次排序    [(38  49) 13  27  49  64  67  96 ]
            [ 38 (13__49) 27  49  64  67  96 ]
            [ 38  13 (27__49) 49  64  67  96 ]
            [ 38  13  27 (49  49) 64  67  96 ] // 第 4 大值 49 已经找到了
            [ 38  13  27  49 (49  64) 67  96 ] // 可以省略
            [ 38  13  27  49  49 (64  67) 96 ] // 可以省略
            [ 38  13  27  49  49  64 (67  96)] // 可以省略

第5次排序    [(13__38) 27  49  49  64  67  96 ]
            [ 13 (27__38) 49  49  64  67  96 ]
            [ 13  27 (38  49) 49  64  67  96 ] // 第 5 大值 49 已经找到了
            [ 13  27  38 (49  49) 64  67  96 ] // 可以省略
            [ 13  27  38  49 (49  64) 67  96 ] // 可以省略
            [ 13  27  38  49  49 (64  67) 96 ] // 可以省略
            [ 13  27  38  49  49  64 (67  96)] // 可以省略

第6次排序    [(13  27) 38  49  49  64  67  96 ]
            [ 13 (27  38) 49  49  64  67  96 ] // 第 6 大值 38 已经找到了。(其实到这里排序就可以结束,循环到n-2次)
            [ 13  27 (38  49) 49  64  67  96 ] // 可以省略
            [ 13  27  38 (49  49) 64  67  96 ] // 可以省略
            [ 13  27  38  49 (49  64) 67  96 ] // 可以省略
            [ 13  27  38  49  49 (64  67) 96 ] // 可以省略
            [ 13  27  38  49  49  64 (67  96)] // 可以省略

第7次排序    [(13  27) 38  49  49  64  67  96 ] // 第 7 大值 27 已经找到了,且第 8 大值 13 也已经确定
            [ 13 (27  38) 49  49  64  67  96 ] // 可以省略
            [ 13  27 (38  49) 49  64  67  96 ] // 可以省略
            [ 13  27  38 (49  49) 64  67  96 ] // 可以省略
            [ 13  27  38  49 (49  64) 67  96 ] // 可以省略
            [ 13  27  38  49  49 (64  67) 96 ] // 可以省略
            [ 13  27  38  49  49  64 (67  96)] // 可以省略

第8次排序    [(13  27) 38  49  49  64  67  96 ] // 可以省略,第 8 大值 13 已经确定
            [ 13 (27  38) 49  49  64  67  96 ] // 可以省略
            [ 13  27 (38  49) 49  64  67  96 ] // 可以省略
            [ 13  27  38 (49  49) 64  67  96 ] // 可以省略
            [ 13  27  38  49 (49  64) 67  96 ] // 可以省略
            [ 13  27  38  49  49 (64  67) 96 ] // 可以省略
            [ 13  27  38  49  49  64 (67  96)] // 可以省略

结束排序

动画演示如下图所示:

2. 例程 #

请将上述的过程写出来。
示例程序:

#include < iostream >
using namespace std;

int main()
{
    int a[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
    int n = sizeof(a)/sizeof(int); // 请解释这段代码的意义
    
    for (int i = 0; i < n; ++i) // 请问可以优化吗?(提示:i < n 可优化)
    {
        for (int j = 0; j < n-1; ++j)
        {
            if (a[j] > a[j+1])
                swap(a[j], a[j+1]); // 如何自己实现?
        }
    }

    for (int i = 0; i < n; ++i)
        cout << a[i] << " ";

    return 0;
}

3. 复杂度分析 #

请问,这两个排序方法分别进行了多少次【比较】操作?你认为谁的速度快?
冒泡排序是与插入排序拥有相等的渐近时间复杂度,但是两种算法在需要的交换次数却很大地不同。
在最坏的情况,冒泡排序需要O(n^2)次交换,而插入排序只要最多O(n)交换。冒泡排序的实现通常会对已经排序好的数列拙劣地执行O(n^2)),而插入排序在这个例子只需要O(n)个运算。因此很多现代的算法教科书避免使用冒泡排序,而用插入排序取代。

习题 #

请默写上述代码。(优化答案:i < n 可以改为 i < n-2)