什麼是遞迴

函式在處理過程中呼叫自己。把問題分成形式相同的較小問題來解,並在不再分割的情況(基底情況)結束呼叫。每次呼叫都會使用堆疊,太深就會溢位。最後只呼叫自己的尾端遞迴可以轉換成迴圈。

日文名稱: 再帰

「遞迴」出現在8領域的14道練習題中(資料結構與演算法, 連結器與載入器與執行檔格式, 程式設計基礎(虛擬碼追蹤)等)。

這個名詞所屬的領域: 資料結構與演算法

練習遞迴的題目

在RISC-V中撰寫呼叫自己的遞迴函式時,若忘了將ra保存到堆疊,會發生什麼事?

  1. Ara在內層的呼叫中被覆寫,外層的函式無法返回正確的呼叫端
  2. BCPU會自動保存ra,所以不會有任何問題
  3. C無論遞迴的深度,計算結果都會變成2倍
查看答案與解析

正確答案:A. ra在內層的呼叫中被覆寫,外層的函式無法返回正確的呼叫端

遞迴呼叫的jal會將ra覆寫為「自己內部呼叫的下一個指令」。若沒有保存,外層的函式在ret時就不會回到原本的呼叫端,而是回到自己內部,導致重複相同的地方或發生錯誤動作。因此,呼叫其他函式的函式,規定要在序言將ra保存到堆疊,並在結尾還原。

當遞迴過深而超過堆疊的上限時,在Linux等系統上一般會發生的事,下列何者正確?

  1. A碰到堆疊前方禁止存取的保護分頁(guard page),程式異常終止
  2. B作業系統自動將堆疊移到磁碟,因此可以無限深地遞迴
  3. C舊的堆疊框被自動清除,計算得以正確地繼續
查看答案與解析

正確答案:A. 碰到堆疊前方禁止存取的保護分頁(guard page),程式異常終止

堆疊有上限,其前方會放置禁止存取的保護分頁。當遞迴過深使堆疊到達這裡時,就會發生分頁錯誤(page fault),由作業系統停止程式(區段錯誤)。保護分頁的好處是能在破壞其他資料之前就停下來。若將大型陣列作為區域變數,也會發生同樣的事,因此大型資料放在堆積上比較安全。

解析中的「遞迴」

出現「遞迴」的題目(14題)

  1. 在RISC-V中撰寫呼叫自己的遞迴函式時,若忘了將ra保存到堆疊,會發生什麼事?
  2. 對上方函式最後的遞迴呼叫進行尾端呼叫最佳化,會有什麼效果?
  3. 當遞迴過深而超過堆疊的上限時,在Linux等系統上一般會發生的事,下列何者正確?
  4. 在無向圖中,各頂點的相鄰頂點如下:A: B, C / B: A, D, E / C: A, F / D: B / E: B, F / F: C, E。從頂點 A 進行遞迴的深度優先搜尋。相鄰頂點依此處列出的順序檢查,一找到尚未拜訪的頂點就立刻前往。拜訪頂點的順序為下列何者?
  5. 以遞迴將求費氏數的函數 fib(n) 定義為「若 n 在1以下則回傳 n,否則回傳 fib(n−1) + fib(n−2)」。呼叫 fib(5) 時,含第一次呼叫在內,fib 被呼叫幾次?
  6. 在程式中呼叫副程式(函式)時,一般用來暫時保存返回位址等的區域是下列何者?
  7. 在C語言的函式中宣告、未加static的區域變數(自動變數),執行時會放在哪裡?
  8. 將行程的堆積與堆疊配置成中間隔著寬廣的空閒區域、朝相反方向延伸,其優點為下列何者?
  9. 在沒有MMU的小型微控制器上,關於堆疊使用過量,應注意的事項下列何者正確?
  10. 在邊沒有權重的圖中,想求出從起點到各頂點的最少邊數。適合的搜尋方法與所使用的資料結構組合為下列何者?
  11. 函數 f(x, y) 定義為「若 y 為0則回傳 x,否則回傳 f(y, x mod y)」。呼叫 f(84, 36) 時的回傳值,以及 f 被呼叫的次數(含第一次呼叫)的組合為下列何者?
  12. ÷ 為除法,代入整數型變數(含引數)時捨去小數部分。以 pow(2, 10) 呼叫下列函式 pow 時,pow 被呼叫的次數(含第一次呼叫)為下列何者?
  13. 以 fib(10) 呼叫下列函式 fib 時,回傳值為下列何者?
  14. int 為32位元(最大值 2147483647)。上方的函式 fact(n) 能不發生溢位、正確回傳 n 的階乘的最大 n 為下列何者?

半導體、電子電路與資訊計算工具

相關名詞

堆疊 變數 引數 回傳值 堆疊框 陣列 深度優先搜尋 廣度優先搜尋 堆疊指標 頁面錯誤

前往名詞解釋列表