為什麼雙層迴圈 氣泡排序 一看就懂的氣泡排序

2021-10-14 12:10:25 字數 3122 閱讀 5793

氣泡排序應該是最經典的排序演算法了,想起上大學的時候, 老師對氣泡排序就花了一節課重點講解,面試中也最喜歡讓手擼乙個氣泡排序。另外據說歐巴馬也寫過氣泡排序。所以身為程式設計師的你,還有什麼理由不去掌握它呢,要學會各類排序,就從氣泡排序開始吧。

氣泡排序(英語:bubble sort)是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越小的元素會經由交換慢慢「浮」到數列的頂端。

氣泡排序分「從大到小」「從小到大」兩種排序方式。它們的唯一區別就是兩個數交換的條件不同,從大到小排序是前面的數比後面的小的時候交換,而從小到大排序是前面的數比後面的數大的時候交換。「在下面我們只講從小到大的排序方式。」

「氣泡排序的原理:」從第乙個數開始,依次往後比較,如果前面的數比後面的數大就交換,否則不作處理。這就類似燒開水時,壺底的水泡往上冒的過程。

如果排列的陣列為:[52, 23, 18, 84, 58, 11], 那麼整個排序過程將如下示:

現在有一堆亂序的數,比如:[52, 23, 18, 84, 58, 11]

第一輪迭代:從第乙個數開始,依次比較相鄰的兩個數,如果前面乙個數比後面乙個數大,那麼交換位置,直到處理到最後乙個數,最後的這個數是最大的。

第二輪迭代:因為最後乙個數已經是最大了,現在重複第一輪迭代的操作,但是只處理到倒數第二個數。

第三輪迭代:因為最後乙個數已經是最大了,最後第二個數是次大的,現在重複第一輪迭代的操作,但是只處理到倒數第三個數。

第n輪迭代:....

經過交換,最後的結果為:[11, 18, 23, 52, 58, 84],我們可以看到已經排好序了。

因為小的元素會慢慢地浮到頂端,很像碳酸飲料的汽泡,會冒上去,所以這就是氣泡排序取名的**。

經過上面一堆的各種圖示和文字講解,是否已經躍躍欲試了,先不急著往下看, 可以先自己動手去實現一下,然後再對照著看一下。這裡我們採用golang語言實現一下(實現語言不重要,關鍵是思想)。

「按冒泡的思想,初步具體實現:」可以用雙層迴圈, 外層用來控制內層迴圈中最值上浮的位置, 內層用來進行兩兩比較和交換位置.

實現**如下示:

package sort

// 冒泡公升序排序

func bubbulesortasc(array int) }}

}

但我們會發現針對一些情況,我們的演算法還可以做進一步的優化。

假設我們有一組資料:[1, 2, 3, 5, 4, 6] 經過一輪冒泡陣列已經變為:[1, 2, 3, 4, 5, 6], 此時陣列已經是有序的了,但是按照我們上面的演算法,此時我們還需要繼續進行往下一輪一輪的比對,雖然這個時候只有比較操作而沒有交換操作, 但這些比較操作仍然是沒有必要的.

「利用上面的原理, 可以對經典實現進行改進」: 裡面一層迴圈在某次掃瞄中沒有執行交換,則說明此時陣列已經全部有序列,無需再掃瞄了。設定乙個標記位來標記此次遍歷是否發生了交換,如果沒有發生交換說明已經完成排序;

改版**如下示:

package sort

// 冒泡公升序排序

func bubbulesortasc(array int) 

}if endflag }}

若陣列是區域性有序的, 例如從某個位置開始之後的陣列已經有序, 則沒有必要對這一部分陣列進行比較了.

「此時的改進方法是:」在遍歷過程中可以記下最後一次發生交換事件的位置, 下次的內層迴圈就到這個位置終止, 可以節約多餘的比較操作.

使用乙個變數來儲存最後乙個發生了交換操作的位置, 並設定為下一輪內層迴圈的終止位置:

實現**如下示:

package sort

// 冒泡公升序排序

func bubbulesortasc(array int) 

}if lastswap == lastswaptemp }}

將思想1和2結合起來, 處理陣列區域性有序和排序過程中整體有序的情況,**也很容易實現, 如下示:

package main

// 冒泡公升序排序

func bubbulesortasc(array int) 

}if lastswap == lastswaptemp 

if endflag }}

其外層迴圈執行 n - 1次。內層迴圈最多的時候執行n次,最少的時候執行1次,平均執行 (n+1)/2次。

所以迴圈體內的比較交換約執行 (n - 1)(n + 1) / 2 = (n^2 - 1)/2(其中n^2是仿照latex中的記法,表示n的平方)。按照計算複雜度的原則,去掉常數,去掉最高項係數,其複雜度為o(n^2)。

按照改進的演算法,對於乙個已經有序的陣列,演算法完成第一次外層迴圈後就會返回。

實際上只發生了 n - 1次比較,所以最好的情況下,該演算法複雜度是o(n)。

通俗地講就是能保證排序前「2個相等的數」其在序列的前後位置順序和排序後它們兩個的前後位置順序相同。在簡單形式化一下,「如果ai = aj,ai原來在位置前,排序後ai還是要在aj位置前。」氣泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,「如果兩個元素相等,我想你是不會再無聊地把他們倆交換一下的」;如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改變,所以氣泡排序是一種穩定排序演算法

氣泡排序效率是及其低下的, 我們主要是要去學習它的思想, 而在實際工作中,一般很少用如此慢的排序演算法。

一看就懂的氣泡排序

不用走啦,看得懂的啦!相鄰兩個數比較大小,較大的下沉 較小的上浮。從第乙個數開始,比較第乙個數和第二個數大小,如果第乙個數比第二個數大,則交換兩個數的位置,使大的數排在後面,依次比較第二個數和第三個數,使第三個數比第二和第乙個數大,直到倒數兩個數,將最大的數移動到最後一位。演算法分為兩個迴圈 1.外...

一看就懂的快速排序

快速排序屬於交換排序,主要步驟是使用基準元素進行比較,把小於基準元素的移動到一邊,大於基準元素的移動到另一邊。從而把陣列分成兩部分,然後再從這兩部分中選取出基準元素,重複上面的步驟。過程如下 紫色 基準元素 綠色 大於基準元素 黃色 小於基準元素 這種思路叫做分治法。基準元素的選取可隨機選取。下面使...

一看就懂的SwitchHosts

switchhosts 是乙個管理 切換多個 hosts 方案的工具。它是乙個免費開源軟體。日常開發工作中,我們可能經常需要切換各種 hosts 繫結,比如在本地開發時可能需要乙個開發環境的 hosts 繫結方案,發布到測試環境後又有乙個測試環境的 hosts 繫結方案,然後可能還有乙個預發布環境,...