「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」
前言
面对玄学编程,很多时候编写递归代码,糊里糊涂的写,能不能运行正确,完全靠运气,递归是编程中的一个难点,自己解决不了的问题, 就继续调用自己来解决问题,我们不禁会发问,你在逗我吗?这样也行? 猴子都知道,解决不了问题的时候,要去搬救兵帮忙解决问题。另外,在编写递归代码的时候,递归代码的后面往往还有代码,大脑不禁会发问,代码都没写完,怎么就可以调用了?这都是反直觉的,这种反直觉性, 会让我们的大脑很排斥, 然后大脑就会很晕,然后就放弃理解了。然后又忍不住去继续学习递归,可很多时候难免还是陷入一看就会,一做就废的循环中。
回答前面的问题
1.解决不了的问题,为什么继续调用自己就能解决?
因为函数体内继续调用自己,解决的是更小的问题。虽然方法没变,但是面对的问题却简化了。所以这里或许是我们日常思维的禁区,面对一个难以解决的问题的时候,我们总倾向于去改变方法, 却忘了方法不变,但是简化问题,也是一条路。但是在日常生活中,我们好像使用这种思维去解决问题的场景比较的少,甚至是没有,毕竟我们不是孙悟空,面对复杂的问题,不能变出一万个和自己长的一模一样的猴子一起来解决问题,所以这是我们难以理解递归的原因之一。因为日常生活中当我们遇到难题,我们往往都是改变方法搬救兵。所以我们在理解递归的时候, 不要单纯的在大脑中模拟他的执行过程,这样很容易把自己搞晕,更重要的是,去问一下自己,这样是否简化了问题。
2.调用递归代码的时候,为什么后面还可以有代码?
因为虽然在编写代码的时候,后面的代码是未知的,但是在执行的时候,后面的代码却是已知的。
回归日常正常思维,递归只是一种简写形式
来看一个最简单的递归的例子,阶乘。
function p(n){
if (n==1){
return 1;
}else{
return n*p(n-1)
}
}
console.log(p(5));//120
如果对这个最简单的递归感到不好理解,可以看看下面的普通思维的代码以加强理解。
function p5(){
return 5*p4();
}
function p4(){
return 4*p3();
}
function p3(){
return 3*p2();
}
function p2(){
return 2*p1();
}
function p1(){
return 1;
}
console.log(p5());//120
任何人理解这段代码都没有任何压力,所以递归一点都不神秘,可以看到,其实递归依然是正常思维代码的一种简写,也仍然可以采用搬救兵的思维来解决问题,只不过,他搬来的救兵,从形式上看,居然和自己长的一模一样,所以其实递归的代码是更高层次的抽象。如果调用100次别的函数,不可能写100次这样的函数,那样会显得非常无聊,而递归的写法就能很好的解决这个问题,尽管在某种程度上,递归增加了代码理解的难度,但这是值得的。
递归的优化
总结
递归难以理解是递归的痛,面对复杂的问题,递归能写出简约又让人惊叹的代码是递归的乐。用大脑去模拟复杂的递归问题,个人觉得几乎是不可能的,所以我们要放弃大脑去模拟递归执行的全程过程,取而代之代之,我们要理解的是递归两层的交接及递归终结的条件。