關於遞歸調用的深度

題目源自牛客網:

1.對n個記錄的線性表進行快速排序爲減少算法的遞歸深度,以下敘述正確的是()

正確答案: A   你的答案: A (正確)

每次分區後,先處理較短的部分
每次分區後,先處理較長的部分
與算法每次分區後的處理順序無關
以上三者都不對

來看一個別人的答案:“考慮一種極端情況,如果每次確定pivot後短的部分都爲1,先處理短的部分,短的部分處理完後就會出棧,那麼輔助棧的深度爲O(1)即可,同理,如果先處理長的部分,較長的部分不斷遞歸壓棧, 輔助棧的深度就是O(n)。所以,如果每次都先處理較短的部分,那麼長而化小,棧區的深度較小,反之,較長的部分不斷遞歸壓棧,棧區的長度就會大。”

可能這樣講還比較抽象,那來看最高票的一個舉例子的解釋:
“看到很多人在別的答案下說看不懂,那我就來舉個栗子。
現在有這麼個序列:123456789
假設每次劃分出短序列的長度爲1
即第一次劃分
短序列:1
長序列:23456789
如果優先處理短序列1
則棧中僅用保存23456789,深度爲1
然後23456789出棧,劃分
短序列:2
長序列:3456789
同樣的先處理短序列
棧中保存3456789,深度爲1
類推下去,處理完整個序列,棧的最大深度都爲1

假如每次劃分出的短序列長度爲2呢
短序列:12
長序列:3456789
優先處理短序列12
棧中保存3456789 深度爲1
12只能劃分爲同樣長度的序列1和2
先處理左邊的
棧保存2 此時棧中有3456789 和 2 深度爲2
然後2 出棧 處理
接着3456789出棧
劃分爲短序列34
長序列 56789
處理短序列34
棧中保存56789
類推下去,處理完整個序列,棧的最大深度都爲2

也就是說棧的最大深度取決於劃分出來的短序列的長度 (前提是先處理短序列)

那麼先處理長序列呢
短序列:1
長序列:23456789
如果優先處理長序列序列23456789 短序列入棧,長序列劃分爲2和3456789
2入棧,3456789劃分
。。。
8入棧,9處理
此時棧中有12345678 深度爲8

短序列:12
長序列:3456789
12入棧 3456789劃分爲34和56789
34入棧 56789劃分爲56和789
56入棧 789劃分爲78和9
9入棧  78劃分爲7和8
7入棧 8處理
此時棧中有12 34 56 9 7 深度爲5

很明顯先處理長序列 棧的深度要大於 先處理短序列棧的深度。”

如果還沒看懂那可以自己在紙上寫一個例子出來。


2.採用遞歸方式對順序表進行快速排序,下列關於遞歸次數的敘述中,正確的是()

正確答案: D   你的答案: C (錯誤)

遞歸次數與初始數據的排列次序無關
每次劃分後,先處理較長的分區可以減少遞歸次數
每次劃分後,先處理較短的分區可以減少遞歸次數
遞歸次數與每次劃分後得到的分區處理順序無關


A選項:快速排序中,如果序列初始化就有序:123456,那麼明顯只需要遞歸一次就好了,因爲右邊先啓動的哨兵一直走呀走走到數字1的位置才停下來,那下面就已經無需再遞歸了,直接得出結果了(這裏需要事先理解快速排序的流程,可參考我的另一篇博客:快速排序C++)。所以顯然至少在快排當中,遞歸的次數是跟初始數據的排列次序是有關的。

後面三個選項:每次劃分應該先處理較短的分區,只是減少遞歸佔用的內存空間(每次調用棧的深度),並不能減少次數,該比較那麼多次還是得比較那麼多次。每次劃分先處理較短的分區,那其實相當於:切瓜子,固定要均分切成一樣厚度的薄片,然後我每次拿較短的一段先切掉,然後再回到長的一段繼續分切,其實最終要切的次數還是那麼多的,只是會給人一種心理安慰似的,因爲每次不用切太久(遞歸深度較淺)我就切完了一段,很有成就感是吧。。。然而最終要切的次數還是一樣多的。

發佈了170 篇原創文章 · 獲贊 64 · 訪問量 52萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章