在最壞情況下快速排序深度要求堆棧空間爲O(n)。爲什麼它在最壞的情況下不會導致大集合的堆棧溢出? (反向序列)Quicksort遞歸深度O(n)的堆棧空間不會導致stackoverflow?
回答
如果您在主軸的兩側進行遞歸,那麼在最壞的情況下它確實會導致足夠大的數據堆棧溢出。這就是爲什麼沒有人在生產代碼中使用天真的QuickSort。
您可以對算法進行簡單的更改,以防止最壞情況下的堆棧使用。在每個分區之後,遞歸地快速排列「小一半」,然後迭代地循環執行「大一半」。這需要O(log n)
額外的堆棧空間。如果你願意,你可以通過再次修改它來使它的堆棧空間和O(log n)
額外的非堆棧空間成爲O(1)
。將「大一半」推到預先分配的數組(或者您選擇的其他後進先出的數據結構)的末尾,循環執行「小一半」,當你點擊底部時彈出最後一個元素關閉數據結構做下一步。
您可以進行進一步更改以避免Omega(n^2)
最壞情況運行時間。但它不再是一個天真的QuickSort,它是一個QuickSort-with-median-of-medians-pivot-selection,或者一個Introsort,或者其他的東西。
QuickSort-with-median-of-medians-pivot-selection仍然是快速排序,對於某些輸入仍然表現出相同的最壞情況行爲。 –
@Konrad:沒有。中位數的中位數是一個真正的線性時間選擇算法,其樞軸選擇算法(這是你在快速排序中使用的算法)發現數據的第30和第70百分位數之間的關鍵點,這足以避免最壞的情況QuickSort和QuickSelect。你是否想過「3中位數」,雖然需要一些棘手的構造,但確實有殺手案例? –
你當然是對的。我把它當作三位數中位數,這是一種不同的(恆定時間)方法。 –
如果序列顛倒(最差的情況),可能會導致堆棧溢出。因爲數組對於內部函數堆棧可能太大。 (例如,99,000,000個元素)您可以用stack
數據結構替換遞歸。您將循環while (stck.empty() == false)
function quicksort(arr[0,1,...n-1])
stack.push(pair(0, n - 1))
while stack not empty
interval = stack.pop()
...
...
stack.push(interval(0, pivot - 1))
stack.push(interval(pivot + 1, n - 1))
這不是問題。儘管它會停止堆棧溢出,但它不會改善O(n)空間消耗,這是一個嚴重的問題。 – delnan
@delnan'O(n)'堆棧空間的問題高度依賴於排序情況。它在好的案例和更糟糕的casa之間有所不同 – 2012-10-19 09:03:19
@delnan:那完全是*問題,這完全是關於堆棧溢出的問題。也許提問者也應該關心非堆棧額外的空間要求,但實際上並沒有問及它。 –
- 1. 遞歸調用堆棧深度
- 2. 遞歸隊列導致「堆棧級別太深」
- 3. 通過遞歸導致堆棧溢出
- 4. QuickSort - RuntimeError:超過最大遞歸深度
- 5. QuickSort返回遞歸深度錯誤
- 6. jQuery .trigger()方法導致深度遞歸
- 7. 爲什麼JDK的quicksort實現會導致堆棧溢出?
- 8. 堆棧級別太深,quicksort實現
- 9. 堆棧級別太深,因爲遞歸
- 10. ColdFusion:遞歸太深;堆棧溢出
- 11. 遞歸時堆棧級別太深(SystemStackError)
- 12. 堆棧排序O(N)
- 13. C++ smart_ptr不會導致堆棧溢出?
- 14. 這不會導致堆棧溢出?
- 15. 歸併排序導致堆棧溢出
- 16. 遞歸Quicksort引發堆棧溢出異常
- 17. 遞歸Java - 堆棧
- 18. C++遞歸堆棧
- 19. vba堆棧空間不足(錯誤28) - 遞歸過程
- 20. 導致堆棧溢出的遞歸函數
- 21. 遞歸方法導致Java程序中的堆棧溢出
- 22. 將遞歸函數中的setTimeOut函數導致堆棧溢出?
- 23. 遞歸調用導致堆棧溢出異常
- 24. 函數與遞歸導致堆棧溢出
- 25. 遞歸深度切斷策略:並行QuickSort
- 26. 的Tcl:遞歸PROC賦予「的堆棧空間」
- 27. 非遞歸O(N)空間合併排序
- 28. 導軌堆棧層太深
- 29. Django模型中的繼承,導致MAX遞歸深度錯誤
- 30. 這種遞歸長輪詢技術會導致堆棧溢出嗎?
使用第一個元素作爲數據透視表的快速排序實現是一個糟糕的實現。請注意,更好的方法是隨機取一個元素或選擇中間元素作爲關鍵點。 – amit
@amit:以中間元素爲中心也是可怕的,它不那麼糟糕,因爲它更難構建殺手級輸入。 –
@SteveJessop:我不同意。請注意,隨機數組與任何選擇具有完全相同的「最壞情況」變化 - 作爲隨機選定的元素。選擇第一個元素的問題是 - 真實生活數組被排序(或幾乎排序)的概率不是「1/n!」(你看過多少次已經排序了已經排序的數組的代碼?很多...),而我懷疑選擇中間元素的最壞情況數組的概率會大得多,如果有的話。這就是說 - 如果你害怕*攻擊* - 那麼應該避免任意的選擇。 – amit