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 著,杨宗源/黄海涛 译 - 清华大学出版社