php实现递归的三种基本方式


Posted in PHP onJuly 04, 2020

递归函数是我们常用到的一类函数,最基本的特点是函数自身调用自身,但必须在调用自身前有条件判断,否则无限无限调用下去。实现递归函数可以采取什么方式呢?本文列出了三种基本方式。理解其原来需要一定的基础知识水品,包括对全局变量,引用,静态变量的理解,也需对他们的作用范围有所理解。递归函数也是解决无限级分类的一个很好地技巧。如果对无限级分类感兴趣,请参照php利用递归函数实现无限级分类。我习惯套用通俗的话解释复杂的道理,您确实不明白请参见手册。

利用引用做参数

先不管引用做不做参数,必须先明白引用到底是什么?引用不过是指两个不同名的变量指向同一块存储地址。本来每个变量有各自的存储地址,赋值删除各行其道。现在可好,两个变量共享一块存储地址。 $a=&$b; 。实际上指的是 $a 不管不顾自己原来的存储地址,非要和 $b 共享一室了。因而任何对存储地址数值的改变都会影响两个值。

函数之间本来也是各行其是,即便是同名函数。递归函数是考虑将引用作为参数,成为一个桥梁,形成两个函数间的数据共享。虽然两个函数见貌似操作的是不同地址,但是实际上操作的是一块儿内存地址。

function test($a=0,&$result=array()){
$a++;
if ($a<10) {
 $result[]=$a;
 test($a,$result);
}
echo $a;
return $result;

}

上面的例子非常简答,以a<10作为判断条件,条件成立,则把a赋给result[];将result的引用传入函数,会将每一次递归产生的a添加到结果数组result。因而本例生成的$result数组是 Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8 [8] => 9 ) 。

本例比较有意思的是echo a的值。相信很多人认为是12345678910吧,其实不然,是1098765432。为什么呢?因为函数还没执行echoa前就进行了下一次的函数递归。真正执行echo a是当a<10条件不满足的时候,echo a,返回result,对于上一层而言,执行完递归函数,开始执行本层的echo $a,依次类推。

例子二、

PHP 的引用允许用两个变量来指向同一个内容,例如 $a = &$b; 这意味着 $a 和 $b 指向了同一个变量。

如下例子,因为 $data 使用了引用传递,所以数据会一直累加。

function recursion(&$data = [], $i = 0)
{
  if ($i < 10) {
    $data[] = $i;
    $i++;
    $this->recursion($data, $i);
  }
  return $data;
}
// 调用
$this->recursion();  // [0,1,2,3,4,5,6,7,8,9]

利用全局变量

利用全局变量完成递归函数,请确保你确实理解什么是全局变量。global在函数内申明变量不过是外部变量的同名引用。变量的作用范围仍然在本函数范围内。改变这些变量的值,外部同名变量的值自然也改变了。但一旦用了&,同名变量不再是同名引用。利用全局变量实现递归函数没必要理解到这么深的一层,还保持原有对全局变量的看法就可以顺理成章理解递归函数。

function test($a=0,$result=array()){
 global $result;
 $a++;
 if ($a<10) {
  $result[]=$a;
  test($a,$result);
 }
 return $result;
}

global 在函数内申明变量不过是外部变量的同名引用。变量的作用范围仍然在本函数范围内。改变这些变量的值,外部同名变量的值自然也改变了。

function recursion($data = [], $i = 0)
{
  global $data;
  if ($i < 10) {
    $data[] = $i;
    $i++;
    $this->recursion($data, $i);
  }
  return $data;
}
 
// 调用
$this->recursion();  // [0,1,2,3,4,5,6,7,8,9]

利用静态变量

我们常常在类中见到static,今天我们把它利用到递归函数中。请记住static的作用:仅在第一次调用函数的时候对变量进行初始化,并且保留变量值。

举个栗子:

function test(){
static $count=0;
echo $count;

$count++;
}
test();
test();
test();
test();
test();

请问这一段代码的执行结果是多少?是00000么?必然不是。是01234。首先第一次调用test(),static对 $count 进行初始化,其后每一次执行完都会保留 $count 的值,不再进行初始化,相当于直接忽略了 static $count=0; 这一句。

因而将static应用到递归函数作用可想而知。在将需要作为递归函数间作为“桥梁"的变量利用static进行初始化,每一次递归都会保留"桥梁变量"的值。

function test($a=0){
 static $result=array();
 $a++;
 if ($a<10) {
  $result[]=$a;
  test($a);
 }
 return $result;
}

静态变量只在第一次调用时初始化。仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。

function recursion($i = 0)
{
  static $data = [];
  if ($i < 10) {
    $data[] = $i;
    $i++;
    $this->recursion($i);
  }
  return $data;
}
 
// 调用
$this->recursion();  // [0,1,2,3,4,5,6,7,8,9]

总结

 所谓递归函数,重点是如何处理函数调用自身是如何保证所需要的结果得以在函数间合理"传递",当然也有不需要函数之间传值得递归函数,例如:

function test($a=0){
 $a++;
 if ($a<10) {
  echo $a;

  test($a);
 }
}

面对这样的函数,我们就不必大伤脑筋了。顺便说一句,深入理解变量引用相关知识对解决这类问题大有裨益。

最后给大家分享一个php实现递归与无限分类的方法,具体实现方法如下:

