西山居递归面试题
一道西山居的面试题,求好的解题思路?
#include<iostream>
int cc(int i)
{
for(;i<4;)
{
std::cout<<cc(++i);
}
return i;
}
int main()
{
cc(1);
return 0;
}
输出结果:___ ?
题目来自:https://www.zhihu.com/question/50552768
解决方案:
这道题困扰了我很久,看了很多相关递归的书,之前一位大神朋友告诉我递归很重要,他是分而治之和动态规划的基础,我也没系统学过递归树的画法。
看了一段时间以后,我也跟着画了一个递归函数调用树,起初不能理解递归树,其实主要遗落了:cout cc(2)的右子树,每一步都单独来看,由于自己实在太笨了,就不得不改写了一下源程序:
int cc(int i)
{
//cout << "call cc(" << i << ")" << endl;
for (; i<4;)
{
++i;
std::cout << cc(i) << endl;
}
return i;
}
参考书(《面向算法设计的数据结构C++语言版》)中p75提到的:
递归中每个函数实体是相互独立的存在,即便它们参数完全一致,也不例外。
递归的唯一体现仅在于递归函数共用一段静态的程序代码,若为每个函数分别保存数据以记录它执行到程序代码的哪一步,并保证各个函数的局部数据与其他函数无关,
则可实现函数之间的独立性。而上述只与具体函数执行有关的信息称为其上下文。执行中的函数是动态的概念,它类似于操作系统中的进程,不妨为函数执行建立
"函数进程"模型。函数进程存在新生(被其他函数调用而创建),运行(执行非函数调用的代码),等待(调用其他函数而自身暂停)和终止(运行结束)四种状态。(这里略去了就绪状态,
一旦调用函数终止,调用者将直接从等待状态转为运行状态),很容易通过改变上下文达到切换函数进程的目的。对于递归来说,不失真的调用自己,而是创建一个
与自身拥有共同代码但包含独立上下文的函数进程。
慢慢来分析此程序:
其实重点是i是在函数内进行加1操作的,也就是当i为3的时候,执行i加1以后,i变为4,要执行cout << cc(4) << endl;
这是我画的递归调用树
至此这道题终于完结了,有空改一下题,可以通过返回值变换下题型。平时没事的时候也拿出来锻炼一下。
知乎上的答案:
我来贡献一个比轮子哥好看的调用树<(╯3╰)
作者:Theodore
链接:https://www.zhihu.com/question/50552768/answer/121498074
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
reference:
《面向算法设计的数据结构C++语言版》谢勰 2015年第1版
《数据结构C++语言版》第3版,邓俊辉
《数据结构》(类C语言版)严蔚敏,吴伟民
《数据结构与算法分析C语言描述》英文版
《算法导论》原书第三版中文版