[英]What is Array.prototype.sort() time complexity?
根據 Mozilla 文檔:
排序的時間和空間復雜度無法保證,因為它取決於實現。
假設它不是O(n^2)
至少安全嗎? 有沒有關於它是如何實施的更詳細的數據? 謝謝。
理論與實踐:理論上,理論與實踐沒有區別,但在實踐中卻有區別。
- 理論:一切都清楚,但無濟於事;
- 實踐:一切正常,但一切都不清楚;
- 有時理論與實踐相遇:沒有什么是行得通的,沒有什么是清楚的。
Big O 表示法非常適合評估算法的可擴展性,但不提供直接比較算法實現之間性能的方法......
一個典型的例子是瀏覽器中 Array.sort() 的實現。 盡管 Timsort 比 Merge sort 具有更好的 Big O profile(參見https://www.bigocheatsheet.com/ ),但實證測試表明,Timsort 在 Chrome 的 V8 引擎中的實現明顯優於 Firefox 中 Merge sort 的實現.
下面的圖表分別顯示了兩組數據點:
此外,大 O 符號提供了從算法的可擴展性中期望的一般經驗法則,但沒有解決可變性問題。 Timsort 算法的 Chrome V8 實現在其執行方面比 Firefox 合並排序具有更大的可變性,盡管 Timsort 的 Big O 配置文件更好,但即使 Timsort 的最佳時間也不比合並排序的最差時間好。 冒着引發宗教戰爭的風險,這並不意味着 Timsort 比合並排序更糟糕,因為這可能只是 Firefox 的 JavaScript 實現更好的整體性能的一個例子。
上面圖表的數據是從我的 Acer Aspire E5-5775G 簽名版上的以下代碼生成的,它具有 Intel Core i5-7200U CPU @2.50GHz 和 8GB RAM。 然后將數據導入 Excel,分析 95% 的邊界范圍,然后繪制圖表。 為了便於視覺比較,圖表上的軸刻度已標准化。
function generateDataPoints( qtyOfTests, arrayRange, valueRange, nearlySortedChange ) {
let loadingTheArray = [];
let randomSortMetrics = [];
let nearlySortedMetrics = [];
for ( let testNo = 0; testNo < qtyOfTests; testNo++ ) {
if ( testNo % 10 === 0 ) console.log( testNo );
// Random determine the size of the array given the range, and then
// randomly fill the array with values.
let testArray = [];
let testArrayLen = Math.round( Math.random() * ( arrayRange.hi - arrayRange.lo ) ) + arrayRange.lo;
start = performance.now();
for ( let v = 0; v < testArrayLen; v++ ) {
testArray[ v ] = Math.round( Math.random() * ( valueRange.hi - valueRange.lo ) ) + valueRange.lo;
}
end = performance.now();
loadingTheArray[ testNo ] = { x: testArrayLen, y: Math.floor( end - start ) };
// Perform the sort and capture the result.
start = performance.now();
testArray.sort( (a, b ) => a - b );
end = performance.now();
randomSortMetrics[ testNo ] = { x: testArrayLen, y: Math.floor( end - start ) };
// Now, let's change a portion of the sorted values and sort again.
let qtyOfValuesToChange = testArrayLen * nearlySortedChange;
for ( let i = 0; i < qtyOfValuesToChange; i++ ) {
let v = Math.round( Math.random() * testArrayLen );
testArray[ v ] = Math.round( Math.random() * ( valueRange.hi - valueRange.lo ) ) + valueRange.lo;
}
start = performance.now();
testArray.sort( (a, b ) => a - b );
end = performance.now();
nearlySortedMetrics[ testNo ] = { x: testArrayLen, y: Math.floor( end - start ) };
}
return [ loadingTheArray, randomSortMetrics, nearlySortedMetrics ];
}
// Let's start running tests!
let arraySizeRange = { lo: 100, hi: 500000 };
let valueRange = { lo: 0, hi: 2 ** 32 - 1 };
let results = generateDataPoints( 500, arraySizeRange, valueRange, 0.02 );
let tabFormat = 'No Of Elements\tTime to Load Array\tFull Sort\tMostly Sorted\n';
for ( let i = 0; i < results[0].length; i++ ) {
tabFormat += `${results[0][i].x}\t${results[0][i].y}\t${results[1][i].y}\t${results[2][i].y}\n`;
}
console.log( tabFormat );
結論是,一個算法的性能,表面上是基於 Big O 符號的更好,有許多因素驅動其整體性能,更好的 Big O 並不一定轉化為更好的性能......
這取決於瀏覽器/引擎。
由於使用了 V8 v7.0和 Chrome 70 Timsort 算法。
其中,對於較小的數組,時間復雜度為 O(n),空間復雜度為 0(1)。 對於更大的數組,它的時間復雜度為 O(nlog(n)),空間復雜度為 O(n)。
舊版本的 V8 使用快速排序,它可以檢查小數組(最多 10 個元素)。 所以對於較小的數組,時間復雜度為 O(n^2),空間復雜度為 O(1)。
對於較大的數組,時間復雜度為 Θ(n log(n))(平均情況),空間復雜度為 O(log(n))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.