1. 程式人生 > >看動畫學演算法之:排序-氣泡排序

看動畫學演算法之:排序-氣泡排序

[toc] # 簡介 排序可能是所有的演算法中最最基礎和最最常用的了。排序是一個非常經典的問題,它以一定的順序對一個數組(或一個列表)中的項進行重新排序。 排序演算法有很多種,每個都有其自身的優點和侷限性。 今天我們來學習最最簡單的氣泡排序演算法。 # 氣泡排序的原理 氣泡排序的原理很簡單,我們想象一下一個一個的氣泡上浮的過程。 假設我們有八個數字 29,10,14,37,20,25,44,15 要進行排序。 我們先用一個動畫圖來直觀的觀察一下整個氣泡排序的過程: ![](https://img-blog.csdnimg.cn/20200708155735461.gif) 排序共進行八輪,每一輪都會做兩兩比較,並將較大的元素右移,就像冒泡一下。 一輪結束之後,八個元素中最大的那個元素44將會移動到最右邊。 然後再重複其他的幾輪。最終得到一個完全排序的陣列。 也可以這樣看: 第一輪是將八個元素中的最大值44交換移動到最右位置。 第二輪是將八個元素中的次大值37交換移動到最右位置。 以此類推。 # 氣泡排序演算法的java實現 我們先看一個最簡單的冒泡演算法: ~~~java public class BubbleSort { public void doBubbleSort(int[] array){ log.info("排序前的陣列為:{}",array); //外層迴圈,遍歷所有輪數 for(int i=0; i< array.length-1; i++){ //內層迴圈,兩兩比較,選中較大的數字,進行交換 for(int j=0; jarray[j+1]){ //交換兩個數字 int temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } log.info("第{}輪排序後的陣列為:{}", i+1, array); } } public static void main(String[] args) { int[] array= {29,10,14,37,20,25,44,15}; BubbleSort bubbleSort=new BubbleSort(); bubbleSort.doBubbleSort(array); } } ~~~ 這個演算法就是兩層遍歷,外層遍歷表示的是進行的輪數。內層遍歷表示的是每一輪的排序。 我們看下輸出結果: ![](https://img-blog.csdnimg.cn/2020070816421585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_30,color_8F8F8F,t_70) # 冒泡演算法的第一次改進 分析上面的遍歷過程,我們可以發現,第一次排序之後,44已經放到最右邊的位置了,已經排好序了。 第二次排序之後,37也已經排好序了。每過一輪,內部迴圈需要比較的次數就可以減一。 這就意味著,在內部迴圈的時候,我們只需要進行array.length-i-1次比較就可以了。 修改程式碼如下: ~~~java public class BubbleSort1 { public void doBubbleSort(int[] array){ log.info("排序前的陣列為:{}",array); //外層迴圈,遍歷所有輪數 for(int i=0; i< array.length-1; i++){ //內層迴圈,兩兩比較,選中較大的數字,進行交換, 最後的i個數字已經排完序了,不需要再進行比較 for(int j=0; jarray[j+1]){ //交換兩個數字 int temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } log.info("第{}輪排序後的陣列為:{}", i+1, array); } } public static void main(String[] args) { int[] array= {29,10,14,37,20,25,44,15}; BubbleSort1 bubbleSort=new BubbleSort1(); bubbleSort.doBubbleSort(array); } } ~~~ 執行結果: ![](https://img-blog.csdnimg.cn/20200708164629451.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_30,color_8F8F8F,t_70) 可以看到執行結果其實沒什麼不同,只不過我們少做了幾次比較。 # 冒泡演算法的第二次改進 從上面的結果,我們可以看到實際上第5輪排序過後就已經排序完成了。但是我們仍然進行了第6,7次排序。 有沒有什麼辦法可以判斷排序是不是已經完成了呢? 我們考慮一下,在內部迴圈中,我們是進行兩兩比較,然後交換位置。 如果在某一次遍歷中,沒有進行互動,這就意味著排序已經完成了。 所以我們可以再引入一個flag來做判斷。 ~~~java public class BubbleSort2 { public void doBubbleSort(int[] array){ log.info("排序前的陣列為:{}",array); //外層迴圈,遍歷所有輪數 for(int i=0; i< array.length-1; i++){ //新增一個flag,如果這一輪都沒有排序,說明排序已經結束,可以提前退出 boolean flag=false; //內層迴圈,兩兩比較,選中較大的數字,進行交換, 最後的i個數字已經排完序了,不需要再進行比較 for(int j=0; jarray[j+1]){ //交換兩個數字 int temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; flag = true; } } log.info("第{}輪排序後的陣列為:{}", i+1, array); if(!flag) { log.info("本輪未發生排序變化,排序結束"); return; } } } public static void main(String[] args) { int[] array= {29,10,14,37,20,25,44,15}; BubbleSort2 bubbleSort=new BubbleSort2(); bubbleSort.doBubbleSort(array); } } ~~~ 執行結果如下: ![](https://img-blog.csdnimg.cn/20200708165143914.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_30,color_8F8F8F,t_70) 從結果我們可以看到少了一輪排序,提升了速度。 # 氣泡排序的時間複雜度 雖然我們可以在冒泡的時候進行一些效能優化,但是基本上還是要進行巢狀的兩次遍歷。遍歷次數近似的=n*n,所以氣泡排序演算法的時間複雜度是O(n²)。 本文的程式碼地址: [learn-algorithm](https://github.com/ddean2009/learn-algorithm/tree/master/sorting) > 本文已收錄於 [http://www.flydean.com/algorithm-bubble-sort/](http://www.flydean.com/algorithm-bubble-sort/) > > 最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現! > > 歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你! ![](https://img-blog.csdnimg.cn/20200709152618916.png)