2016-12-08 11 views
8

我一直在挑選和斯威夫特標準庫探測sort()函數爲它的數組類型表現良好。令我驚訝的是,我注意到它在已經排序的數據上表現不佳。排序這是洗牌的int數組似乎比排序是非常相同的陣列時,它已經排序快5倍。排序洗牌對象的數組約4倍比排序順序排序已經非常相同的速度更快(排序對象數組VS int數組使用不同的算法,我相信,所以我整理既能消除偏見)。這些結果如下:哪些通用的排序算法做斯威夫特用呢?它不會對排序的數據

Shuffled Int array sort time: 1.3961209654808 
Shuffled ColorObject array sort time: 3.14633798599243 
NOnshuffled Int array sort time: 7.34714204072952 
NOnshuffled ColorObject array sort time: 10.9310839772224 

對於低於基準是我的代碼:

class ElapsedTimer { 

let startTime:CFAbsoluteTime 
var endTime:CFAbsoluteTime? 

init() { 
    startTime = CFAbsoluteTimeGetCurrent() 
} 

func stop() -> CFAbsoluteTime { 
    endTime = CFAbsoluteTimeGetCurrent() 

    return duration! 
} 

var duration:CFAbsoluteTime? { 
    if let endTime = endTime { 
     return endTime - startTime 
    } else { 
     return nil 
    } 
} 

}

公共類CountedColor { 公私臺(套)VAR計數:詮釋 公私(集)VAR顏色:的UIColor

public init(color: UIColor, colorCount: Int) 
    { 
     self.count = colorCount 
     self.color = color 
    } 
} 

var distributedIntArray = [Int]() 
    for value in 1..<1000000 { 
     distributedIntArray.append(value) 
    } 

    var distributedCountedColorArray = distributedIntArray.map{CountedColor(color: UIColor.white, colorCount: $0)} 
    distributedCountedColorArray.shuffle() 
    distributedIntArray.shuffle() 

    var timer = ElapsedTimer() 
    distributedIntArray.sort() 
    print("Shuffled Int array sort time: \(timer.stop())") 
    timer = ElapsedTimer() 
    distributedCountedColorArray.sort{ return $0.count < $1.count } 
    print("Shuffled Color array sort time: \(timer.stop())") 
    timer = ElapsedTimer() 
    distributedIntArray.sort() 
    print("NOnshuffled Int array sort time: \(timer.stop())") 
    timer = ElapsedTimer() 
    distributedCountedColorArray.sort{ return $0.count < $1.count } 
    print("NOnshuffled Color array sort time: \(timer.stop())") 

我的數組shuffle()方法被從這篇文章中拉出來:Shuffle array swift 3 My ElapsedTimer簡單地包裝和使用CACurrentMediaTime()函數。

我的問題是爲什麼我看到這種行爲?特別是當我排序對象數組時,它肯定應該使用通用排序。什麼樣的通用排序算法是快速使用的?它肯定不可能是最糟糕的情況和平均情況是相似的mergeSort。

+0

問「爲什麼」斯威夫特選擇某種實現方式並不是一個好的客觀問題 - 理由問題很少做,因爲客觀支持性證據通常很難找到。去除額外的污點將會產生一個更加整潔的問題。客觀的問題是「Swift使用什麼類型的算法?(可以預期什麼樣的性能(在xyz的情況下)?)」 – user2864740

+2

我相信問「爲什麼」是一個完全有效的問題。理解選擇實施的原因同樣重要,如果不是更多,所有的決定都應該是合理的。這就是說我可以重新提出這個問題。 – AyBayBay

+1

Swift是開源的,所以如果你真的想知道它們使用的是什麼算法,爲什麼你不看和看?至於你的實際問題,「爲什麼會」不適合Stack Overflow;這是蘋果公司爲什麼要這麼做的原因。 – matt

回答

14

斯威夫特使用Introsort。縱觀source code我們看到,所選擇的支點是第一要素。關於內省排序維基百科頁面稱:

(...),關鍵的操作之一是選擇樞軸:圍繞該列表劃分的 元素。選擇算法最簡單的選擇算法是以 列表的第一個或最後一個元素爲關鍵點,導致對排序或近似排序的輸入的情況的行爲不佳。

因此,它是完全可預測的,給出的實現選擇,即斯威夫特的排序表現最差的排序輸入。

我已經建立了誰想要輕鬆重現OP的權利人一個完整的風向標: https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/extra/swift/sort

作爲參考,GNU ISO C++標準庫使用中位數的3樞軸(按照​​頭)。

+0

後續行動:如果選擇第一個項目因爲樞軸是一個不好的選擇,那麼更好的實現是什麼?維基百科提到中位數爲3,但有一些注意事項。對我來說,想出一個最壞的情況會比較困難,雖然中位數爲3,但與第一項相比。 –

2

這是這個問題似乎的副本:Swift sorting algorithm implementation

此外,爲什麼它進行洗牌的時候要好得多原因可能只是因爲當它的改變了它的性能沒有擊中上限NlogN的。對排序後的數組進行排序可能會更接近該上限,因此它的排列依然完全相同。但我不知道這只是理論

+0

這是不正確的,對大於幾個向下元素的已排序數組進行排序的性能是'O(n ** 2)'。在一個* shuffled *數組中,它歸結爲'O(n * log(n))'。 –

+0

By O(n ** 2)我假設你的意思是N平方。這怎麼可能是swift排序的介紹,而intro排在最壞情況下的複雜程度是NlogN。 – AyBayBay

+0

正如OP的問題所證明的那樣,swift的排序看起來並不像一個正確的introsort,否則它不會受到有序輸入的影響。也許深度閾值設置得非常高,主要表現爲快速排列行爲。 –