zoukankan      html  css  js  c++  java
  • 算法分析:什么是冒泡排序?

    2011年,C语言老师给我们讲冒泡排序。

    2014年,听同学说起他面试时和面试官提起冒泡排序。

    2015年,大学本科刚毕业,开始找工作,我还记得我在笔记中写了冒泡排序的代码,结果还真的被问到了。

    2019年,公司首席架构师跟我提到冒泡排序。

    什么是冒泡排序呢?

    冒泡排序,Bubble Sort,通过依次来比较相邻两个元素的大小,在每一次的比较的过程中,两个元素,通过交换来达到有序的目的。

    • 如果一组无序的数列想要从小到大排序,那么两个元素比较,通过交换来实现,左边的元素要比右边的元素要小。
    • 如果一组无序的数列想要从大到小排序,那么两个元素比较,通过交换来实现,左边的元素要比右边的元素要大。

    就像碳酸饮料中的气泡一样,从底部一直冒泡到顶部。

    我想通过一组数据来阐述冒泡排序的过程。

    • 准备一组无序的数列,从小到大依次排序。

    • 开始排序开始。由于6>3,因此两个元素交换。

     

    • 由于6>2,因此两个元素交换。

    • 由于6>1,因此两个元素交换。

    • 由于6<8,因此两个元素不交换。
    • 由于8<9,因此两个元素不交换。
    • 由于9>7,因此两个元素交换。

    • 由于9>5,因此两个元素交换。

    • 第一轮排序结束。此时,元素9处于有序区域。

    • 第二轮排序开始。由于3>2。因此两个元素交换。

    • 由于3>1。因此两个元素交换。

    • 由于3<6。因此两个元素不交换。
    • 由于6<8。因此两个元素不交换。
    • 由于8>7。因此两个元素交换。

    • 由于8>5。因此两个元素交换。

    • 由于8<9。因此两个元素不交换。
    • 第二轮排序结束。此时,元素8和9处于有序区域。

    • 第三轮排序开始。由于2>1。因此两个元素交换。

     

    • 由于2<3。因此两个元素不交换。
    • 由于3<6。因此两个元素不交换。
    • 由于6<7。因此两个元素不交换。
    • 由于7>5,因此两个元素交换。

    • 第三轮排序结束此时,元素7,8和9处于有序区域。

    • 第四轮排序开始。由于1<2。因此两个元素不交换。
    • 由于2<3。因此两个元素不交换。
    • 由于3<6。因此两个元素不交换。
    • 由于6>5。因此两个元素交换。

    • 第四轮排序结束。此时,元素6,7,8,9在有序区域内。

     

    • 第五轮排序开始。由于1<2。因此两个元素不交换。
    • 由于2<3。因此两个元素不交换。
    • 由于3<5。因此两个元素不交换。
    • 第五轮排序结束。此时,元素5,6,7,8,9在有序区域内。
    • 第六轮排序开始。由于1<2。因此两个元素不交换。
    • 由于2<3。因此两个元素不交换。
    • 轮排序结束。此时,元素3,5,6,7,8,9在有序区域内。
    • 第七轮排序开始。由于1<2。因此两个元素不交换。
    • 轮排序结束。此时,元素2,3,5,6,7,8,9在有序区域内。
    • 第八轮排序开始
    • 轮排序结束。此时,元素1,2,3,5,6,7,8,9在有序区域内。可见最后一轮没有必要存在。

    最后我们使用Java代码来展示上述的算法。

     1 private static void sort() {
     2 
     3         Integer[] data = {6,3,2,1,8,9,7,5};
     4 
     5         for(int i=0; i<data.length-1; i++) {
     6 
     7             for(int j=0; j<data.length-i-1; j++) {
     8 
     9                 if(data[j] > data[j+1]) {
    10                     int k = data[j];
    11                     data[j] = data[j+1];
    12                     data[j+1] = k;
    13                 }
    14 
    15             }
    16         }
    17 
    18     }

    从上述的代码以及流程图中。大致的步骤如下:

    1. 定义一组无序数列。
    2. 第一层循环。第一层循环的次数是(元素个数-1)
    3. 第二层循环。第二层循环的次数是无序区域内,元素1和元素2,元素2和元素3...依次两两比较。
    4. 两个元素比较,根据规则确认元素是否需要交换。
    5. 继续第二步。直到循环的次数 = (元素个数-1),结束循环,输出有序数列,结束。

    从以上的现象来看,我们得出结论和思考:

    • 排序的轮数等于元素的个数-1。是否可以较少轮数,上述的例子中实际上在完成第四轮以后已经是一组有序的数列。从上述代码来看,第5行控制的是轮数,而第7行是每一轮中无序区域中元素的两两比较。从本质上来说,我们需要在发现没有元素交换的情况下,就能够说明已经有序,我们需要尽早在21行结束。代码如下所示:
     1 private static void sort() {
     2 
     3         Integer[] data = {6,3,2,1,8,9,7,5};
     4 
     5         for(int i=0; i<data.length-1; i++) {
     6 
     7             boolean isSorted = true;
     8 
     9             for(int j=0; j<data.length-i-1; j++) {
    10 
    11                 if(data[j] > data[j+1]) {
    12                     int k = data[j];
    13                     data[j] = data[j+1];
    14                     data[j+1] = k;
    15 
    16                     isSorted = false;
    17                 }
    18             }
    19 
    20             if(isSorted) {
    21                 break;
    22             }
    23         }
    24 
    25

    从上述的代码和流程图中,如果在第一层的循环中第二次始终没有元素交换,表明数列已经有序,直接输出

    • 完成每一轮,有序区域的元素个数增加1。是否可以冲破每一次有序区域只能增加1的僵局?我们采取在一个大的轮询中,记录最后交换的元素的下标,把这个下标作为无序区域的边界,用来最大提高有序区域元素数量增加的加速度。
     1 private static void sort() {
     2 
     3         Integer[] data = {6,3,2,1,8,9,7,5};
     4 
     5         //最后交换的元素的下标
     6         int lastIndexOfSwap = 0;
     7         //无序数列边界元素的下标
     8         int borderIndexOfUnsort = data.length - 1;
     9 
    10         for(int i=0; i<data.length-1; i++) {
    11 
    12             boolean isSorted = true;
    13 
    14             for(int j=0; j<borderIndexOfUnsort; j++) {
    15 
    16                 if(data[j] > data[j+1]) {
    17                     int k = data[j];
    18                     data[j] = data[j+1];
    19                     data[j+1] = k;
    20 
    21                     isSorted = false;
    22 
    23                     lastIndexOfSwap = j;
    24                 }
    25             }
    26 
    27             borderIndexOfUnsort = lastIndexOfSwap;
    28 
    29             if(isSorted) {
    30                 break;
    31             }
    32 
    33         }
    34 
    35     }

    冒泡排序是最简单的一种排序算法,3个版本演进,也许并没有提高多大的效能,更多应该是对于算法的思维。

  • 相关阅读:
    Django之使用内置函数和celery发邮件
    Django之FBV和CBV的用法
    使用xampp将angular项目运行在web服务器
    Django之使用中间件解决前后端同源策略问题
    Spring cloud Feign 调用端不生效
    进程同步——哲学家进餐问题Java实现
    数据库事务四大特性、隔离级别
    B树 B+树 红黑树
    SpringCloud Config Bus webhook 只能刷新config server 不能刷新config client
    Java8 容器类详解
  • 原文地址:https://www.cnblogs.com/behindyou/p/10567041.html
Copyright © 2011-2022 走看看