重温算法之冒泡排序法

冒泡排序的基本思想是:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换过来。

例如我们需要将12 35 99 18 76 这5 个数进行从大到小的排序。既然是从大到小排序,也就是说越小的越靠后。

首先比较第1 位和第2 位的大小,现在第1 位是12,第2 位是35。发现12 比35 要小,因为我们希望越小越靠后嘛,因此需要交换这两个数的位置。交换之后这5 个数的顺序是35 12 99 18 76。

按照刚才的方法,继续比较第2 位和第3 位的大小,第2 位是12,第3 位是99。12 比99 要小,因此需要交换这两个数的位置。交换之后这5 个数的顺序是35 99 12 18 76。

根据刚才的规则,继续比较第3 位和第4 位的大小,如果第3 位比第4 位小,则交换位置。交换之后这5 个数的顺序是35 99 18 12 76。

最后,比较第4 位和第5 位。4 次比较之后5 个数的顺序是35 99 18 76 12。经过4 次比较后我们发现最小的一个数已经就位(已经在最后一位,请注意12 这个数的移动过程),是不是很神奇。现在再来回忆一下刚才比较的过程。每次都是比较相邻的两个数,如果后面的数比前面的数大,则交换这两个数的位置。一直比较下去直到最后两个数比较完毕后,最小的数就在最后一个了。就如同是一个气泡,一步一步往后“翻滚”,直到最后一位。所以这个排序的方法有一个很好听的名字“冒泡排序”。

说到这里其实我们的排序只将5 个数中最小的一个归位了。每将一个数归位我们将其称为“一趟”。下面我们将继续重复刚才的过程,将剩下的4 个数一一归位。

好,现在开始“第二趟”,目标是将第2 小的数归位。首先还是先比较第1 位和第2 位,如果第1 位比第2 位小,则交换位置。交换之后这5 个数的顺序是99 35 18 76 12。接下来你应该都会了,依次比较第2 位和第3 位,第3 位和第4 位。注意此时已经不需要再比较第4位和第5 位。因为在第一趟结束后已经可以确定第5 位上放的是最小的了。第二趟结束之后这5 个数的顺序是99 35 76 18 12。

“第三趟”也是一样的。第三趟之后这5 个数的顺序是99 76 35 18 12。现在到了最后一趟“第四趟”。有的同学又要问了,这不是已经排好了吗?还要继续?当然,这里纯属巧合,你若用别的数试一试可能就不是了。你能找出这样的数据样例来吗?

请试一试。

“冒泡排序”的原理是:每一趟只能确定将一个数归位。即第一趟只能确定将末位上的数(即第5 位)归位,第二趟只能将倒数第2 位上的数(即第4 位)归位,第三趟只能将倒数第3 位上的数(即第3 位)归位,而现在前面还有两个位置上的数没有归位,因此我们仍然需要进行“第四趟”。“第四趟”只需要比较第1 位和第2 位的大小。因为后面三个位置上的数归位了,现在第1 位是99,第2 位是76,无需交换。这5 个数的顺序不变仍然是99 76 35 18 12。到此排 序完美结束了,5 个数已经有4 个数归位,那最后一个数也只能放在第1 位了。 最后我们总结一下:如果有n 个数进行排序,只需将n1 个数归位,也就是说要进行n-1 趟操作。而“每一趟”都需要从第1 位开始进行相邻两个数的比较,将较小的一个数放在后面,比较完毕后向后挪一位继续比较下面两个相邻数的大小,重复此步骤,直到最后一个尚未归位的数,已经归位的数则无需再进行比较(已经归位的数你还比较个啥,浪费表情)。这个算法是不是很强悍?记得我每次拍集体照的时候就总是被别人换来换去的,当时特别烦。不知道发明此算法的人当时的灵感是否来源于此。啰里吧嗦地说了这么多,下面是代码。建议先自己尝试去实现一下看看,再来看我是如何实现的。

```

public class BubbleSort{

public static void main(String[] args){

int score[] = {67, 69, 75, 87, 89, 90, 99, 100};

for (int i = 0; i < score.length -1; i++){    //最多做n-1趟排序

for(int j = 0 ;j < score.length - i - 1; j++){    //对当前无序区间score[0......length-i-1]进行排序(j的范围很关键,这个范围是在逐步缩小的)

if(score[j] < score[j + 1]){    //把小的值交换到后面

int temp = score[j];

score[j] = score[j + 1];

score[j + 1] = temp;

}

}

System.out.print("第" + (i + 1) + "次排序结果:");

for(int a = 0; a < score.length; a++){

System.out.print(score[a] + "\t");

}

System.out.println("");

}

System.out.print("最终排序结果:");

for(int a = 0; a < score.length; a++){

System.out.print(score[a] + "\t");

}

}

}

```

冒泡排序的核心部分是双重嵌套循环。不难看出冒泡排序的时间复杂度是O(N2)。这是一个非常高的时间复杂度。冒泡排序早在1956 年就有人开始研究,之后有很多人都尝试过对冒泡排序进行改进,但结果却令人失望。如Donald E. Knuth(中文名为高德纳,1974 年图灵奖获得者)所说:“冒泡排序除了它迷人的名字和导致了某些有趣的理论问题这一事实之外,似乎没有什么值得推荐的。”你可能要问:那还有没有更好的排序算法呢?不要走开,请看下节——快速排序。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 简化版的 桶排序 不仅仅有上一节所遗留的问题,更要命的是:它非常浪费空间!例如需要排序数的范围是 0~210000...
    青葱烈马阅读 336评论 0 0
  • 程序其实就是对数据的增删改查 以及对我们所得的数据进行排序。既然涉及到数据的处理就肯定会要牵扯到排序的算法选...
    小鸡在路上阅读 1,211评论 0 4
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,220评论 0 52
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,743评论 0 15
  • 排序的基本概念 在计算机程序开发过程中,经常需要一组数据元素(或记录)按某个关键字进行排序,排序完成的序列可用于快...
    Jack921阅读 1,459评论 1 4