<?php
echo "<pre>";
$area = array(
array('id'=>1,'area'=>'北京','pid'=>0),
array('id'=>2,'area'=>'广西','pid'=>0),
array('id'=>3,'area'=>'广东','pid'=>0),
array('id'=>4,'area'=>'福建','pid'=>0),
array('id'=>11,'area'=>'朝阳区','pid'=>1),
array('id'=>12,'area'=>'海淀区','pid'=>1),
array('id'=>21,'area'=>'南宁市','pid'=>2),
array('id'=>45,'area'=>'福州市','pid'=>4),
array('id'=>113,'area'=>'亚运村','pid'=>11),
array('id'=>115,'area'=>'奥运村','pid'=>11),
array('id'=>234,'area'=>'武鸣县','pid'=>21)
);
function t($arr,$pid=0,$lev=0){
static $list = array();
foreach($arr as $v){
if($v['pid']==$pid){
echo str_repeat(" ",$lev).$v['area']."<br />";
//这里输出,是为了看效果
$list[] = $v;
t($arr,$v['id'],$lev+1);
}
}
return $list;
}
$list = t($area);
echo "<hr >";
print_r($list);
?>

到此这篇关于php实现递归的三种基本方式的文章就介绍到这了,更多相关php 递归内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
在smarty模板中使用PHP函数的方法
Apr 23 PHP
session在PHP大型web应用中的使用
Jun 25 PHP
PHP实现的交通银行网银在线支付接口ECSHOP插件和使用例子
May 10 PHP
php中json_encode处理gbk与gb2312中文乱码问题的解决方法
Jul 10 PHP
linux下编译安装memcached服务
Aug 03 PHP
PHP设计模式之装饰者模式代码实例
May 11 PHP
PHP基于MySQL数据库实现对象持久层的方法
Jun 17 PHP
php上传图片生成缩略图(GD库)
Jan 06 PHP
PHP实现基于回溯法求解迷宫问题的方法详解
Aug 17 PHP
PHP操作redis实现的分页列表,新增,删除功能封装类与用法示例
Aug 04 PHP
PHP判断访客是否手机端(移动端浏览器)访问的方法总结【4种方法】
Mar 27 PHP
PHP7 mongoDB扩展使用的方法分享
May 02 PHP
php析构函数的简单使用说明
Aug 24 #PHP
分享微信扫码支付开发遇到问题及解决方案-附Ecshop微信支付插件
Aug 23 #PHP
dvwa+xampp搭建显示乱码的问题及解决方案
Aug 23 #PHP
详细解读PHP的Yii框架中登陆功能的实现
Aug 21 #PHP
使用PHP进行微信公众平台开发的示例
Aug 21 #PHP
PHP的Yii框架的基本使用示例
Aug 21 #PHP
PHP的Yii框架使用中的一些错误解决方法与建议
Aug 21 #PHP
You might like
一个SQL管理员的web接口
2006/10/09 PHP
《PHP编程最快明白》第三讲:php数组
2010/11/01 PHP
在smarty模板中使用PHP函数的方法
2011/04/23 PHP
PHP调用Linux的命令行执行文件压缩命令
2013/01/27 PHP
php实现图片局部打马赛克的方法
2015/02/11 PHP
php简单实现单态设计模式的方法分析
2017/07/28 PHP
JS 自定义函数缺省值的设置方法
2010/05/05 Javascript
onclick与listeners的执行先后问题详细解剖
2013/01/07 Javascript
简洁Ajax函数处理(示例代码)
2013/11/15 Javascript
fckeditor粘贴Word时弹出窗口取消的方法
2014/10/30 Javascript
jQuery制作图片旋转效果
2017/02/02 Javascript
jquery使用EasyUI Tree异步加载JSON数据(生成树)
2017/02/11 Javascript
使用命令行工具npm新创建一个vue项目的方法
2017/12/27 Javascript
实现jquery放大镜的两种方法
2018/02/22 jQuery
基于vue循环列表时点击跳转页面的方法
2018/08/31 Javascript
Vue 实现手动刷新组件的方法
2019/02/19 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
小程序富文本提取图片可放大缩小
2020/05/26 Javascript
[41:08]2014 DOTA2国际邀请赛中国区预选赛 HGT VS NE
2014/05/22 DOTA
[04:52]DOTA2亚洲邀请赛附加赛 TOP10精彩集锦
2015/01/29 DOTA
Django中Model的使用方法教程
2018/03/07 Python
python 日期排序的实例代码
2019/07/11 Python
python中update的基本使用方法详解
2019/07/17 Python
Django 用户登陆访问限制实例 @login_required
2020/05/13 Python
Python使用windows设置定时执行脚本
2020/11/12 Python
详解HTML5中的元素与元素
2015/08/17 HTML / CSS
戛纳奢侈品商店:Jacques Loup法国
2019/11/04 全球购物
英国奢侈品牌时尚购物平台:Farfetch(支持中文)
2020/02/18 全球购物
市场营销专科应届生求职信
2013/11/24 职场文书
九年级历史教学反思
2014/01/27 职场文书
中秋节礼品促销方案
2014/02/02 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
2014年底工作总结
2014/12/15 职场文书
新教师教学工作总结
2015/08/12 职场文书
寒假致家长的一封信
2015/10/10 职场文书
使用CSS连接数据库的方式
2022/02/28 HTML / CSS