void show(....) { ... show(....); ... }
在上面這個遞歸函數中,調用自己的那行語句叫作遞歸調用語句。
有時候,遞歸調用的前后往往還有其他語句,它們的執行順序情況是有規律的。
考慮一個數組 int a[7],設當前位置在a[6],並希望以遞歸的方式輸出數組內容(沒人會用遞歸做這種事情)。
int main(int argc, char* argv[]) { int a[7] = {1,2,3,4,5,6,7}; // show(a, 6); show(a, sizeof(a) / sizeof(int) - 1); cout<<endl; return 0; }
如果我的輸出語句寫再遞歸調用的前面,如:
void show(int* a, unsigned i) { if(i == 0) { cout<<a[i]<<" "; return; } cout<<a[i]<<" "; show(a, i - 1); }
則輸出為:7 6 5 4 3 2 1。
而如果我的輸出語句寫在遞歸調用的后面,如:
void show(int* a, unsigned i) { if(i == 0) { cout<<a[i]<<" "; return; } show(a, i - 1); cout<<a[i]<<" "; }
則輸出為:1 2 3 4 5 6 7。
可見,在遞歸調用語句前后的語句,最終執行的順序是反過來。
考慮第一種情況。一開始位置在a[6],則a[6]在遞歸調用之前就已經輸出了 。
進入遞歸,當前位置在a[5],可發現a[5]在遞歸調用之前也已經輸出了。
再進入遞歸,當前位置a[4],也在遞歸調用之前輸出了.....
這樣,先輸出的永遠是當前位置的元素,a[0]將會被最后輸出。
第二種情況中,總是在遞歸調用后才輸出當前元素,所以當前元素永遠是后輸出的。
再觀察代碼,第一種情況:
cout<<a[i]<<" ";
show(a, i - 1);
因為i相關的語句在前面,i-1 相關的語句在后面,所以是先處理 i 相關的,再處理 i-1 相關的。
反之第二種情況:
show(a, i - 1);
cout<<a[i]<<" ";
先處理 i-1 相關的, 再處理 i 相關的。
可見,執行語句放在遞歸調用的前面還是后面,是個很重要的問題。雖然上面這個例子完全可以不用遞歸來完成,但說明了一些道理。
假設要寫一個程序,來完成類似linux中pwd命令的功能,以輸出當前目錄的完整路徑,那么上面例子揭示的道理就很有用了。
每一級目錄的名字就好比是數組a中的每一個元素。
如此看來,需求不過就是:當前位置在a的最后一個元素,而要把數組a的所有元素從前往后輸出。
所以,輸出每個目錄名的語句必須放到遞歸調用語句的后面。
參考資料:
《Unix/Linux編程實踐教程》 - (美) Bruce Molay 著,楊宗源/黃海濤 譯 - 清華大學出版社