美文网首页PHP经验分享PHP实战
实战PHP数据结构基础之递归

实战PHP数据结构基础之递归

作者: 萧潇在jianshu | 来源:发表于2018-07-06 21:42 被阅读6次

什么是递归?

之前说到,递归是一种将大问题分解为小问题的解决方案。一般来说,递归被称为函数自身的调用。这么说可能听起来很奇怪,事实上在递归中,函数确实必须调用自己。

一个栗子

例如在数学中,我们都知道“阶乘”的概念。例如5的阶乘就是5*4*3*2*1

  • 5!= 5 * 4!
  • 4!= 4 * 3!
  • 3!= 3 * 2!
  • 2!= 2 * 1!
  • 1!= 1 * 0!
  • 0!= 1

我们可以总结出求n的阶乘的规律,即 n! = n * (n -1) !

这就体现了递归。你可以从中发现,我们把求5的阶乘一步一步转化成了另外一个个的小问题。

递归算法的特性

  • 每一个递归调用都必须基于一个小的子问题。例如5的阶乘就是5乘4的阶乘。
  • 递归必须有一个Base case。例如阶乘的Base case就是0,当条件是0的时候,就停止递归。
  • 递归中避免循环调用,否则最后计算机会显示栈溢出的错误。
function factorial(int $n): int
{
    if ($n = 0) {
        return 1;
    }
    
    return $n * factorial($n - 1);
}

看上面的代码,我们可以看到对于阶乘问题的解决方案我们有一个基础的条件就是当n为0的时候,我们返回1。如果不符合这个条件,我们返回nfactorial(n) ,这符合递归特性的第一条和第三条。我们避免了循环调用,因为我们把每一次的递归调用都分解成了大问题的一个小的子问题。上面的算法思想可以表达成:

clipboard.png

递归Vs迭代

上面的递归代码我们同样可以使用迭代的方法实现

function factorial(int $n): int
{
    $result = 1;
    
    for ($i = $n; $i > 0; $i--) {
        $result*= $n;
    }
    
    return $result;
}

如果一个问题可以很容易的使用迭代来解决,我们为何要使用递归?

递归是用来处理更加复杂的问题的,不是所有的问题都可以简单的使用迭代来解决的。递归使用函数调用来管理调用栈,所以相比于迭代递归会使用更多和时间以及内存。此外,在迭代中,我们每一步都会有一个结果,但是在递归中我们必须等到base case执行结束才会有任何结果。看上面的例子,我们发现在递归算法中我们没有任何变量或者声明来保存结果,而在迭代算法中,我们每一次都用$result来保存了返回结果。

斐波那契数列

在数学中,斐波那契数列是一个特殊的整数数列,数列中的每一个数的是由另外两个数求和产生的。规则如下:

clipboard.png
function fibonacci($n)
{
    if ($n == 0) {
        return 0;
    }
    
    if ($n == 1) {
        return 1;
    }
    
    return fibonacci($n - 1) + fibonacci($ - 2);
}

最大公因数

另外一个使用递归算法的常见问题是求两个数的最大公因数。

clipboard.png
function gcd(int $a, int $b)
{
    if ($b == 0) {
        return $a;
    }
    
    return gcd($b, $a % $b);
}

递归类型

  • 线性递归

在每一次递归调用中,函数只调用自己一次,这就叫做线性递归。

  • 二分递归

在二分递归中,每一次递归调用函数调用自己两次。求解斐波那契数列的算法就是二分递归,除此之外还有二分查找、分治算法、归并排序等也使用了二分递归。

  • 尾递归

当一个递归返回的时候没有等待的操作的时候就称为尾递归。斐波那契算法中,返回值需要乘以前一个递归的返回值,因此他不是尾递归,而求解最大公因式的算法是尾递归。尾递归是线性递归的一种形式。

  • 相互递归

例如在每一次递归调用中 有 A() 调用 B(), B() 调用 A() ,这样的递归就叫做相互递归。

  • 嵌套递归

当一个递归函数把自己作为一个参数进行递归调用时,就叫做嵌套递归。一个常见的栗子就是阿克曼函数,看下面的表达。

clipboard.png

看最后一行的,可以看到第二个参数就是递归函数自己。

下一节

下一篇内容会使用递归解决一些实际开发中会遇到的问题,例如构建N级分类、构建嵌套评论、目录文件的遍历等等。

更多内容

PHP基础数据结构专题系列目录地址:https://github.com/... 主要使用PHP语法总结基础的数据结构和算法。还有我们日常PHP开发中容易忽略的基础知识和现代PHP开发中关于规范、部署、优化的一些实战性建议,同时还有对Javascript语言特点的深入研究。

相关文章

  • 实战PHP数据结构基础之递归

    什么是递归? 之前说到,递归是一种将大问题分解为小问题的解决方案。一般来说,递归被称为函数自身的调用。这么说可能听...

  • 实战PHP数据结构基础之栈

    栈和队列 栈和队列和之前讲到的实战PHP数据结构基础之双链表 一样都是线性结构。 栈有什么特点 栈遵循后进先出的原...

  • 实战PHP数据结构基础之队列

    什么是队列 队列是另外一种遵循先进先出原则的线性数据结构。队列有两端可供操作,一端出队,一端入队。这个特点和栈不同...

  • 实战PHP数据结构基础之双链表

    什么是双链表? 上一篇实战PHP数据结构基础之单链表说到 单链表由一个一个的作为节点的对象构成的,每一个节点都有指...

  • 实战PHP数据结构基础之单链表

    什么是链表? 链表由一个一个的作为节点的对象构成的,每一个节点都有指向下一个节点的指针,最后一个节点的指针域指向空...

  • PHP中一些函数方法

    php自定义函数之递归函数 php自定义函数之静态变量 php​ 使用系统内置函数 亚麻跌”是PHP学习时间处理的...

  • PHP Socket 编程实战总结

    在进入 PHP Socket 编程实战之前,我们先来了解一下 PHP Socket 的一些基础知识。 一、基础部分...

  • 数据结构之递归

    数据结构之递归 1.递归的概念 简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量.递归有助于编程者解...

  • 一. PHP入门篇和PHP进阶篇

    PHP基础语法 PHP数组 PHP函数 PHP之类和对象 PHP字符串 PHP之正则表达式 PHP之cookie ...

  • PHP基础与案例开发详解

    《PHP基础与案例开发详解》本书以目前PHP的较新版本PHP为依托,结合PHP语言特性和实战案例,充分融入了企业开...

网友评论

  • JasonChenc1:递归更考脑子
    萧潇在jianshu:还有动态规划 回溯 这些内容。可能确实比写一般的业务需要多思考一点

本文标题:实战PHP数据结构基础之递归

本文链接:https://www.haomeiwen.com/subject/tvtiuftx.html