演算法2 鄰居好說話 氣泡排序

2022-05-05 00:51:12 字數 3077 閱讀 6741

簡化版的桶排序不僅僅有上一節所遺留的問題,更要命的是:它非常浪費空間!例如需要排序數的範圍是 0~2100000000 之間,那你則需要申請 2100000001 個變數,也就是說要寫成 int a[2100000001]。因為我們需要用 2100000001 個「桶」來儲存 0~2100000000 之間每乙個數出現的次數。即便只給你 5 個數進行排序(例如這 5 個數是 1,1912345678,2100000000,18000000 和 912345678),你也仍然需要 2100000001 個「桶」,這真是太浪費了空間了!還有,如果現在需要排序的不再是整數而是一些小數,比如將 5.56789,2.12,1.1,3.123,4.1234 這五個數進行從小大排序又該怎麼辦呢?現在我們來學習另一種新的排序演算法:氣泡排序。它可以很好的解決這兩個問題。

氣泡排序的基本思想是:每次比較兩個相鄰的元素,如果他們的順序錯誤就把他們交換過來。

例如我們需要將 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 位開始進行相鄰兩個數的比較,將較小的乙個數放在後面,比較完畢後向後挪一位繼續比較下面兩個相鄰數的大小,重複此步驟,直到最後乙個尚未歸位的數,已經歸位的數則無需再進行比較(已經歸位的數你還比較個啥,浪費表情)。

這個演算法是不是很強悍。記得我每次拍集體照的時候就總是被別人換來換去的,當時特別煩。不知道發明此演算法的人當時的靈感是否**於此。羅里吧嗦地說了這麼多,下面是**。建議先自己嘗試去實現一下看看,再來看我是如何實現的。

#include int main()

;//這裡建立了乙個結構體用來儲存姓名和分數

int main()

{struct student a[100],t;

int i,j,n;

scanf("%d",&n); //輸入乙個數n

for(i=1;i<=n;i++) //迴圈讀入n個人名和分數

scanf("%s %d",a[i].name,&a[i].score);

//按分數從高到低進行排序

for(i=1;i<=n-1;i++)

{for(j=1;j<=n-i;j++)

{if(a[j].score可以輸入以下資料進行驗證

5huhu 5

haha 3

xixi 5

hengheng 2

gaoshou 8

執行結果是

gaoshou

huhu

xixi

haha

hengheng

氣泡排序的核心部分是雙重巢狀迴圈。不難看出氣泡排序的時間複雜度是 o(n2)。這是乙個非常高的時間複雜度。氣泡排序早在 1956 年就有人開始研究,之後有很多人都嘗試過對氣泡排序進行改進,但結果卻令人失望。如 knuth(donald e. knuth 中文名為高德納,1974 年圖靈獎獲得者)所說:「氣泡排序除了它迷人的名字和導致了某些有趣的理論問題這一事實之外,似乎沒有什麼值得推薦的。」你可能要問:那還有沒有更好的排序演算法呢?請期待下週更新——快速排序。

鄰居好說話 氣泡排序

簡化版的桶排序不僅僅有上一節所遺留的問題,更要命的是 它非常浪費空間!例如需要排序數的範圍是0 2100000000之間,那你則需要申請2100000001個變數,也就是說要寫成int a 2100000001 因為我們需要用2100000001個 桶 來儲存0 2100000000之間每乙個數出現...

鄰居好說話 氣泡排序

氣泡排序的基本思想是 每次比較兩個相鄰的元素,如果它們的順序錯誤就把它們交換過來。如下 include intmain for i 1 i n i 輸出結果 printf d a i return0 現在分別有5個人的名字 和分數 huhu 5分 haha 3分 xixi 5分 hengheng 2...

鄰居好說話 氣泡排序

簡化版的桶排序不僅僅有上一節所遺留的問題,更要命的是 它非常浪費空間!例如需要排序數的範圍是0 2100000000之間,那你則需要申請 2100000001個變數,也就是說要寫成int a 2100000001 因為我們需要用2100000001個 桶 來儲存0 2100000000之間每乙個數出...