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编程最快明白》第二讲 数字、浮点、布尔型、字符串和数组
Nov 01 PHP
PHP中用hash实现的数组
Jul 17 PHP
深入探讨PHP中的内存管理问题
Aug 31 PHP
本地机apache配置基于域名的虚拟主机详解
Aug 10 PHP
php去除字符串换行符示例分享
Feb 13 PHP
PHP之sprintf函数用法详解
Nov 12 PHP
php魔术函数__call()用法实例分析
Feb 13 PHP
修改WordPress中文章编辑器的样式的方法详解
Dec 15 PHP
Zend Framework入门知识点小结
Mar 19 PHP
php使用parse_str实现查询字符串解析到变量中的方法
Feb 17 PHP
PHP7.1实现的AES与RSA加密操作示例
Jun 15 PHP
浅谈laravel-admin form中的数据,在提交后,保存前,获取并进行编辑
Oct 21 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
用php将任何格式视频转为flv的代码
2009/09/03 PHP
解析PHP SPL标准库的用法(遍历目录,查找固定条件的文件)
2013/06/18 PHP
php生成扇形比例图实例
2013/11/06 PHP
PHP实现股票趋势图和柱形图
2015/02/07 PHP
laravel通用化的CURD的实现
2019/12/13 PHP
js的表单操作 简单计算器
2011/12/29 Javascript
Angular Js文件上传之form-data
2015/08/28 Javascript
JS常用函数和常用技巧小结
2016/10/15 Javascript
自动适应iframe右边的高度
2016/12/22 Javascript
jQuery多选框选择数量限制方法
2017/02/08 Javascript
jQuery.cookie.js使用方法及相关参数解释
2017/03/06 Javascript
Javascript中的async awai的用法
2017/05/17 Javascript
详解ES6 Fetch API HTTP请求实用指南
2018/11/14 Javascript
js form表单input框限制20个字符,10个汉字代码实例
2019/04/12 Javascript
Vue调用后端java接口的实例代码
2019/10/28 Javascript
JS script脚本中async和defer区别详解
2020/06/24 Javascript
vue如何使用外部特殊字体的操作
2020/07/30 Javascript
解决vue-loader加载不上的问题
2020/10/21 Javascript
[01:00:30]完美世界DOTA2联赛循环赛 Inki vs Matador BO2第二场 10.31
2020/11/02 DOTA
Python3+OpenCV2实现图像的几何变换(平移、镜像、缩放、旋转、仿射)
2019/05/13 Python
使用Python将字符串转换为格式化的日期时间字符串
2019/09/01 Python
windows、linux下打包Python3程序详细方法
2020/03/17 Python
Python进程的通信Queue、Pipe实例分析
2020/03/30 Python
Python接口测试文件上传实例解析
2020/05/22 Python
Python 中如何写注释
2020/08/28 Python
python3代码输出嵌套式对象实例详解
2020/12/03 Python
处理HTML5新标签的浏览器兼容版问题
2017/03/13 HTML / CSS
美国婚戒购物网站:Anjays Designs
2017/06/28 全球购物
荷兰最大的多品牌男装连锁店:Adam Brandstore
2019/12/31 全球购物
青年教师典范事迹材料
2014/01/31 职场文书
职工运动会感言
2014/02/07 职场文书
有关爱国演讲稿
2014/05/07 职场文书
爱国演讲稿400字
2014/05/07 职场文书
2014年优秀党员材料
2014/12/18 职场文书
冬季作息时间调整通知
2015/04/24 职场文书
Java实现多文件上传功能
2021/06/30 Java/Android