递归算法
• 引用的作用 如果程序比较大,引用同一个对象的变量 比较多,并且希望用完该对象后手工清除它,个 人建议用 "&" 方式,然后用$var=null的方式清 除. 其它时候还是用php5的默认方式吧. 另外, php5中对于大数组的传递,建议用 "&" 方式, 毕 竟节省内存空间使用。
• 取消引用 当你 unset 一个引用,只是断开了变量名和变量内容 之间的绑定。这并不意味着变量内容被销毁了。例如: • <?php $a = 1; $b =& $a; unset ($a); ?> • 不会 unset $b,只是 $a。 function quoteTest(){ global $var ; //相 当于 $var = &$GLOBALS['var']; unset($var); //删除只是删除引用, 而引用的内容还存在,同上这并不意味着变量内容被销毁 了}$var=1;quoteTest();echo $var; // 结果 1 • 不会 unset $b,只是 $a。
递归算法
递归的介绍,理解和使用
定义
• 递归算法: 是将问题转化为规模缩小的同类问题的子 问题,每一个子问题都用一个同样的算法 去解决。 一般来说,一个递归算法就是函数调用自 身去解决它的子问题。
特点
• 递归就是在过程或函数里调用自身。 • 在递归过程中,必须有一个明确的条件判 断递归的结束,既递归出口。 • 递归算法解题通常显得很简洁,但递归算 法解题的运行效率较低。 • 在递归调用的过程当中系统为每一层的返 回点、局部量等开辟了栈来存储。递归次 数过多过深可以造成栈溢出等问题(就js和 php而言这种可能性很小很少见,而由递归 边界设置不当造成的死循环则更为常见)。
• 通俗的讲 1:如果有下面的代码 <?php
$a="ABC"; $b=$a; ?>
其实此时,$a与$b都是指向同一内存地址,而并不是$a与$b占用不同的 内存
• 函数的引用返回: <?php function &test(){ static $b=0;//申明一个静态变量 $b=$b+1; echo $b; return $b; } } $a=test();//这条语句会输出 $b的值 为1 $a=5; $a=test();//这条语句会输出 $b的值 为2 $a=&test();//这条语句会输出 $b的值 为3 $a=5; $a=test();//这条语句会输出 $b的值 为6 ?>
• 其实函数的引用返回多用在对象中。 • 对象的引用 : <?php class a{ var $abc="ABC"; } $b=new a; $c=$b; echo $b->abc;//这里输出ABC echo $c->abc;//这里输出ABC $b->abc="DEF"; echo $c->abc;//这里输出DEF ?>
Length=0
abcd bcd cd d null
Echo ’a’
Echo ‘b’
Echo ‘c’
返 回 顺 序
Echo ‘d’
实际案例
使用递归的方式创建目录 /** * 递归创建目录 * @param [string] $path [创建的目录] * @return [type] [description] */ function mk_Dir($path){ // 如果目录存在返回 ture if(is_dir($path)){ return true; } // 如果上级目录存在 创建目录 if(is_dir(dirname($path))){ return mkdir($path); } // 递归 查找父目录 mk_Dir(dirname($path)); return mkdir($path); }
代码
/** * 用迭代的方法 */ function f($n){ $v = 1; // 设定初始值 for($i=9;$i>=$n;--$i){ $v = ($v+1)*2; } return $v; } echo f(1);
递归的执行过程
Length=3
执 行 顺 序
Length=2
Length=1
例子
1. 张三去和李四借钱,李四说你等一下,我 去找王五借给你, 2. 然后李四去找王五借钱,王五说你等一下, 我去找赵六借给你, 3. 最后王五找赵六借钱,赵六借给了王五。 (这里就是递归出口) 4. 王五从赵六那里返回把钱给了李四,李四 从王五那里返回把钱给到张三,最终张三 得到需要的结果,得到钱。
例子
5. 这里有一个规律就是最先执行的最后返回, 比如张三去借钱,一队人转下来最后才会 把钱给到他。这种先进后出的特点,与程 序的执行顺序和堆栈数据结构的特点相一 致。 6. 理解递归,就是忘记递归;即假设问题的 子问题已经解决,从上面的例子说就是假 设李四已经有钱。由此逆推的过程就是问 题的解决过程和算法步骤。
对递归的理解
• 递归很多时候是一个问题最直觉、最方便 的解法。想想快速排序。
• 递归是算法里很能体现把「未知不熟悉的 问题转化为已知熟悉问题」这一数学思想 的。 • 递归的意义在于,在寻求问题的解决思路 时,让人像人一样去思考,让计算机像计 算机一样去计算。
对递归的理解
• 递归的用处:递归最大的益处是,可以简化问题。事实上,有 些问题,不用递归的思想,几大小递 增的圆盘,如何借助B柱,将原盘放到C柱,要求:一次仅能移 动一个原盘 移动中依然要求保持上小下大当n=3,你可能能 很容易算出来,当n=4,应该你二年级可以做,当要说你写出算法。然而,用递归的思想,做这件事, 仅仅是计算量的问题。没有递归,冥思苦想,往往也得不出一 个有效地解决办法。 总之,递归就是给傻人开的一扇窗,给聪 明人留的一个巧。
对递归的理解
• 递归的本质是栈。
• 如果一个算法不需要栈,那么你用递归的 时候,这种递归是可以优化的。只是现实 是很少有语言会进行优化。 • 如果一个算法需要栈,即使你不用递归, 也要手工写一个栈,不如递归方便。
php变量引用、函数引用、对象引用
php的引用(就是在变量或者函数、对象等前 面加上&符号) //最重要就是 删除引用的变 量 ,只是引用的变量访问不了,但是内容并 没有销毁 在PHP 中引用的意思是:不同的名 字访问同一个变量内容. 变量的引用 PHP 的引用允许你用两个变量来指向同一 个内容
• 以上代码是在PHP5中的运行效果 在PHP5中 对象的复制是通过引用来实现的。上列中 $b=new a; $c=$b; 其实等效于$b=new a; $c=&$b; PHP5中默认就是通过引用来调用对 象, 但有时你可能想建立一个对象的副本, 并希望原来的对象的改变不影响到副本 . 为 了这样的目的,PHP定义了一个特殊的方法, 称为__clone.
•
•
•
这意味着,例如,unset $var 不会 unset 全局变量。
$this 在一个对象的方法中,$this 永远是调用它的对象的引用。
•
//下面再来个小插曲 php中对于地址的指向(类似指针)功能不是由用户 自己来实现的,是由Zend核心实现的,php中引用采用的是“写时拷贝” 的原理,就是除非发生写操作,指向同一个地址的变量或者对象是不会 被拷贝的。
代码样例
• 样例问题
一个猴子看一堆桃子,每天,吃了一半,又 多吃一个!当到第十天时,只有一个桃子了。 问题,有几个桃子?
分析
第十天,只有一个桃子,第九天就是(1+1) *2个桃子,假设子问题已经解决,那 f(1)=(f(2)+1)*2,第一天的桃子等于第二天桃子 加1乘以2,上代码:
代码
/** * 递归实现方法 */ function f($n=1){ if($n==10){ return 1; // 递归出口 } return (f($n+1)+1)*2; }
• 示例: <?php $a="ABC"; $b =&$a; echo $a;//这里输出:ABC echo $b;//这里输出:ABC $b="EFG"; echo $a;//这里$a的值变为EFG 所以输出EFG echo $b;//这里输出EFG ?>
• 函数的传址调用: <?php function test(&$a){ $a=$a+100; } $b=1; echo $b;//输出1 test($b); //这里$b传递给函数的其实是$b的变量内容所处的内存地址,通过 在函数里改变$a的值就可以改变$b的值了 echo "<br>"; echo $b;//输出101 ?> 要注意的是,在这里test(1);的话就会出错,原因是:PHP规定传递的引 用不能为常量(可以看错误提示)。
对递归的理解
• 说道递归慢,更多的可能是指类似C语言下的情况;因为递归是 函数调用函数自身,而在类C语言的编程语言下,函数调用是需 要切换CPU和寄存器的上下文环境的,其实就是先把CPU和寄存 器状态压入栈,然后加载函数地址,再初始化CPU和寄存器状 态,最后开始执行函数代码。显然相比较于C语言下,同一问题 的迭代循环方式大多只操作堆上的变量而言,确实是多了很多 次保存上下文环境,压栈出栈,切换寄存器内容和状态。但这 是在更接近与硬件语言的情况下。而在像js和php等解释型语言 下,其本身就是在一个虚拟的执行环境中,其虚拟机的上下文 切换更多是由变量模拟的,所以其执行和响应速度和迭代循环 的差别没有那么大,甚至一些语言(如 Scheme)循环只是递归 的语法糖,并且保证可以用循环解决的问题,递归不会比循环 慢。