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 相关文章推荐
php mysql数据库操作分页类
Jun 04 PHP
Ajax+PHP 边学边练之四 表单
Nov 27 PHP
UCenter中的一个可逆加密函数authcode函数代码
Jul 20 PHP
php比较两个绝对时间的大小
Jan 31 PHP
php 批量添加多行文本框textarea一行一个
Jun 03 PHP
PHP面试题之文件目录操作
Oct 15 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
Jun 13 PHP
PHP HTTP 认证实例详解
Nov 03 PHP
PHP API接口必备之输出json格式数据示例代码
Jun 27 PHP
php高清晰度无损图片压缩功能的实现代码
Dec 09 PHP
php连接mysql数据库最简单的实现方法
Sep 24 PHP
php使用fputcsv实现大数据的导出操作详解
Feb 27 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
如何去掉文章里的 html 语法
2006/10/09 PHP
给php新手谈谈我的学习心得
2007/02/25 PHP
浅谈PHP错误类型及屏蔽方法
2017/05/27 PHP
PHP实现在对象之外访问其私有属性private及保护属性protected的方法
2017/11/20 PHP
javascript 节点遍历函数
2010/03/28 Javascript
跟我一起学写jQuery插件开发方法(附完整实例及下载)
2010/04/01 Javascript
各情景下元素宽高的获取实现代码
2011/09/13 Javascript
JS中typeof与instanceof之间的区别总结
2013/11/14 Javascript
js中把JSON字符串转换成JSON对象最好的方法
2014/03/21 Javascript
jQuery使用before()和after()在元素前后添加内容的方法
2015/03/26 Javascript
JAVA四种基本排序方法实例总结
2015/07/24 Javascript
jQuery随手笔记之常用的jQuery操作DOM事件
2015/11/29 Javascript
JavaScript基于Dom操作实现查找、修改HTML元素的内容及属性的方法
2017/01/20 Javascript
微信小程序 flex实现导航实例详解
2017/04/26 Javascript
微信小程序之多文件下载的简单封装示例
2018/01/29 Javascript
Vue.js的动态组件模板的实现
2018/11/26 Javascript
优雅的将ElementUI表格变身成树形表格的方法步骤
2019/04/11 Javascript
微信小程序项目总结之记账小程序功能的实现(包括后端)
2019/08/20 Javascript
微信小程序 scroll-view的使用案例代码详解
2020/06/11 Javascript
vue自定义指令和动态路由实现权限控制
2020/08/28 Javascript
JS+CSS实现过渡特效
2021/01/02 Javascript
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
Python用模块pytz来转换时区
2016/08/19 Python
python读取csv和txt数据转换成向量的实例
2019/02/12 Python
解决python打不开文件(文件不存在)的问题
2019/02/18 Python
OpenCV+face++实现实时人脸识别解锁功能
2019/08/28 Python
win10安装python3.6的常见问题
2020/07/01 Python
浅析Python迭代器的高级用法
2020/07/16 Python
利用django创建一个简易的博客网站的示例
2020/09/29 Python
保密工作实施方案
2014/02/24 职场文书
企业年检委托书范本
2014/10/14 职场文书
2015年银行个人工作总结
2015/05/14 职场文书
祝福语集锦:给满月宝宝的祝福语
2019/11/20 职场文书
Apache POI的基本使用详解
2021/11/07 Servers
Python matplotlib绘制雷达图
2022/04/13 Python
Vue深入理解插槽slot的使用
2022/08/05 Vue.js