神的规范:排序算法(三):冒泡排序

写在前面:
排序又称为分类,它是数据处理中经常用到的一种重要运算。
虽然并未列入世界最伟大的几大算法之一,但毫无疑问,在各行各业的各个时期排序都是作为奠基者般的存在为程序所调用,也为编程者所敬仰。只是,也许正是因为它与我们息息相关,以至于我们竟然时常忽略它的存在。
事实上我们生活中无时无刻不在做排序:考试成绩排名,按身高、年龄、能力高低去评判他人,划分任务处理的优先级,等等·······
前面2篇博客我们讨论了简单插入排序和简单选择排序算法,而今天我们进入“冒泡排序”的学习,一步步去探索排序算法如何在反思中前进,在山重水复处柳暗花明。

所谓冒泡排序,还是非常容易理解的,就是在每一次排序过程中,我们让最大的(最小的)那个元素逐渐冒泡到最后的(最前的)位置。关键是,该如何实现呢?这样做又有什么好处呢?
冒泡排序的基本思想是(以最大冒泡为例):针对{R1,R2,…Rn}的无序数据元素集合,从R1开始,两两比较Ri和R(i+1),若前者大于后者,则交换两者数据元素(即互换位置)。第一次全部比较完之后,Rn为序列中最大的数据元素。以此类推,第二次比较完后,R(n-1)是除Rn之外最大的数据元素。
但是有一点需要注意,就是在冒泡排序算法中,我们有必要全部都比较完吗(最坏情况下确实需要如此)?
不一定,如果经历了第i趟排序后,整个序列已然有序,那后面岂不都做了无用功!为了避免浪费资源,我们立下flag(当然不是那个flag啦),用来标志某一趟比较是否空跑(即只比较不移动)。这一点将在下面的算法代码描述中加以体现。
那么现在我们用C语言来明确描述一下我们的冒泡排序算法(以double型数据为例):

void bubblesort(double a[],int n) {
    int i,j,flag = 1;                   //flag is used to label if the sequence is already ordered
    double swap;
    for (i = 0;i < n-1 && flag == 1;i++) {  //Two conditions
        flag = 0;                          //Set flag in every i loop
        for (j = 0;j < n-i-1;j++) {        //Note it cannot be written as "j < n-i" for the reason that a[n] does not exsit
            if (a[j] > a[j+1]) {          //swap data
                swap = a[j+1];
                a[j+1] = a[j];
                a[j] = swap;
                flag = 1;
            }
        }
        if (flag == 0)             //if ordered,then return
            return;
    }
}

代码的思想还是比较清晰的,只是i,j的边界的处理要非常小心,因为很容易出现数组访问越界的情况。
为证明其可用性,截图如下以证清白:
这里写图片描述

接下来,我们感兴趣的地方是,看来简单选择、简单插入、冒泡排序都可以实现排序,那么它们谁的效率更高,性能更优呢?
其实这是个仁者见仁智者见智的问题(这不相当于没说么。。。),我们在同等条件下,跑三个大型范例(用随机数),测试其花费时间的多少:
数据量10000时:
这里写图片描述
数据量20000时:
这里写图片描述
数据量40000时:
这里写图片描述
是不是很震撼!
是不是很遗憾?
咱们都琢磨到第三篇了,怎么这个冒泡排序算法还是这么慢?
诸位莫急。其实直观来讲,冒泡排序算法比较慢是非常正常的,因为它很可能伴随着大量的数据交换。但是问题来了:性能最佳的插入排序还可能伴随着大量的数据移动呢!
但是想想这么个道理:移动数据一条指令足以,但是交换数据可是要三条指令啊。加上冒泡排序里有个时而鸡肋的flag,平均效率低于插入排序实在是太正常了。
那么冒泡排序就没有有点了么?当然不是!当元素序列一开始已经非常有序时,它的速度就会非常快!基本上空跑一趟flag知道白跑了,马上就可以返回。在某些场合冒泡排序还是有它的优势的,然而,我并没看到谁会主张用冒泡排序。。。

因为下一篇,我们会引入一个排序界的小天王——快速排序。
快排,听名字就知道实力很强!
那么关于冒泡排序的分享,就到此为止,下次再会啦!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值