php递归分析

文章转载链接1:https://blog.csdn.net/ohmygirl/article/details/19679643

文章转载链接2:https://blog.csdn.net/wzqnls/article/details/38705143

递归的定义

    递归(http:/en.wikipedia.org/wiki/Recursive)是一种函数调用自身(直接或间接)的一种机制,这种强大的思想可以把某些复杂的概念变得极为简单。在计算机科学之外,尤其是在数学中,递归的概念屡见不鲜。例如:最常用于递归讲解的斐波那契数列便是一个极为典型的例子,而其他的例如阶层(n!)也可以转化为递归的定义(n! = n*(n-1)!).即使是在现实生活中,递归的思想也是随处可见:例如,由于学业问题你需要校长盖章,然而校长却说“只有教导主任盖章了我才会盖章”,当你找到教导主任,教导主任又说:“只有系主任盖章了我才会盖章”...直到你最终找到班主任,在得到班主任豪爽的盖章之后,你要依次返回到系主任、教导主任、最后得到校长的盖章,过程如下:

以上事例体现了递归的基本思想,也就是递归的两个基本条件:

  1. 递归的退出条件,这是递归能够正常执行的必要条件,也是保证递归能够正确返回的必要条件。如果缺乏这个条件,递归就会无限进行下去,直到系统给予的资源耗尽(在大多数语言中,都是堆栈空间耗尽),因此,如果你在编程中碰到类似“stack overflow”(C语言中,即栈溢出)和“max nest level of 100 reached”(php中,超出递归限制)等错误,多半是没有正确的退出条件,导致了递归深度过大或者无限递归。

  2. 递推过程。由一层函数调用进入下一层函数调用的递推。以n!为例。在n>1的情况下。N! = N*(N-1)! 便是该递归函数的递推过程,我们也可以简单的称为“递归公式”

有了这两个基本条件,我们便得到了递归的一般模式, 用代码可以描述为:


function Recur(  param ){
	if(  reach the baseCondition ){
		Calu();//计算
		return ;
	}
	//else just do it recursively
	param = modify(param)/修改参数,准备进入下层调用
	Recur(param);
}

 有了递归的一般模式,我们便可以轻松实现大多的递归函数。例如:经常提起的斐波那契数列的递归实现,再如,目录的递归访问

还有 递归使用 “层”这个概念。主要有两大原因:

1. 人们在分析递归的过程中,经常使用递归树的形式来分析递归函数的走向。以斐波那契数列为例,首先斐波那契数列的定义为:

 

因此,为了得到Fab(n)的值,我们常常需要展开为“递归树”的形式,如下图所示:

而递归的计算过程则是从上而下,从左而右,一旦到达递归树的叶子节点(也就是递归的退出条件),便又层层向上返回。

作为递归的基本实例,以下可用于练习:

1. 目录的递归遍历。

2. 无限分类。

3. 二分查找和合并排序。

4. PHP内置的与递归行为有关的函数(如array_merge_recursive,array_walk_recursive,array_replace_recursive等,考虑它们的实现)

理解递归-函数调用的堆栈跟踪

在php中,可以使用的调试方法有:

1.原生的print ,echo ,var_dump,print_r等,通常对于较为简单的程序,只需要在函数的 关键点输出即可。

2.Php内置的堆栈跟踪函数:debug_backtrace 和debug_print_backtrace.

3.xdebug 和xhprof等调试工具。

使用范例:

function fab($n){
    debug_print_backtrace();
    if($n == 1 || $n == 0){
        return $n;
    }             
    return fab($n - 1) + fab($n - 2);
}                     
fab(4);

 还有一个形象的解释:

代码A:


<?php
	//递归函数
	$num=10;
	function add($sum){
		static $tot;
		if($sum>=1){
			$tot+=$sum;
			add(--$sum);
		}else{
			return $tot;
		}
	}
	echo add($num);
?>

代码B:

<?php
	//递归函数
	$num=10;
	function add($sum){
		static $tot;
		if($sum>=1){
			$tot+=$sum;
			return add(--$sum);
		}else{
			return $tot;
		}
	}
	echo add($num);
?>

 A中打印不出想要的结果,B中可以实现。而A和B代码中的唯一差别就是在if中添加了一个return。

下面就开始分析整个递归的过程,完全可以去看看盗梦空间加深理解了:(以不能实现的A代码为例)

1.将10带入函数中,if语句判断之后,$tot开始叠加。

2.这里重点来了:将参数减一之后重新带入函数中。(没有返回值!!!)

3.接着上面的过程一直循环,一直到$sum=1,这从外到内,由10到1,这10层的循环都没有返回值。

4.$sum=0的时候,要求有返回值。

就好像,盗梦空间中,主角在11层梦境中醒来,但是前面10层的梦境都处于睡眠阶段。这主角你觉得醒的过来吗,明显不可能。他只能卡在第11层梦境,永远醒不过来。

唯一能让主角醒过来的办法也就是他的每一层梦醒都醒过来,一直回到现实生活中。而相对与A代码,B代码则从第一层开始就要求有返回值,一直到11层都要有返回值。所以11层醒过来之后激活了第10层,然后一层一层的激活,最后就顺利醒过来了,这个最后的结果也就正确输出了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值