_**我们一起,每天进步一点。日积月累,有朝一日定会,厚积薄发。 **_
(三)不可不说的JS重点知识~递归和尾递归(测试小姐姐专题)
(五)javaScript重点知识~~~单例模式(测试小姐姐专题)
我们是程序员,程序员的最大的本事,就是可以把编程思想运用到生活中。前几天,我和测试小姐姐在咖啡厅畅谈了人生,想放弃眼前的苟且,一起寻找诗和远方。这是她一时的冲动还是想品尝爱情的甜蜜呢?突发奇想,我们何不用递归来,反测试一下这个小姐姐呢?看看 她是否有恒心。以后我会每天都请他吃饭,喝咖啡,周而复始。
递归含义:
函数中调用函数自己,在使用递归的时候一定需要有结束递归的条件,否则就会变成死循环,直到浏览器崩溃。
递归的条件栗子:
这个结束递归的条件 ,就是:
1.如果有一天她不耐烦了,说出她的心声:只是一时冲动,那我就结束递归。
2.如果小姐姐在每次约会之后,彼此交心畅谈未来,谈到七大姑八大姨,生宝宝的话题。那我就带她去看房子.......
但是还是忽略了一种情况,那就是小姐姐想与我共度余生,但是每天 除了一起吃饭就是喝咖啡,生活很精彩,却被吃饭喝咖啡占用了大部分的精力。这就遇到了递归的瓶颈问题了。接下来,让我们研究一下递归的优点和缺点。
递归的优缺点
优点:
1、代码简洁
2、易于理解
如在树的前/中/后序遍历中,递归的实现明显比循环简单。
缺点:
1、时间和空间的消耗比较大
递归由于是函数调用自身,而函数的调用时消耗时间和空间的,每一次函数调用,都需要在内存栈中分配空间以保存参数,返回值和临时变量,而往栈中压入和弹出数据也都需要时间,所以降低了效率。
2、重复计算
递归中又很多计算都是重复的,递归的本质时把一个问题分解成两个或多个小 问题,多个小问题存在重叠的部分,即存在重复计算,如斐波那契数列的递归实现。
3、调用栈溢出
递归可能时调用栈溢出,每次调用时都会在内存栈中分配空间,而栈空间的容量是有限的,当调用的次数太多,就可能会超出栈的容量,进而造成调用栈溢出。
原因是每次执行代码时,都会分配一定尺寸的栈空间(Windows 系统中为 1M),每次方法调用时都会在栈里储存一定信息(如参数、局部变量、返回值等等),这些信息再少也会占用一定空间,成千上万个此类空间累积起来,自然就超过线程的栈空间了。那么如何解决此类问题?
解决方案~~尾递归:
以阶乘为例子,我们一起研究一下尾递归:
尾递归就是:**在函数执行的最后一步返回一个一个函数调用**
递归:
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5) // 120
尾递归:
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1) // 120
**理论上对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。但是,经过试验,尾递归也出现了栈溢出。结果可以参考下图:**
很坑啊!!!是浏览器没有实现尾递归,产生省内存的效果**!**
应用案例:
(1)求斐波那契数列
function getFib(x) {
if(x==1||x==2){
return 1
}
return getFib(x-1)+getFib(x-2);
}
console.log(getFib(12));
(2)求一个数字各个位数上的数字的和
getEverySum(x) {
if(x<10){
return x;
}
//获取的是这个数字的个位数
return x%10+getEverySum(parseInt(x/10));
}
console.log(getEverySum(123));//6
言归正传,测试小姐姐是否是 一时冲动呢?我已经给测试小姐姐发微信了,下班之后去吃好伦哥。
《临江仙~三国演义》
滚滚长江东逝水,
浪花淘尽英雄。
是非成败转头空。
青山依旧在,
几度夕阳红。
白发渔樵江渚上,
惯看秋月春风。
一壶浊酒喜相逢。
古今多少事,
都付笑谈中。