Рекурсия. Уроки PHP. Рекурсия Php функция которая возвращает факториал числа

Данный урок посвящен рекурсии в PHP. Из функции можно вызывать другую функцию. Программа может вызвать функцию f1(), которая вызывает функцию f2(), и т.д. Вызывающая себя функция называется рекурсивной. Такой тип рекурсии называется явной рекурсией. Если функция f1() вызывает другую функцию f2(), которая в свою очередь вызывает функцию f1(), то эти функции также рекурсивные. Такой тип рекурсии называется неявной рекурсией. Очевидно, что возможны более сложные формы неявной рекурсии.

Предположим, что для решения некоторой задачи нужно создать рекурсивную функцию. В этом уроке опишем одну из известных стратегий решения задачи с использованием рекурсивной функции. Процесс рекурсивного решения задачи разделяется на этапы. На первом шаге для решения задачи вызывается рекурсивная функция. В этой функции задача решается для простейшей ситуации. Простейшая ситуация данной задачи называется базисной задачей. Если функция используется для решения базисной задачи, то она возвращает решение или результат.

Если функция вызывается для решения задачи более сложной, чем базисная задача, то функция разделяет задачу на две части:

  • часть 1, которую функция может решить;
  • часть 2, которую функция не может решить.

Для применения рекурсии часть 2 должна быть подобна начальной задаче, но относительно меньше или проще.

Так как образовавшаяся в части 2 задача подобна начальной задаче, поэтому функция вызывает новый собственный экземпляр с целью обработки новой задачи. Это действие называется рекурсивным вызовом или шагом рекурсии.

Так как на каждом шаге рекурсии (при каждом рекурсивном вызове) задача делится на две части, поэтому то количество этих шагов рекурсии может быть достаточно большое.

Для завершения рекурсии рекурсивная функция должна образовать последовательность упрощающихся (уменьшающихся) задач, которые приближаются к базисной задаче. Когда, на каком-то шаге рекурсии, функция обнаруживает базисную задачу, она возвращает решение (результат) базисной задачи в предыдущий вызов (предыдущий шаг рекурсии). В этом вызове, в свою очередь, полученный результат объединяется с частью, которую функция может решить. Образовавшееся таким путем решение возвращается на шаг выше, и т.д. Так генерируется последний результат, который возвращается в начальную точку вызова рекурсивной функции. То есть, чтобы был возможен возврат, каждый шаг функции нужно строить таким образом, чтобы он содержал в себе зарезервированное слово return.

Для демонстрации вышеизложенной идеи приведем пример использования рекурсивной функции.

Пример 1. Факториал. Факториал целого неотрицательного числа n равен n*(n-1)*(n-2)*...2*1 и обозначается n!. Принято, что 1!=1 и 0!=1. Например, 7!=7*6*5*4*3*2*1=5040.

Итеративное (нерекурсивное) решение для вычисления факториала таково (файл factorial1.php):



Факториал



Вычисление факториала



Адади натурали (n>=0):





";
exit;
}
$f=1;
for($i=$n;$i>=1;$i--)
$f*=$i;
echo "$n!=$f";
?>

Пусть f(n)=n!, тогда
f(n)=n!=n*(n-1)!=n*f(n-1),
то есть рекурсивная формула вычисления факториала такова:
f(n)=n*f(n-1).

Пример:
f(5)=5*f(4)=5*4*f(3)=5*4*3*f(2)= 5*4*3*2*f(1)= 5*4*3*2*1=120.

На основе рекурсивной формулы составим рекурсивную функцию для вычисления факториала (файл factorial2.php):



Факториал



Вычисление факториала



Адади натурали (n>=0):




if(!isset($_GET["n"]) || ($n = $_GET["n"])=="") {
echo "Введите натуральное число!
";
exit;
}
$f=factorial($n);
echo "$n!=$f";

function factorial($i) {
if($i<2) return 1;
$k=$i*factorial($i-1);
return $k;
}

?>

Если в программу ввести число 5, то для вычисления 5! программа действует следующим образом:

При первом вызове функции factorial() проверяется является ли посланное функции число меньше 2. Если полученное функцией число не меньше 2, то задача больше или сложнее базисной задачи, следовательно, задача делится на две части:

  1. $k=$i* - часть 1, которую функция может решить;
  2. factorial($n-1) – часть 2, которую функция не может решить.

