C++算法之冒泡排序

C++算法之冒泡排序



一、基本思想

试想一下,如果在上体育课的时候,通常学生都会随意站成一列,但是体育老师会帮忙调整学生的站位使得最终顺序是按照身高排序的。那么,回忆一下体育老师是如何调整顺序的呢?

假设体育老师想将学生从左到右按照身高从矮到高排序。通常情况下,他会从左到右扫视学生的身高。如果左边有一个同学,个子比右边的同学高,他就要将其进行调整。具体调整方法是:

如果一个同学比他右边的同学高,就让这两个同学交换位置。
如果交换过后,这个同学仍然比新的右边的同学高,那么继续交换,直到他不在比右边的同学高。这样进行了若干次以后,队列就按照身高排好序了。

那么,如何严谨地表述“体育老师排序方法”,并对于任意给定的序列,都能将其从小到大排好序呢?

回忆在介绍选择排序的时候,我们的具体思路如下:
在这里插入图片描述
我们发现,这里我们使用了将原问题转换为规模更小的子问题的思路。

所以在选择排序的过程,相当于每次将当前序列未排序部分的最小元素归位,将未排序的序列长度缩小一位。同样,如果我们能够通过某种方式,把序列中的最大值移动到序列最后面,也可以起到将未排序序列长度缩小一位的效果。
在这里插入图片描述
通过“体育老师交换方法”,使得每次我们都能把最大值移动到序列的最后一位。

利用上面的步骤进行问题转换,将未排序的序列长度缩减一个。

这就是冒泡排序的具体思路,而上面提到的“将最大值移动到最后一位”的操作,就叫做冒泡操作。

二、步骤

冒泡排序

1、冒泡排序分为n-1个阶段。
在第1个阶段,通过“冒泡”,将前n个元素的最大值移动到序列的最后一位。此时只剩前n-1个元素未排序。
2、在第i个阶段,此时序列前n-i+1个元素未排序。通过“冒泡”,我们将前n-i+1个元素中的最大值移动到最后一位。此时只剩前n-i个元素未排好序。
3、最终到第n-1个阶段,前2个元素未排序。将其中的较大值移动到后一位,则整个序列排序完毕。
4、在上面的算法过程中,我们提到“冒泡”将序列中的最大值移动到最后一位。下面,我们介绍一下“冒泡”的过程:

冒泡过程

对于长度为n的序列,如何将其中的最大值移动到最后一位?

就像上面说的那样,如果相邻两个元素(如下图2和3),第一个大,第二个小,那么,将两个元素交换。
在这里插入图片描述
如果我们对一段序列从左到右连续做如下交换操作:

if (a[i] > a[i + 1]) swap(a[i], a[i + 1])

它的效果相当于将每一个”极大值“元素,移动到能到达的最远的位置。
在这里插入图片描述
自然,序列中的最大值,也是一个极大值,而它能被移动到的最远的位置,就是序列的最后一位。

所以,如果对于序列的1~n位,想将其中的最大元素”冒泡“到最后一位,那么就需要从第1位开始,一直到第n-1位,依次进行上面的交换过程。

三、代码

代码如下(示例):

#include <bits/stdc++.h>
#define N 1010
using namespace std;
int n = 6; // 待排序的元素个数为6
int a[N] = {0, 2, 3, 2, 11, 7, 6}; // 待排序元素 {2,3,2,11,7,6}

int main() {   
    // 连续交换过程
    // 一共n-1个阶段,在第i个阶段,未排序序列长度从n-i+1到n-i。
    for (int i = 1; i < n; ++i) {  
        // 将序列从1到n-i+1的最大值,移到n-i+1的位置
        for (int j = 1; j <= n - i; ++j)
            // 其中j枚举的是前后交换元素的前一个元素序号
            // TODO 请补全代码完成阶段的冒泡过程
            if (a[j] > a[j + 1]) 
                swap(a[j], a[j + 1]);
    }
    
    // 输出
    for (int i = 1; i <= n; ++i) cout << a[i] << ' ';
    cout << endl;
    return 0;
}

四、复杂度分析

从代码中,我们可以看到冒泡排序的主干部分有两层循环,并且每一层的循环次数都在O(n)左右的数量级。所以完整的冒泡排序时间复杂度是O(n^2)

  • 34
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值