用最土的方式把细节剖给你看——冒泡排序算法的 Java 实现版
说到算法,很多人都会害怕。但是想升职加薪怎么办呢?
总是逃避是改变不了什么,也解决不了什么问题。我不希望自己以后一直被这些算法堵住,但同时也不强求一下子掌握优雅的实现算法。
一点一点地吃透它。
冒泡排序的概念:
不断的比较相邻的元素,如果顺序不对,就交换。 一轮又一轮,直到所有相邻的元素都比较完,是一种非常朴素的排序方法。
摆平心态放大招
import java.util.Arrays; public class 冒泡算法 { // 优化点:挨个比较了一圈,没有交换,说明已经排好了;已经有序的不要去交换了 public static void main(String[] args) { int[] values = {3, 1, 6, 2, 9, 0, 7, 4, 5, 8}; bubbleSort(values); System.out.println(Arrays.toString(values)); } private static void bubbleSort(int[] values) { int temp; for (int i=0; i<values.length; i++) { for (int j = 0; j<values.length-1-i; j++) { if (values[j] > values[j+1]) { // 这一行决定了是从小到大,还是从大到小 temp = values[j]; values[j] = values[j+1]; values[j+1] = temp; } System.out.println(i + ": " + Arrays.toString(values)); } System.out.println(); } } } 复制代码
我手敲了基础实现版后,还加了很多 print,把过程复现,然后理解程序的每一句话实现了什么,改变了什么,就会更容易理解一些。
核心实现部分,嵌套循环,挨个比较:
这一行可以看到 values[j]
和 values[j+1]
分别是前一个元素和后一个元素。我文章里用的是前一个大于后一个的话,就交换,也就是把前一个元素往后堆,循环这个过程,就很像泡泡。一个一个这样冒到最后。
最后的排序结果:
这里 j 的上界没有取 values.length, 就是因为每次冒过去,最大值已经排到最后了。
我们来仔细看看,每个循环内做了什么样的事情:
第一个循环:
第一个循环,一共 0-9,10个元素,两两比较,比较 9 次。
第二个循环,最后两个肯定比较好了,少一次比较:
第三个循环:
第四个循环:
第五 ~ 第九个循环:
也就是这个时候,你是不是明白了,为什么那么多调优文章都说,有重复的了吧?
到这里看起来已经非常棒了,上面我们已经对冒泡的次数,以及每次冒泡需要比较的次数都做了优化,但这就够了嘛,不 我们还可以对比较的次数做进一步的优化,每轮冒泡时,最后一次交换的索引可以作为下一轮冒泡比较的次数,如果这个值是 0, 就证明整个数组有序,直接退出外层循环即可。「非正经程序员 juejin.cn/post/701632… 」
优化了!
上面的截图已经很清楚地表现了代码可以优化的地方:
让这个循环在有序的情况下别比较了。
private static void bubbleSort(int[] values) { int temp; for (int i=0; i<values.length; i++) { boolean flag = true; for (int j = 0; j<values.length-1-i; j++) { if (values[j] > values[j+1]) { temp = values[j]; values[j] = values[j+1]; values[j+1] = temp; // 发生交换了,就改变,数组在这一趟是无序的,还要接着比较 flag = false; } System.out.println(i + ": " + Arrays.toString(values)); } // 内循环都跑完了,flag 还是 true,说明已经有序了,后面不用再比较了 if (flag) { break; } System.out.println(); } } 复制代码
我们是通过新增了一个布尔变量实现的:
重新跑一次以后发现,前面的循环和之前都一样,不同的是排好序以后,就不再进行多余的比较了:
作者:小小匚
链接:https://juejin.cn/post/7018198518343041061