Это действие повторяется до получения базисной задачи, то есть до вызова factorial(1). Если число меньше 2 (1 или 0), то функция factorial() возвращает число 1 ($k=1), то есть решается базисная задача. Если данный экземпляр функции factorial() был вызван ранее другим экземпляром функции factorial(), то результат возвращается вызвавшему экземпляру функции. Там возращенный результат $k умножается на переданный функции параметр $n и присваивается $k. Если данный экземпляр функции factorial() был вызван ранее другим экземпляром функции factorial(), то результат возвращается вызвавшему экземпляру функции и описанный процесс повторяется. Если данный экземпляр функции factorial() был вызван из главной части программы, то $k возвращается в эту часть, где результат выводится на экран и работа программы завершается.

Может ли кто-нибудь объяснить мне рекурсивную функцию в PHP (без использования Фибоначчи) на языке неспециалистов и на примерах? Я искал пример, но Фибоначчи полностью потерял меня!

Заранее спасибо;-) Кроме того, как часто вы используете их в веб-разработке?

17 ответов 17

Условия Laymens:

Рекурсивная функция - это функция, которая сама вызывает

Чуть подробнее:

Если функция продолжает вызывать себя, как она узнает, когда остановиться? Вы создали условие, известное как базовый вариант. Базовые случаи сообщают нашему рекурсивному вызову, когда нужно остановиться, иначе он будет повторяться бесконечно.

Хорошим примером обучения для меня, так как я хорошо разбираюсь в математике, был

<--calling itself. } }

Что касается использования рекурсивных функций в веб-разработке, я лично не прибегаю к использованию рекурсивных вызовов. Не то чтобы я считал плохой практикой полагаться на рекурсию, но они не должны быть вашим первым вариантом. Они могут быть смертельными, если не используются должным образом.

Хотя я не могу конкурировать с примером каталога, я надеюсь, что это поможет.

(20.04.10) Обновление:

Также было бы полезно проверить этот вопрос, где принятый ответ демонстрирует в терминах непрофессионалов, как работает рекурсивная функция. Несмотря на то, что вопрос ОП касался Java, концепция та же самая,

2017-05-23 11: 33: 24Z

Примером может быть печать каждого файла в любых подкаталогах данного каталога (если у вас нет символических ссылок внутри этих каталогов, которые могут как-то нарушать функцию). Псевдокод печати всех файлов выглядит следующим образом:

