递归
思路:
1.找起点(其实是函数执行的终点)
2.找规律,函数转换为数字,得到第n个求法
3.转换为递归函数--包括if终止条件1和else递归方法2
while和递归的区别
递归优点就是易理解,容易编程。但递归是用栈机制实现的(c++),每深入一层,都要占去一块栈,如果嵌套过深,空间上会以内存崩溃而爆栈;
循环其缺点就是不容易理解,编写复杂问题时困难。优点是效率高。运行时间只因循环次数增加而增加, 没什么额外开销。
注:函数栈的目的:保持入口环境
尾调用:就是指某个函数的最后一步是调用另一个函数。
使用尾递归优化 --> 在展开的过程中计算并且缓存了结果,并不会像普通递归函数那样展开出非常庞大的中间结果,所以不会爆栈是吗?
当然不是!不会爆栈是因为语言的编译器或者解释器所做了“尾递归优化”,才让它不会爆栈的。尾递归优化本质也是一种循环。
尾递归为什么可以优化? 因为尾递归的情况下,我们保持这个函数的入口环境没意义,所以我们就可以把这个函数的调用栈给优化掉。在 ES6 中,只要使用尾递归,就不会发生栈溢出,相对节省内存。
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除 f() 的调用记录,只保留 g(3) 的调用记录。
http://www.ruanyifeng.com/blog/2015/04/tail-call.html