﻿
<h1 class=p1>Что такое рекурсия</h1>
<br>
<br>
<p class=text><b>Рекурсией</b> называется такая конструкция, при которой функция вызывает саму себя. Различают прямую и косвенную рекурсии. Функция называется прямо рекурсивной, если содержит в своем теле вызов самой себя. Если же функция вызывает другую функцию, которая в свою очередь вызывает первую, то такая функция называется косвенно рекурсивной.</p>
<p class=text>Рассмотрим классические примеры использования рекурсии - реализацию операции возведения в степень и вычисление факториала числа. Заметим, что эти примеры являются классическими только из-за их удобства для объяснения понятия рекурсии, однако они не дают выигрыша в программной реализации по сравнению с итерационным способом решения этих задач.</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <em class=gr>function</em> <b>degree</b><em class=gr>(</em><b>$x,$y</b><em class=gr>)</em>
  <em class=gr>{</em>
    <em class=gr>if(</em><b>$y</b><em class=gr>)</em>
    <em class=gr>{</em>
      <em class=gr>return</em> <b>$x</b><em class=gr>*</em>degree<em class=gr>(</em><b>$x</b>,<b>$y</b><em class=gr>-</em>1<em class=gr>);</em>
    <em class=gr>}</em>
    <em class=gr>return</em> 1<em class=gr>;</em>
  <em class=gr>}
  echo(</em><b>degree</b><em class=gr>(</em>2,4<em class=gr>));</em><em class=comnt> // выводит 16</em>
<em class=red>?&gt;</em>
</pre></blockquote>

<p class=text>Этот пример основан на том, что <b>x<sup><sup><sup><sup>y</sup></sup></sup></sup></b>  эквивалентно <b>x*x<sup><sup><sup><sup>(y-1)</sup></sup></sup></sup></b>. В этом коде задача вычисления <b>2<sup><sup><sup><sup>4</sup></sup></sup></sup></b> разбивается на вычисление <b>2*2&#179;</b>. Затем <b>2*2&#179;</b> разбивается на <b>2*2&#178;</b> и так до тех пор, пока показатель не станет равным нулю.</p>
<p class=text>Итерационный вариант этого примера выглядит так:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <em class=gr>function</em> <b>degree</b><em class=gr>(</em><b>$x,$y</b><em class=gr>)
  {
    for(</em><b>$result</b><em class=gr> = </em>1<em class=gr>;</em> <b>$y</b><em class=gr> > </em>0<em class=gr>;</em> <b>--$y</b><em class=gr>)</em>
    <em class=gr>{</em>
      <b>$result</b><em class=gr> *= </em><b>$x</b><em class=gr>;
    }
    return</em> <b>$result</b><em class=gr>;
  }
  echo(</em>degree<em class=gr>(</em>2,4<em class=gr>));</em><em class=comnt> // выводит 16</em>
<em class=red>?&gt;</em>
</pre></blockquote>

<p class=text>Кроме того, что этот код намного легче понять, он еще и более эффективен, поскольку проход цикла обходится "дешевле" вызова функции.</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <em class=gr>function</em> <b>fact</b><em class=gr>(</em><b>$x</b><em class=gr>)
  {
    if (</em><b>$x</b><em class=gr> < </em>0<em class=gr>)</em> <em class=gr>return</em> 0<em class=gr>;
    if (</em><b>$x</b><em class=gr> == </em>0<em class=gr>)</em> <em class=gr>return</em> 1<em class=gr>;
    return</em> <b>$x</b><em class=gr> * </em><b>fact</b><em class=gr>(</em><b>$x</b><em class=gr> - </em>1<em class=gr>);
  }
  echo (</em><b>fact</b><em class=gr>(</em>3<em class=gr>));</em><em class=comnt> // выводит 6</em>
<em class=red>?&gt;</em>
</pre></blockquote>

<p class=text>Для отрицательного аргумента функция возвращает нулевое значение, так как факториал отрицательного числа не существует по определению. Для нулевого параметра функция возвращает значение 1, поскольку 0! = 1. В иных случаях вызывается та же функция с уменьшенным на 1 значением параметра, после чего результат умножается на текущее значение параметра. Т. е. происходит вычисление произведения:</p>
<blockquote><pre>
k * (k - 1) * (k - 2) * ... * 3 * 2 * 1 * 1
</pre></blockquote>

<p class=text>Последовательность рекурсивных вызовов прерывается только при вызове <b>fact(0)</b>, который и приводит к последнему значению 1 в произведении, так как последнее выражение, из которого вызывается функция, имеет вид 1 * <b>fact</b>(1 - 1).</p>
<p class=text>Итерационно факториал можно вычислить так:</p>
<blockquote><pre>
<em class=red>&lt;?</em>
  <em class=gr>function</em> <b>fact</b><em class=gr>(</em><b>$x</b><em class=gr>)</em>
  <em class=gr>{
    for (</em><b>$result</b><em class=gr> = </em>1<em class=gr>; </em><b>$x</b><em class=gr> > </em>1<em class=gr>;</em> <b>--$x</b><em class=gr>)
    {</em>
      <b>$result</b><em class=gr> *= </em><b>$x</b><em class=gr>;
    }
    return</em> <b>$result</b><em class=gr>;
  }
  echo (</em><b>fact</b><em class=gr>(</em>6<em class=gr>));</em><em class=comnt> // выводит 720</em>
<em class=red>?&gt;</em>
</pre></blockquote>