Function printAllFiles($dir) { foreach (getAllDirectories($dir) as $f) { printAllFiles($f); // here is the recursive call } foreach (getAllFiles($dir) as $f) { echo $f; } }

Идея состоит в том, чтобы сначала распечатать все подкаталоги, а затем файлы текущего каталога. Эта идея применяется ко всем подкаталогам, и это является причиной рекурсивного вызова этой функции для всех подкаталогов.

Если вы хотите попробовать этот пример, вы должны проверить специальные каталоги. и.. , в противном случае вы все время застреваете в вызове printAllFiles(".") . Кроме того, вы должны проверить, что печатать и каков ваш текущий рабочий каталог (см. opendir() , getcwd() , ...).

2013-11-18 14: 16: 52Z

Рекурсия - это то, что повторяется. Как функция, которая вызывает себя изнутри. Позвольте мне продемонстрировать несколько псевдо-пример:

Представь, что твои приятели пьют пиво, но твоя жена собирается тебя убить, если ты не вернешься домой до полуночи. Для этого давайте создадим функцию orderAndDrinkBeer ($time), где $time - полночь минус время, потраченное на завершение напитка и возвращение домой.

Итак, придя в бар, вы заказываете свое первое пиво и начинаете пить:

$timeToGoHome = "23"; // Let"s give ourselves an hour for last call and getting home function orderAndDrinkBeer($timeToGoHome) { // Let"s create the function that"s going to call itself. $beer = New Beer(); // Let"s grab ourselves a new beer $currentTime = date("G"); // Current hour in 24-hour format while ($beer->status != "empty") { // Time to commence the drinking loop $beer->drink(); // Take a sip or two of the beer(or chug if that"s your preference) } // Now we"re out of the drinking loop and ready for a new beer if ($currentTime < $timeToGoHome) { // BUT only if we got the time orderAndDrinkBeer($timeToGoHome); // So we make the function call itself again! } else { // Aw, snap! It is time:S break; // Let"s go home:(} }

Теперь давайте просто надеяться, что вы не смогли выпить достаточно пива, чтобы стать настолько опьяненными, что ваша жена заставит вас спать на диване, несмотря на то, что вы не дома вовремя -.-

Но да, именно так и происходит рекурсия.

2010-10-27 10: 59: 35Z

Это функция, которая вызывает сама себя. Это полезно для обхода определенных структур данных, которые повторяются, таких как деревья. HTML DOM - классический пример.

Пример древовидной структуры в javascript и рекурсивной функции для «обхода» дерева.

1 / \ 2 3 / \ 4 5

Var tree = { id: 1, left: { id: 2, left: null, right: null }, right: { id: 3, left: { id: 4, left: null, right: null }, right: { id: 5, left: null, right: null } } };

Для обхода дерева мы неоднократно вызываем одну и ту же функцию, передавая дочерние узлы текущего узла одной и той же функции. Затем мы снова вызываем функцию, сначала слева, а затем справа.

В этом примере мы получим максимальную глубину дерева

Var depth = 0; function walkTree(node, i) { //Increment our depth counter and check i++; if (i > depth) depth = i; //call this function again for each of the branch nodes (recursion!) if (node.left != null) walkTree(node.left, i); if (node.right != null) walkTree(node.right, i); //Decrement our depth counter before going back up the call stack i--; }

Наконец, мы вызываем функцию

Alert("Tree depth:" + walkTree(tree, 0));

Отличным способом понимания рекурсии является пошаговое выполнение кода во время выполнения.

2010-04-15 22: 15: 09Z

Это очень просто, когда функция вызывает себя для выполнения задачи для неопределенного и конечного числавремя Пример из моего собственного кода, функция для заполнения многоуровневым деревом категорий

Function category_tree($parent=0,$sep="") { $q="select id,name from categorye where parent_id=".$parent; $rs=mysql_query($q); while($rd=mysql_fetch_object($rs)) { echo("id."">".$sep.$rd->name.""); category_tree($rd->id,$sep."--"); } }

2010-10-27 12: 44: 20Z

Рекурсия - это причудливый способ сказать: «Делай это снова, пока не сделаешь».

Две важные вещи:

  1. Базовый случай. У вас есть цель, к которой можно добраться.
  2. Тест - как узнать, попал ли ты туда, куда собираешься.

Представьте себе простую задачу: сортируйте стопку книг по алфавиту. Простым процессом было бы взять первые две книги, отсортировать их. Теперь вот рекурсивная часть: есть ли еще книги? Если так, сделайте это снова. «Сделай это снова» - это рекурсия. «Есть ли еще книги» - это тест. И «нет, книг больше нет» - это базовый случай.

2010-04-15 21: 48: 00Z

Это потому, что одно:

Функция при вызове создается в памяти (создается новый экземпляр)

Таким образом, рекурсивная функция НЕ ВЫЗЫВАЕТСЯ , а вызывает другой экземпляр - так что в памяти нет ни одной функции, выполняющей магию. Его пара экземпляров в памяти, которые возвращают себе некоторые значения - и это поведение такое же, когда, например, функция a вызывает функцию b. У вас есть два экземпляра, а также если бы рекурсивная функция вызывала новый экземпляр самого себя.

Попробуйте нарисовать память экземплярами на бумаге - это будет иметь смысл.

2017-04-14 05: 17: 49Z

Рекурсия - это альтернатива циклам, они редко придают вашему коду большую ясность или элегантность. Хороший пример был дан ответом Progman: если он не будет использовать рекурсию, он будет вынужден отслеживать, в каком каталоге он в настоящее время (это называется состоянием) рекурсии, позволяет ему вести бухгалтерию, используя стек (область, где переменные и обратный адрес метода сохраняются)

Стандартные примеры факториала и Фибоначчи бесполезны для понимания концепции, поскольку их легко заменить циклом.

2010-04-15 21: 46: 11Z

В основном это. Он продолжает называть себя, пока не закончится

Void print_folder(string root) { Console.WriteLine(root); foreach(var folder in Directory.GetDirectories(root)) { print_folder(folder); } }

Также работает с циклами!

Void pretend_loop(int c) { if(c==0) return; print "hi"; pretend_loop(c-); }

Вы также можете попробовать поискать его в Google. Обратите внимание на «Вы имели в виду» (нажмите на него...). http://www.google.com/search?q=recursion&spell= 1 р>

2015-08-14 09: 56: 52Z

Вот практический пример (уже есть несколько хороших). Я просто хотел добавить тот, который будет полезен практически любому разработчику.

В какой-то момент разработчикам потребуется проанализировать объект, как в ответе API или какого-либо типа объекта или массива.

Эта функция изначально вызывается для анализа объекта, который может содержать только параметры, но что, если объект также содержит другие объекты или массивы? Это нужно будет решить, и по большей части основная функцияуже делает это, поэтому функция просто вызывает себя снова (после подтверждения того, что ключ или значение является объектом или массивом) и анализирует этот новый объект или массив. В конечном итоге возвращается строка, которая создает каждый параметр в строке отдельно для удобства чтения, но вы также можете легко записать значения в файл журнала или вставить в БД или что-то еще.

Я добавил параметр $prefix , чтобы использовать родительский элемент для описания конечной переменной, чтобы мы могли видеть, к чему относится значение. Он не включает в себя такие вещи, как нулевые значения, но это можно изменить из этого примера.

Если у вас есть объект:

$apiReturn = new stdClass(); $apiReturn->shippingInfo = new stdClass(); $apiReturn->shippingInfo->fName = "Bill"; $apiReturn->shippingInfo->lName = "Test"; $apiReturn->shippingInfo->address1 = "22 S. Deleware St."; $apiReturn->shippingInfo->city = "Chandler"; $apiReturn->shippingInfo->state = "AZ"; $apiReturn->shippingInfo->zip = 85225; $apiReturn->phone = "602-312-4455"; $apiReturn->transactionDetails = array("totalAmt" => "100.00", "currency" => "USD", "tax" => "5.00", "shipping" => "5.00"); $apiReturn->item = new stdClass(); $apiReturn->item->name = "T-shirt"; $apiReturn->item->color = "blue"; $apiReturn->item->itemQty = 1;

и используйте:

Var_dump($apiReturn);

он вернется:

object (stdClass) # 1 (4) {["shippingInfo"] = > object (stdClass) # 2 (6) {["fName"] = > string (4) "Bill" ["lName"] = > string (4) "Test" ["address1"] = > Строка (18) "22 S. Deleware St." [ "Город"] = > string (8) "Chandler" ["state"] = > string (2) "AZ" ["zip"] = > int (85225)} ["phone"] = > string (12) "602-312-4455" ["actionDetails "] = > array (4) {["totalAmt"] = > string (6) "100.00" ["currency"] = > string (3) "USD" ["tax"] = > string (4) "5.00" ["shipping"] = > string (4) "5.00"} ["item"] = > object (stdClass) # 3 (3) {["name"] = > string (7) "Футболка" ["color"] = > string (4) "blue" ["itemQty"] = > int (1)}}

и вот код для его разбора на строку с разрывом строки для каждого параметра:

Function parseObj($obj, $prefix = ""){ $stringRtrn = ""; foreach($obj as $key=>$value){ if($prefix){ switch ($key) { case is_array($key): foreach($key as $k=>$v){ $stringRtrn .= parseObj($key, $obj); } break; case is_object($key): $stringRtrn .= parseObj($key, $obj); break; default: switch ($value) { case is_array($value): $stringRtrn .= parseObj($value, $key); break; case is_object($value): $stringRtrn .= parseObj($value, $key); break; default: $stringRtrn .= $prefix ."_". $key ." = ". $value ."
"; break; } break; } } else { // end if($prefix) switch($key){ case is_array($key): $stringRtrn .= parseObj($key, $obj); break; case is_object($key): $stringRtrn .= parseObj($key, $obj); break; default: switch ($value) { case is_array($value): $stringRtrn .= parseObj($value, $key); break; case is_object($value): $stringRtrn .= parseObj($value, $key); break; default: $stringRtrn .= $key ." = ". $value ."
"; break; } // end inner switch } // end outer switch } // end else } // end foreach($obj as $key=>$value) return $stringRtrn; } // END parseObj()

Это вернет объект следующим образом:

ShippingInfo_fName = Bill shippingInfo_lName = Test shippingInfo_address1 = 22 S. Deleware St. shippingInfo_city = Chandler shippingInfo_state = AZ shippingInfo_zip = 85225 phone = 602-312-4455 transactionDetails_totalAmt = 100.00 transactionDetails_currency = USD transactionDetails_tax = 5.00 transactionDetails_shipping = 5.00 item_name = T-shirt item_color = blue item_itemQty = 1

Я сделал операторы вложенного переключателя , чтобы избежать путаницы с if . . . ifelse . . . else , но это было почти так же долго. Если это поможет, просто попросите условные выражения if, и я могу вставить их для тех, кто в этом нуждается.

2017-01-15 20: 40: 28Z

Хорошим примером является прогулка по дереву каталогов. Вы можете сделать что-то подобное для обработки массива. Вот действительно простая рекурсивная функция, которая просто обрабатывает строку, простой массив строк или вложенный массив строк любой глубины, заменяя экземпляры "hello" на "goodbye" в строке или значениях массива или любого другого вложенный массив:

Function replaceHello($a) { if (! is_array($a)) { $a = str_replace("hello", "goodbye", $a); } else { foreach($a as $key => $value) { $a[$key] = replaceHello($value); } } return $a }

Он знает, когда выйти, потому что в определенный момент обрабатываемая им вещь не является массивом. Например, если вы вызываете replaceHello («привет»), он вернет «до свидания». Если вы отправите ему массив строк, хотя он будет вызывать себя один раз для каждого члена массива, тогда верните обработанный массив.

2014-07-04 22: 16: 16Z

Если вы добавите определенное значение (скажем, «1») к примеру Энтони Форлони, все будет ясно:

Function fact(1) { if (1 === 0) { // our base case return 1; } else { return 1 * fact(1-1); // <--calling itself. } }

оригинал:

Function fact($n) { if ($n === 0) { // our base case return 1; } else { return $n * fact($n-1); // <--calling itself. } }

2014-07-21 06: 49: 29Z

Это очень простой пример факториала с помощью рекурсии:

Факториалы - это очень простая математическая концепция. Они написаны как 5! а это значит 5 * 4 * 3 * 2 * 1. Итак 6! это 720 и 4! это 24.

Function factorial($number) { if ($number < 2) { return 1; } else { return ($number * factorial($number-1)); } }

надеюсь, что это полезно для вас. :)

2015-09-15 07: 49: 11Z

Рекурсия, используемая для константы Капрекара

Function KaprekarsConstant($num, $count = 1) { $input = str_split($num); sort($input); $ascendingInput = implode($input); $descendingInput = implode(array_reverse($input)); $result = $ascendingInput > $descendingInput ? $ascendingInput - $descendingInput: $descendingInput - $ascendingInput; if ($result != 6174) { return KaprekarsConstant(sprintf("%04d", $result), $count + 1); } return $count;

Функция продолжает вызывать себя с результатом вычисления, пока не достигнет константы Капрекарса, при которой она будет возвращать количество раз, когда были выполнены вычисления.

/edit Для тех, кто не знает константу Капрекара, требуется ввод 4 цифр, по крайней мере, с двумя разными цифрами.

2018-03-02 07: 34: 31Z

Я тоже не нахожу примеры полезными. Вы не можете решить две проблемы одновременно, когда математика вовлечена, ваш ум переключается между двумя проблемами. Хватит говорить

Пример: р>

У меня есть функция, в которой я взрываю строки в массив на основе разделителя: .

Public function explodeString($string) { return explode(":", $string); }

У меня есть другая функция, где я беру строки в качестве входных данных

Public function doRec() { $strings = [ "no:go", "hello:world", "nested" => [ "iam:good", "bad:array", "bad:how", "bad:about", ] ]; $response = ; foreach ($strings as $string) { array_push($response,$this->explodeString($string)); } return $response; }

Проблема в том, что у моего ввода есть вложенный массив, и моя функция explodeString получает тип string . Я могу переписать некоторый код в функции explodeString , чтобы приспособиться к этому, но мне все еще нужна та же функция для выполнения той же операции с моей строкой. Вот где я могу вызвать метод recursively в. Итак, вот последняя функция explodeString с рекурсией.

Public function explodeString($string) { if (is_array($string)) { $combine = ; foreach ($string as $str) { array_push($combine, $this->explodeString($str)); } return $combine; } return explode(":", $string); }

» Рекурсия

Навигация по Самоучителю: 1.1 О PHP 1.2 История PHP 1.3 Почему именно PHP? 1.4 Как это все (PHP) работает? 1.5 От интерпретатора к компилятору 1.6 Возможности PHP 1.7 Что необходимо для работы? 1.8 Ответы на ваши вопросы 1.9 Заключение к главе 2.1 Установка и конфигурирование 2.2 Установка Apache 2.3 Установка PHP 2.4 Установка MySQL 2.5 Настройка Apache 2.6 Настройка PHP 2.7 Настройка MySQL 2.8 Тестирование программ Apache, PHP 2.9 Заключение к главе 2 3.1 Синтаксис языка PHP 3.2 Профессиональная вставка 3.3 РНР и HTML 3.4 Комментарии в языке (коде) PHP 3.5 Оформление PHP кода программы 3.6 Заключение к главе 3 4.1 Переменные. Что такое переменные? 4.2 Переменные. Типы данных в PHP 4.3 Integer. Тип данных. 4.4 Double. Тип данных. 4.5 Boolean. Тип данных. 4.6 Другие типы данных 4.7 Определение переменных в PHP 4.8 Изменение типа данных в PHP 4.9 Ссылки на переменные в PHP 4.10 Динамические переменные в PHP 4.11 Что такое Константы в PHP? 4.12 Определение констант в языке PHP 4.13 Предопределенные константы в языке PHP 4.14 Заключение к главе 4 5.1 Операторы в PHP 5.2 Оператор присваивания в PHP 5.3 Арифметические операторы в PHP 5.4 Операторы отношения в PHP 5.5 Логические операторы в PHP 5.6 Поразрядные операторы в PHP 5.7 Строковые операторы в PHP 5.8 Оператор подавления ошибок в PHP 5.9 Операторы увеличения и уменьшения в PHP 5.10 Сокращенная запись присвоения переменных в PHP 5.11 Приоритетность и ассоциативность в PHP 5.12 Заключение к главе 5 6.1 Управляющие операторы PHP 6.2 Условный оператор IF 6.3 Условный оператор Elseif 6.4 Условный оператор Switch 6.5 Операторы цикла For 6.6 Оператор цикла While 6.7 Оператор цикла Do...while 6.8 Безусловный оператор Break 6.9 Безусловный оператор Continue 6.10 Безусловный оператор Exit 6.11 Require 6.12 Include 6.13 Заключение к главе 6 7.1 Функции в PHP 7.2 Определение функций в PHP 7.3 Аргументы функций в PHP 7.4 Область видимости переменных 7.5 Время жизни переменных в PHP 7.6 Рекурсия в PHP 7.7 Динамический вызов функций в PHP 7.8 Заключение к главе 7 8.1 Массивы в PHP 8.2 Присвоение значений массивов PHP 8.3 Функция array () PHP 8.4 Вывод PHP массивов 8.5 Обход массивов PHP. Функция count(), Конструкции foreach() 8.6 Функция reset() 8.7 each() 8.8 list() 8.9 Сложение массивов 8.10 Сравнение массивов 8.11 Добавление элементов массива 8.12 Удаление элементов массива 8.13 Сортировка массивов 8.14 Многомерные массивы 8.15 Преобразование в массив 8.16 Заключение к главе 8 9.1 Строка 9.2 Обработка переменных внутри строк 9.3 Вывод строк 9.4 Форматированный вывод строк 9.5 Длина строки в PHP 9.6 Поиск подстроки в строке 9.7 Чистка строк 9.8 Заключение к главе 9 10.1 Работа с HTML-формами 10.2 Передача данных HTML-формы. Метод GET и POST 10.3 Получение данных в PHP 10.4 Суперглобальные массивы $_GЕТ и $_POST 10.5 Заключение к главе 10 11.1 Открытие файлов в PHP 11.2 Закрытие файлов в PHP 11.3 Чтение и запись файлов в PHP 11.4 Копирование, удаление и переименование файлов в PHP 11.5 Получение информации о файлах в PHP 11.6 Файловый указатель в PHP 11.7 Открытие и закрытие каталогов в PHP 11.8 Чтение каталогов в PHP 11.9 Создание и удаление каталогов в PHP 11.10 Заключение к главе 11 12.1 Работа с базами данных MySQL в PHP 12.2 Соединение PHP с сервером базы данных MySQL 12.3 Создание и удаление базы данных MySQL 12.4 Создание и удаление таблиц MySQL 12.5 Работа с данными MySQL 12.6 Заключение к главе 12 13.1 Работа с изображениями в PHP. Библиотека GD 13.2 Создание и вывод изображений в PHP 13.3 Модификация изображений в PHP 13.4 Работа с текстом в PHP 13.5 Заключение к главе 13 14.1 Работа с датой и временем в PHP 14.2 Символы форматирования даты и времени в PHP 14.3 Функция date() и getdate() в PHP 14.4 Преобразования к абсолютному времени в PHP 14.5 Заключение к главе 14 15.1 Работа с регулярными выражениями в PHP 15.2 Регулярные выражения POSIX в PHP 15.3 Метасимволы в PHP 15.4 Классы символов 15.5 Квантификаторы 15.6 Замена по шаблону 15.7 Примеры регулярных выражений 15.8 Заключение к главе 15 16.1 Работа с Cookies в PHP 16.2 Создание Cookies в PHP 16.3 Чтение из Cookies 16.4 Удаление Cookies 16.5 Заключение к главе 16

При объяснении решения задач математики очень часто применяют словосочетание «по индукции», которое многих ставит в тупик, так как это понятие является не самым простым. В программировании тоже имеется своеобразная индукция, называемая рекурсией .

Например, попробуем написать функцию с помощью обычного цикла for, возвращающую факториал числа. Из курса математики известно, что он вычисляется следующим образом: n! =1*2...*(n-1)*n. Причем 0!=1, а факториала отрицательных чисел не бывает (листинг 7.13).

Листинг 7.13. Функция нахождения факториала числа без рекурсии.

‹html›
‹head›
‹title›Функция нахождения факториала числа без рекурсии‹/title›
‹/head›
‹body›
‹?php
function factorial($num)
{
if ($num {
return 0;
}
if ($num == 0)
{
return 1;
}
for ($i = 1, $sum = 1; $i {
$sum = $sum * $i;
}
return $sum;
}

?›
‹/body›
‹/html›

Итак, задача решена, как говорится, «в лоб». В случае передачи отрицательных значений функция будет возвращать 0. Это реализуется с помощью первого оператора if. Далее если передано число 0, то возвращаем единицу. И наконец, в цикле for вычисляем факториал при любых других значениях.

При решении задач с помощью рекурсии требуются рассуждения иного рода. Например, факториал числа можно вычислить следующим образом:

n! = 1, если n=0
n! = n*(n-1)!, если n>0

Заметьте, что второе утверждение содержит в себе знак факториала. Именно в этом и состоит основной смысл рекурсии. При решении определенной задачи мы используем то, что нам нужно найти. В программировании функцию называют рекурсивной, если в ее описании присутствует обращение саму на себя.

Итак, вернемся к рассуждению о факториале. При решении задач с помощью рекурсии всегда надо иметь два типа утверждений: базисное и рекурсивное. В нашем случае базисным утверждением является n! = 1, если n = 0. Как вы, наверное, уже догадались, работая с рекурсивным утверждением, мы должны перейти к базисному и получить результат. Теперь попробуем реализовать все это на практике (листинг 7.14).

Листинг 7.14. Функция нахождения факториала числа с рекурсией

‹html›
‹head›
‹title›Функция нахождения факториала числа с рекурсией‹/title›
‹/head›
‹body›
‹?php
function factorial($num)
{
if ($num {
return 0;
}
if ($num == 0)
{
return 1;
}
return $num*factorial($num-1); // рекурсивный вывод
}
echo factorial(3); // выведет 6
?›
‹/body›
‹/html›

В этом случае первые два условия аналогичны примеру, разобранному выше. Но теперь вместо цикла fоr мы записываем рекурсивное выражение, в котором функция вызывает сама себя. В нашей программе это происходит до тех пор, пока в качестве входного параметра не будет число 0, при котором функция возвратит 1. Причем это значение возвратится не в основную программу, а в тело предыдущей функции. Эта функция, в свою очередь, возвратит свое значение в тело следующей функции и т. д., пока нужное значение не возвратится в основную программу.