【排序算法-2】冒泡排序详解

一.简述

上篇总结了一下常用的排序算法,排序算法总结,这篇文章将详细介绍冒泡排序算法。
冒泡排序法(Bubble Sort)是由观察水中冒泡的变化启发而来,需要遍历几次数组,在每次遍历的过程中,比较连续相邻的元素,如果相邻的两个元素是降序,则将他们俩的值互换,如果是升序则保持不变,然后再继续比较下一个相邻元素。由于较小的值像“气泡”一样会逐渐浮起来,较大的值会慢慢沉下底部,所以将这种排序技术形象的称为“冒泡排序”或者“下沉排序”。

二. 原理

原理其实上面已经有所说明,具体就是:
(1)比较相邻的元素,如果第一个比第二个大,就交换他们两个;
(3)针对所有的元素重复以上的步骤;

这里写图片描述

现在为了更加清楚的说明原理,我们举个例子:

有8个数:

3,9,2,7,5,0,8,10

从左到右依次比较相邻元素:
(1)先比较第一对元素(3,9),因为这两个数本来就是先大后小的顺序,所以不需要进行交换;
(2)然后比较第二对元素(9,2),因为 9 大于 2,所以需要交换两个数,8个数的次序暂时为:

3,2,9,7,5,0,8,10;

(3)接着计较第三对数(9,7),因为 9 大于 7 ,所以交换俩数,8个数的次序暂时变为:

3,2,7,9,5,0,8,10;

(4)继续比较第四对数(9,5),因为9 大于 5, 所以交换,8个数的次序暂时变为:

3,2,7,5,9,0,8,10;

(5)继续比较第五对数(9,0),因为9 大于 0, 所以交换,8个数的次序暂时变为:

3,2,7,5,0,9,8,10;

(6)继续比较第六对数(9,8),因为9 大于 8, 所以交换,8个数的次序暂时变为:

3,2,7,5,0,8,9,10;

(6)继续比较第七对数(9,10),因为9 小于 10, 所以交换,8个数的次序暂时变为:

3,2,7,5,0,8,9,10;

经过一次遍历后,910放在的最后。其实冒泡排序经过第一次遍历后,最后一个元素就是数组中最大的元素,第二次遍历后,倒数第二个元素就是数组中第二大的数,而相应的比它们小的数则会慢慢向数组前面移动。

上面是完成一轮遍历的过程,紧接着进行第二轮遍历,第三轮…,因为在第k轮遍历时,不需要考虑最后k-1个元素,因为它们已经排好序了,所以8个数一共进行7轮遍历才可以完成冒泡排序

三.分析

1. 时间复杂度分析(以n个数为例)

最好情况下:

冒泡排序算法只进行一轮遍历就能确定数组已经排好序,不需要进行下一轮遍历,由于第一次遍历的比较次数为 n-1,所以在最好情况下,冒泡排序的时间复杂度为O(n)。

最坏情况下

这种情况下冒泡排序算法需要进行 n-1 轮遍历才可以排序完成,
第一次需要 n-1 次比较;
第二次需要 n-2 次比较;

第n-2 次需要 2 次比较;
第n-1 次需要 1 次比较;
因此,比较的总数为:
(n-1)+ (n-2) + … + 2 + 1
= ((n-1)*n)/2
= ((n^2)-n)/2
= O(n^2)
最坏情况下,冒泡排序的时间复杂度为 O(n^2)

2. 空间复杂度

需要一临时变量来交换两个数,所以空间复杂度为O(1)

3. 稳定性

冒泡排序排序之前两个数如果相等,这两个数在排序的过程中是不会去调换位置的,所以是稳定的。

四. 代码

C++代码:

#include <iostream>
#include <iomanip>
using namespace std;

//待排序元素个数
#define N 8
//函数声明
void Show(int *data, int n);
void BubbleSort(int *data, int n);

//主函数
int main()
{
    //待排序数据
    int data[N]={3,9,2,7,5,0,8,10};
    cout<<"***************排序前的数据为:**************";
    Show(data, N);
    BubbleSort(data, N);
    cout<<"***************排序后的数据为:**************";
    Show(data, N);
    system("pause");
}

//冒泡排序
void BubbleSort(int *data, int n)
{   int temp;
    //第i轮冒泡扫描,共进行n-1轮
    for(int i=n-1; i>0; i--)
    {
        for(int j=0; j<i; j++)
        {
            //若前面数大于后面数,则进行交换
            if(data[j] > data[j+1])
            {
                temp = data[j];
                data[j] = data[j+1];
                data[j+1] = temp;
            }
        }
        cout << "第" << N-i <<"轮遍历后的排序结果为:\t";
        Show(data, N);
    }
}

//输出数组
void Show(int *data, int n)
{
    for(int i=0; i<n; i++)
    {
        cout << setw(3) << data[i];
    }
    cout << endl;
}

运行结果:
这里写图片描述

改进:

我们发现如果在某轮遍历中没有发生任何元素的交换,说明所有的元素都已经排序好了,这种情况下我们是没有必要进行下一次遍历的,如上图运行结果,第6轮其实和第五轮排序后的结果是一样的,第六轮其实根本就没有交换元素,所以在接下来的第七轮我们其实没必要再继续排序了,所以上面的排序算法实现是可以改进的,改进代码如下:

#include <iostream>
#include <iomanip>
using namespace std;

//待排序元素个数
#define N 8

void Show(int *data, int n);
void BubbleSort(int *data, int n);


//主函数
int main()
{
    //待排序数据
    int data[N]={3,9,2,7,5,0,8,10};
    cout<<"***************排序前的数据为:**************" << endl;
    Show(data, N);
    BubbleSort(data, N);
    cout<<"***************排序后的数据为:**************" << endl;
    Show(data, N);
    system("pause");
}

//冒泡排序
void BubbleSort(int *data, int n)
{
    bool isNeedNext = true;
    int temp;
    //第i轮冒泡扫描,共进行n-1轮
    for(int i=n-1; i>0 && isNeedNext; i--)
    {
        isNeedNext = false;
        for(int j=0; j<i; j++)
        {
            //若前面数大于后面数,则进行交换
            if(data[j] > data[j+1])
            {
                temp = data[j];
                data[j] = data[j+1];
                data[j+1] = temp;
                isNeedNext = true;
            }
        }
        cout << "第" <<" "<< N-i <<" "<<"轮遍历后的排序结果为:";
        Show(data, N);
    }
}

//输出数组
void Show(int *data, int n)
{
    for(int i=0; i<n; i++)
    {
        cout << setw(3) << data[i];
    }
    cout << endl;
}

运行结果:
这里写图片描述
第七轮排序是没有进行的,因为第六轮后整个数据已经排序完成了。

如果错误,欢迎指正,谢谢!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值