最快最簡單的排序——桶排序
在我們生活的這個世界中到處都是被排序過的。站隊的時候會按照身高排序,考試的名次需要按照分數排序,網上購物的時候會按照**排序,電子郵箱中的郵件按照時間排序……總之很多東西都需要排序,可以說排序是無處不在。現在我們舉個具體的例子來介紹一下排序演算法。
首先出場的我們的主人公小哼,上面這個可愛的娃就是啦。期末考試完了老師要將同學們的分數按照從高到低排序。小哼的班上只有5個同學,這5個同學分別考了5分、3分、5分、2分和8分,哎考的真是慘不忍睹(滿分是10分)。接下來將分數進行從大到小排序,排序後是8 5 5 3 2。你有沒有什麼好方法編寫一段程式,讓計算機隨機讀入5個數然後將這5個數從大到小輸出?請先想一想,至少想15分鐘再往下看吧(*^__^*) 。
我們這裡只需借助乙個一維陣列就可以解決這個問題。請確定你真的仔細想過再往下看哦。
首先我們需要申請乙個大小為11的陣列int a[11]。ok現在你已經有了11個變數,編號從a[0]~a[10]。剛開始的時候,我們將a[0]~a[10]都初始化為0,表示這些分數還都沒有人得過。例如a[0]等於0就表示目前還沒有人得過0分,同理a[1]等於0就表示目前還沒有人得過1分……a[10]等於0就表示目前還沒有人得過10分。
下面開始處理每乙個人的分數,第乙個人的分數是5分,我們就將相對應a[5]的值在原來的基礎增加1,即將a[5]的值從0改為1,表示5分出現過了一次。
第二個人的分數是3分,我們就把相對應a[3]的值在原來的基礎上增加1,即將a[3]的值從0改為1,表示3分出現過了一次。
注意啦!第三個人的分數也是「5分」,所以a[5]的值需要在此基礎上再增加1,即將a[5]的值從1改為2。表示5分出現過了兩次。
按照剛才的方法處理第四個和第五個人的分數。最終結果就是下面這個圖啦。
你發現沒有,a[0]~a[10]中的數值其實就是0分到10分每個分數出現的次數。接下來,我們只需要將出現過的分數列印出來就可以了,出現幾次就列印幾次,具體如下。
a[0]為0,表示「0」沒有出現過,不列印。
a[1]為0,表示「1」沒有出現過,不列印。
a[2]為1,表示「2」出現過1次,列印2。
a[3]為1,表示「3」出現過1次,列印3。
a[4]為0,表示「4」沒有出現過,不列印。
a[5]為2,表示「5」出現過2次,列印5 5。
a[6]為0,表示「6」沒有出現過,不列印。
a[7]為0,表示「7」沒有出現過,不列印。
a[8]為1,表示「8」出現過1次,列印8。
a[9]為0,表示「9」沒有出現過,不列印。
a[10]為0,表示「10」沒有出現過,不列印。
最終螢幕輸出「2 3 5 5 8」,完整的**如下。
#include int main()
for(i=0;i<=10;i++) //依次判斷a[0]~a[10]
for(j=1;j<=a[i];j++) //出現了幾次就列印幾次
printf("%d ",i);
getchar();getchar();
//這裡的getchar();用來暫停程式,以便檢視程式輸出的內容
//也可以用system("pause");等來代替
return 0;
}
輸入資料為
5 3 5 2 8仔細觀察的同學會發現,剛才實現的是從小到大排序。但是我們要求是從大到小排序,這該怎麼辦呢?還是先自己想一想再往下看哦。
其實很簡單。只需要將for(i=0;i<=10;i++)改為for(i=10;i>=0;i--)就ok啦,快去試一試吧。
這種排序方法我們暫且叫他「桶排序」。因為其實真正的桶排序要比這個複雜一些,以後再詳細討論,目前此演算法已經能夠滿足我們的需求了。
這個演算法就好比有11個桶,編號從0~10。每出現乙個數,就將對應編號的桶中的放乙個小旗子,最後只要數數每個桶中有幾個小旗子就ok了。例如2號桶中有1個小旗子,表示2出現了一次;3號桶中有1個小旗子,表示3出現了一次;5號桶中有2個小旗子,表示5出現了兩次;8號桶中有1個小旗子,表示8出現了一次。
現在你可以請嘗試一下輸入n個0~1000之間的整數,將他們從大到小排序。提醒一下如果需要對資料範圍在0~1000之間的整數進行排序,我們需要1001個桶,來表示0~1000之間每乙個數出現的次數,這一點一定要注意。另外此處的每乙個桶的作用其實就是「標記」每個數出現的次數,因此我喜歡將之前的陣列a換個更貼切的名字book(book這個單詞有記錄、標記的意思),**實現如下。
#include int main()
for(i=1000;i>=0;i--) //依次判斷編號1000~0的桶
for(j=1;j<=book[i];j++) //出現了幾次就將桶的編號列印幾次
printf("%d ",i);
getchar();getchar();
return 0;
}
可以輸入以下資料進行驗證
10執行結果是8 100 50 22 15 6 1 1000 999 0
1000 999 100 50 22 15 8 6 1 0最後來說下時間複雜度的問題。**中第6行的迴圈一共迴圈了m次(m為桶的個數),第9行的**迴圈了n次(n為待排序數的個數),第14和15行一共迴圈了m+n次。所以整個排序演算法一共執行了m+n+m+n次。我們用大寫字母o來表示時間複雜度,因此該演算法的時間複雜度是o(m+n+m+n)即o(2*(m+n))。我們在說時間複雜度時候可以忽略較小的常數,最終桶排序的時間複雜度為o(m+n)。還有一點,在表示時間複雜度的時候,n和m通常用大寫字母即o(m+n)。
這是乙個非常快的排序演算法。桶排序從2023年就開始被使用,該演算法的基本思想是由e.j.issac r.c.singleton提出來。之前說過,其實這並不是真正的桶排序演算法,真正的桶排序演算法要比這個更加複雜。但是考慮到此處是演算法講解的第一篇,我想還是越簡單易懂越好,真正的桶排序留在以後再聊吧。需要說明一點的是:我們目前學習的簡化版桶排序演算法其本質上還不能算是乙個真正意義上的排序演算法。為什麼呢?例如遇到下面這個例子就沒轍了。
現在分別有5個人的名字和分數:huhu 5分、haha 3分、xixi 5分、hengheng 2分和gaoshou 8分。請按照分數從高到低,輸出他們的名字。即應該輸出gaoshou、huhu、xixi、haha、hengheng。發現問題了沒有?如果使用我們剛才簡化版的桶排序演算法僅僅是把分數進行了排序。最終輸出的也僅僅是分數,但沒有對人本身進行排序。也就是說,我們現在並不知道排序後的分數原本對應著哪乙個人!這該怎麼辦呢?
排序演算法 白話經典排序演算法
1.白話經典演算法系列之一 氣泡排序的三種實現 2.白話經典演算法系列之二 直接插入排序的三種實現 3.白話經典演算法系列之三 希爾排序的實現 4.白話經典演算法系列之四 直接選擇排序及交換二個資料的正確實現 5.白話經典演算法系列之五 歸併排序的實現 6.白話經典演算法系列之六 快速排序 快速搞定...
經典排序演算法 桶排序Bucket sort
經典排序演算法 桶排序bucket sort 補充說明三點 1,桶排序是穩定的 2,桶排序是常見排序裡最快的一種,比快排還要快 大多數情況下 3,桶排序非常快,但是同時也非常耗空間,基本上是最耗空間的一種排序演算法 我自己的理解哈,可能與網上說的有一些出入,大體都是同樣的原理 無序陣列有個要求,就是...
經典排序演算法 桶排序Bucket sort
經典排序演算法 桶排序bucket sort 補充說明三點 1,桶排序是穩定的 2,桶排序是常見排序裡最快的一種,比快排還要快 大多數情況下 3,桶排序非常快,但是同時也非常耗空間,基本上是最耗空間的一種排序演算法 我自己的理解哈,可能與網上說的有一些出入,大體都是同樣的原理 無序陣列有個要求,就是...