Swift實現的快速排序及sorted方法的對比,swiftsorted

來源:互聯網
上載者:User

Swift實現的快速排序及sorted方法的對比,swiftsorted

Swift語言有著優秀的函數式編程能力,面試的時候面試官都喜歡問我們快速排序,那麼用Swift如何?一個快速排序呢?首先擴充Array類:

extension Array {    var decompose : (head: T, tail: [T])? {        return (count > 0) ? (self[0], Array(self[1..<count])) : nil    }}

屬性decompose的作用是返回數組中的第一個元素和剩下的元素,注意這個屬性是可選型的,當count為0的時候返回nil,count是Array的屬性。使用擴充的原因是這種拆分可以實現非常多的操作,一勞永逸。
然後實現快速排序的方法:

func qsortDemo(input: [Int]) -> [Int] {    if let (pivot, rest) = input.decompose {        let lesser = rest.filter { $0 < pivot }        let greater = rest.filter { $0 >= pivot }        return qsortDemo(lesser) + [pivot] + qsortDemo(greater)    } else {        return []    }}

可以發現使用Swift實現快速排序的代碼非常的簡潔。首先調用待排序序列的decompose屬性,使用一個元組來儲存數組的第一個元素和首先的數組,由於依舊是採用遞迴的方式,所以使用可選綁定來做邊界判斷。在可選綁定內部使用了filter方法來分割元素,省去了比較移動元素的複雜過程,得到的lesser是小於pivot的數組、greater是大於pivot的數組,在返回時使用了數組的拼接並對拆分的數組進行遞迴,結構非常的簡單,至此一個快速排序的過程就結束了。
讓我們在storyboard中做個效能測試:

var a:[Int] = [1,2,4,6,2,4,3,7,8]qsortDemo(a)

數組a在快排中的效率如下:

可以看到可選綁定中的return執行了9次等於a中元素的個數,和預想的一樣,這是因為每一個元素是在這個return中確定自身的位置的,所以執行次數應該為n。那麼為什麼else中的語句執行了n+1次呢?想知道每一個元素在一次遞迴中發生了什麼,可以把讓a中只有一個元素類比一次遞迴發生的事情,結果如:

開啟decompose的執行記錄:

可以看到decompose被執行了三次,第一次是[1]來訪問,返回了([1],[]),此時在可選綁定中,lesser和greater都是[],在return中遞迴的時候lesser和greater會繼續訪問decompose此時返回了兩個nil,所以對應的可選綁定判斷為假直接運行else中的return[],整個過程結束。
else條件返回的是[],[]加入到數組中不會起作用,所以可以作為邊界傳回值。
把a中的元素擴充到兩個。

decompose中的執行記錄為:

很好理解了,第一次拆分得到[1]和[2],pivot為[1],lesser為[],而greater為[2]。在return時lesser訪問decompose得到nil,可選綁定為假執行else中的語句,此時greater又成了一個元素的數組,步驟同上。所以在這個快排的遞迴過程中每次只有最後一個元素的lesser和greater會同時為[],其他元素都只有一邊為[],這也就解釋了為什麼return會出現n+1的執行次數。
觀察一下兩個filter,這種拆分方法需要多餘的空間來儲存lesser和greater,點開追蹤可以看到lesser和greater中的追蹤軌跡是相反的,這很好理解。另外filter是系統API,並不知道內部的實現方法,但是可以看到在判斷[2]中的元素的時候被調用了三次,應該與內部機制有關,雖然看起來執行的次數變多了,但是免去了傳統快速排序中的元素交換位置的操作,效率高低並不好說。總之寫了這麼多最後的效果就一個:排序。
在看完這段代碼後我做了如下思考:既然是排序,那麼必然可以使用系統的sorted方法(以前的sort方法),效果如何呢?讓我們用第一個例子來試試,只需要一行代碼:

let b = a.sorted{$0<$1}

效果如何呢?請看:

沒錯,整個方法只有15次比較!效率非常的驚人,sorted的實現是由蘋果的工程師在底層實現的,我想他們一定用了什麼好辦法來提升效率。不信?來看下面的例子,我們都知道快速排序的最壞情況出現在遞迴時對數組的不均衡劃分上,比如修改數組a為:

var a:[Int] = [1,1,1,1,1,1,1,1,1]

數組的整體大小沒有發生變化,運行效率

可以看到演算法的主要耗時部分lesser和greater的執行此時由之前的35次變為45次了,那麼sorted方法的執行效率又如何呢?

你沒有看錯!對於快排最頭疼的順序性數組,sorted的重複次數只有n次!說明在面對這種類型的數組的時候sorted方法進行過判斷,直接輸出了。當然閉包中的語句一定要合適,“千萬不要使用等號!”,比如改寫a:

var a:[Int] = [1,1,2,2,3,1,1,1,1]

沒有等號的情況:

如果你寫上等號:

OMG!效果一樣的前提下效率差了好多。
另外一種極端情況,完全逆序一個數組:

當然快排的時間和完全相同的元素一樣:

如果覺得數量級太小不過癮,那麼來個大號的數組:
現在修改a為500個隨機的100以內的正整數:

var a:[UInt32] = []for _ in 0..<500{  a.append(arc4random() % 100)}

同時比較兩種排序方式,下面是快排的:

下面是sorted的效率:

大家可以試試,規模越大的數組效率差別越明顯,sorted以肉眼可見的速度秒殺了快排!
掌聲在哪裡?

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.