JavaScript的递归之楔子和一个例子

(几年前的几篇文章,重发于此。)

楔子

王二、张三和赵四一日无聊,决定玩击鼓传花讲冷笑话的游戏。王二和张三围成一圈传花,赵四负责击鼓。张三接连讲了几个诸如小菜、狐狸狡猾的笑话。花停在了王二的手中。

王二:这个笑话很短。你要保证听完后不生气我就说。

张三:你说吧。

王二:张三。

张三:怎么了?

王二:笑话说完了,就两个字。

张三欲发怒。

王二:欸,你刚才说好了不会生气的。

张三只好作罢。新一轮开始,花又停在王二的手中。

王二:张三不是个笑话。

张三再次欲发怒。

王二:别生气,我说的是冷笑话,就表示不好笑啊。

花又一次停在王二的手中。

王二:[张三不是个笑话]不是个笑话。

第四次花停在王二的手中。

王二:[[[张三不是个笑话]不是个笑话]不是个笑话]。

……

递归与一个例子

程序设计中,递归指在一个函数中直接或间接地调用函数自身。所以以上冷笑话的无穷序列就可以看作是递归调用“不是个笑话”。递归在实现上没有什么特殊的困难,因为以堆栈模型来看函数调用,被调用函数与调用函数是否相同是无关紧要的。所以大部分语言都支持递归。函数作为Javascript的基石,也支持递归。

递归和循环常常可以用来解决同一个问题。但是两者的设计方法有很大不同。采用循环的代码需要指明解决问题的每一个步骤。而递归则更接近于数学上的形式定义,只需要写明问题给出的条件,剩下的就由计算机重复地迭代,思路上往往很直观。

很多书里都用计算斐波纳契数列来说明递归的应用。这里也把它作为第一个例子。

斐波纳契数列的定义为,当n=0和1时,A(n)=n;当n>=2时,A(n)=A(n-1)+A(n-2)。

用循环和递归的方法分别都可以写出计算斐波纳契某一项的函数。不过实际上,如果让一个熟练掌握数列通项公式又刚学习程序的高中生来写,结果可能会是这样。

//以下一系列的函数都假设n为非负整数
function fibonacci1(n){
	var phi=(1+Math.sqrt(5))/2;//(1-Math.sqrt(5))/2
	if (n<2) return n;
	return (Math.pow(phi, n) + Math.pow(1-phi, n))/(phi*(3-phi));
}

(他的思路如下:根据A(n)=A(n-1)+A(n-2),得A(n)+x*A(n-1)=(1+x)*[A(n-1)+1/(1+x)*A(n-2)],令x=1/(1+x)可得x^2+x-1=0,解出x=[-1+sqrt(5)]/2或[-1-sqrt(5)]/2。A(n)+x*A(n-1)构成一个等比数列。最后得到程序中的解的公式。)

这样的解法会让数学老师高兴,计算机老师难过。计算机被当成计算器来用。另外,由于运算中涉及到小数,计算结果与本应是整数的精确值相比有微小的误差。

采用循环的的第二个版本如下:

function fibonacci2(n){
	if (n<2) return n;
	var a=0, b=1, c;
	for (i=2; i<=n; i++){
		c=a+b;
		a=b;
		b=c;
	}
	return c;
}

下面则是采用递归的第三个版本。

function fibonacci3(n){
	if (n<2) return n;
	return f3(n-1) + f3(n-2);	
}

可以明显地看出,采用递归的版本程序最简短,它只是将斐波纳契数列的数学定义用程序的语言写出来。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值