用Scala瞎寫的冒泡排序算法

               

冒泡排序的基本概念

冒泡排序的基本概念是:依次比較相鄰的兩個數,將小數放在前面,大數放在後面,如此繼續直到最後一個數;然後再從頭開始,一直到倒數第二個數;如此循環一直到排序完成。

 

         

稍微想一下

基本概念已經很清楚了,我稍微的想了一下。如果用程序來實現的話,比較直觀的方法就是用for循環。一開始時可以設置一個變量index,讓index=0,也就是每次都從0開始循環,比較index和index+1的值,如果index的值大於index+1的值,就將它們互換,然後讓index++,一直比較到最後兩個值;一輪完成後,再重新讓index爲0,重新從0開始循環,依舊上面的邏輯,只不過這次只循環到倒數第二個值就好了;以此類推。

有了上面的想法,我很直觀的寫出下面的代碼:(這裏沒有Scala代碼框,我就用Java的代替了)

這個代碼可以用來做第一次循環,那麼問題來了:之後的循環怎麼辦?包括我該怎麼控制一輪的循環以及每一輪循環中for循環的上邊界,畢竟每一輪for循環的上邊界都是不同的。

 

            

去掉for循環

網上最推崇的方法是用嵌套for循環的方法,自己對for循環不是很喜歡,更何況for循環嵌套for循環的做法。所以我的想法是去掉for循環。就連上面代碼中的那一層也不要。當然,去掉for用while來代替等於什麼也沒做,因此,我只能用遞歸來做了。

用遞歸的話,我可以把上面的代碼改造一下,把用來控制循環的數組索引變量i作爲方法參數,這樣我可以在遞歸調用方法時,每次把索引i加1作爲參數來代替for循環。

OK,改造完就是下面的代碼:

但是我還是沒有解決上面的問題:之後的循環該怎麼辦?

            

還是先重構吧

雖然我還沒想明白之後的循環怎麼辦,不過至少上面的這個代碼做第一次循環已經夠了。先重構一下,把那個index的判斷換成case方式:

至少我看着舒服了,繼續。

                  

回到冒泡排序的概念上

我現在的遞歸每次都要到數組的最後一個元素。按照冒泡排序的概念,從第二輪開始就不需要再看最後一個元素了。這也就是說,每一輪遞歸下來,需要排序的元素都會少一個。這樣的話,我們最後一輪遞歸的就只是數組的頭兩個元素。

這麼來看,上面的兩個問題就好解決了。我可以再引入一個變量lastIndex,排序開始的時候讓它等於數組的最後一個索引值,每遞歸完一輪把lastIndex減1,這樣就可以用它來告訴程序這次應該遞歸到哪個元素;另外還可以用它來指示我們什麼時候完成排序——就是當lastIndex等於我們數組第二個元素的索引時。

由此看來,這個lastIndex最好作爲實例變量,獨立於方法之外,這樣可以在調用方法之前初始化它,並且在每一輪遞歸完成時將它的值減1。

 

                      

需要一個單獨的類了

從上面分析來看,我應該創建一個新的類出來了。另外我還發現一個問題,sort方法的參數會很讓人費解。現在我自己編寫沒關係,但是如果給別人用呢?作爲排序算法,我們最直觀的用法是這樣:

或者

現在我的方法第一個參數是一個不倫不類、讓人費解的Int類型,這個必須得改掉。

上面的兩個用法,第一個適合寫一個幫助類,不過這個讓我想到Java裏的一大堆static方法,捨棄不要。

採用第二種方式,需要我創建一個新的類型,裏面包裝我的sort方法,這個簡單:

這上面做了一些改動,當程序遞歸到lastIndex的位置時,判斷一下此時lastIndex是否在第二個元素索引上,如果在的話我們就排序完了,如果不在,就需要把lastIndex減1,並且啓動新一輪的遞歸。

這下看着明瞭多了,對於使用者只要調用bubbleSort就可以。

 

                   

不行,還有雜念

首先,這個類只能用來排序Int類型的數組,那麼其它的類型呢?比如String數組。

另外,如果我想用這個類排序,每次還需要new一個對象,太麻煩了,我只是想排序而已。

對於第一個問題,使用泛型就好了。我們可以把類定義變成這樣:

這裏使用了Scala的View Bound,這樣可以讓Scala的編譯器把你的T看成是可以變爲Ordered[T]的類型。爲什麼這麼做呢,首先我在程序裏需要比較兩個T類型,而Ordered[T]提供了我需要的>方法。其次,我能夠想到的需要排序的類型如Int,Long,Double等都有對應的Ordered類型下的子類型,Int對應RichInt,Long對應RichLong等。所以我在這裏選擇Ordered類型。

好了,第一個問題解決了,第二個問題也不復雜,只要我提供一個implicit轉換就可以:

OK,這樣就全部解決了。

 

 

                      

雜念,玩兒蛋去吧

最後還有一個問題。比如有一個比較大的數組,程序進行一輪又一輪的遞歸的時候,如果在途中就排序完成了,程序就不需要等到lastIndex一直減到數組第二個元素才停,只要在這一輪的遞歸中沒有發現調用swap方法,就說明沒有亂序的排列了,此時程序就應該停止繼續遞歸下去——因爲排序完成了。

按照這個分析的話,我可以加入一個notFinish變量,一旦在這一輪遞歸中調用到swap方法了,notFinish就是true,否則就是false。

下面就是修改後的完整代碼:

下面是測試代碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章