0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p><strong>В этой статье разбираемся, какой бывает рекурсия, как с ее помощью можно решать задачи и что такое рекурсивные функции.</strong></p>
1
<p><strong>В этой статье разбираемся, какой бывает рекурсия, как с ее помощью можно решать задачи и что такое рекурсивные функции.</strong></p>
2
<h2>Содержание</h2>
2
<h2>Содержание</h2>
3
<ul><li><a>Рекурсия vs рекурсивный или итеративный процесс: в чем разница</a></li>
3
<ul><li><a>Рекурсия vs рекурсивный или итеративный процесс: в чем разница</a></li>
4
<li><a>Методы решения задач с помощью рекурсии</a></li>
4
<li><a>Методы решения задач с помощью рекурсии</a></li>
5
<li><a>В чем отличие рекурсивного процесса от итеративного</a></li>
5
<li><a>В чем отличие рекурсивного процесса от итеративного</a></li>
6
<li><a>Что такое рекурсивные функции и в чем особенность их применения</a></li>
6
<li><a>Что такое рекурсивные функции и в чем особенность их применения</a></li>
7
<li><a>Что такое хвостовая рекурсия</a></li>
7
<li><a>Что такое хвостовая рекурсия</a></li>
8
</ul><h2>Рекурсия vs рекурсивный или итеративный процесс: в чем разница</h2>
8
</ul><h2>Рекурсия vs рекурсивный или итеративный процесс: в чем разница</h2>
9
<p>Рекурсия - это функция, которая вызывает саму себя, но с другими значениями параметров.</p>
9
<p>Рекурсия - это функция, которая вызывает саму себя, но с другими значениями параметров.</p>
10
<p>На самом деле понятия рекурсии и процесса никак не связаны. Рекурсия - просто абстрактная концепция, которую можно наблюдать в природе, в математике и в других областях. Такая же абстрактная, как, например, музыкальная гармония.</p>
10
<p>На самом деле понятия рекурсии и процесса никак не связаны. Рекурсия - просто абстрактная концепция, которую можно наблюдать в природе, в математике и в других областях. Такая же абстрактная, как, например, музыкальная гармония.</p>
11
<p>Теперь давайте поговорим о компьютерах. Для выполнения задач им нужны инструкции. Когда компьютер выполняет набор инструкций - это процесс. Ваш работающий сейчас браузер - тоже процесс. Простой цикл, выводящий на экран десять раз число "42" - также процесс.</p>
11
<p>Теперь давайте поговорим о компьютерах. Для выполнения задач им нужны инструкции. Когда компьютер выполняет набор инструкций - это процесс. Ваш работающий сейчас браузер - тоже процесс. Простой цикл, выводящий на экран десять раз число "42" - также процесс.</p>
12
<p>Некоторые задачи можно решать рекурсивно, то есть использовать концепцию, когда что-то является частью самого себя, в инструкциях. В частности, функция может быть частью самой себя, то есть вызывать саму себя.</p>
12
<p>Некоторые задачи можно решать рекурсивно, то есть использовать концепцию, когда что-то является частью самого себя, в инструкциях. В частности, функция может быть частью самой себя, то есть вызывать саму себя.</p>
13
<blockquote><h3>Читайте также:</h3>
13
<blockquote><h3>Читайте также:</h3>
14
<p>Что такое<a>callback-функция</a>в JavaScript?</p>
14
<p>Что такое<a>callback-функция</a>в JavaScript?</p>
15
</blockquote><h2>Методы решения задач с помощью рекурсии</h2>
15
</blockquote><h2>Методы решения задач с помощью рекурсии</h2>
16
<p>Есть два метода решения задач с использованием рекурсии: рекурсивный процесс и итеративный процесс. Рекурсия в них не отличается: в каждом из подходов функция вызывает саму себя, рекурсивно. Отличаются способы использования идеи рекурсии.</p>
16
<p>Есть два метода решения задач с использованием рекурсии: рекурсивный процесс и итеративный процесс. Рекурсия в них не отличается: в каждом из подходов функция вызывает саму себя, рекурсивно. Отличаются способы использования идеи рекурсии.</p>
17
<p>Давайте продолжим аналогию с музыкальной гармонией и подумаем про фортепиано. При написании музыки используем эту концепцию - "гармонию звуков". Можно придумать разные способы: рассчитывать частоты звуков - ноты - математическими формулами или рассчитывать правильные расстояния между клавишами.</p>
17
<p>Давайте продолжим аналогию с музыкальной гармонией и подумаем про фортепиано. При написании музыки используем эту концепцию - "гармонию звуков". Можно придумать разные способы: рассчитывать частоты звуков - ноты - математическими формулами или рассчитывать правильные расстояния между клавишами.</p>
18
<p>В детстве я научился находить правильные расстояния между клавишами на фортепиано, и получал гармоничные комбинации звуков, но понятия не имел, что это за ноты. А профессиональный музыкант знает теорию и подбирает гармонию другими методами. В любом случае, гармония есть гармония, эта концепция не меняется, меняются лишь способы ее использования.</p>
18
<p>В детстве я научился находить правильные расстояния между клавишами на фортепиано, и получал гармоничные комбинации звуков, но понятия не имел, что это за ноты. А профессиональный музыкант знает теорию и подбирает гармонию другими методами. В любом случае, гармония есть гармония, эта концепция не меняется, меняются лишь способы ее использования.</p>
19
<h2>В чем отличие рекурсивного процесса от итеративного</h2>
19
<h2>В чем отличие рекурсивного процесса от итеративного</h2>
20
<p>Рекурсивный процесс на каждом шаге рекурсии говорит "я это запомню и потом посчитаю". "Потом" наступает в самом конце.</p>
20
<p>Рекурсивный процесс на каждом шаге рекурсии говорит "я это запомню и потом посчитаю". "Потом" наступает в самом конце.</p>
21
<ul><li>Если рекурсивный процесс считает факториал 6, то ему нужно запомнить 5 чисел, чтобы посчитать их в самом конце, когда уже никуда не деться и рекурсивно двигаться вниз больше нельзя</li>
21
<ul><li>Если рекурсивный процесс считает факториал 6, то ему нужно запомнить 5 чисел, чтобы посчитать их в самом конце, когда уже никуда не деться и рекурсивно двигаться вниз больше нельзя</li>
22
<li>Когда мы находимся в очередном вызове функции, то где-то снаружи этого вызова в памяти хранятся эти запомненные числа</li>
22
<li>Когда мы находимся в очередном вызове функции, то где-то снаружи этого вызова в памяти хранятся эти запомненные числа</li>
23
</ul><p>На этой картинке видно, как растет использование памяти: процессу нужно запоминать все больше и больше чисел</p>
23
</ul><p>На этой картинке видно, как растет использование памяти: процессу нужно запоминать все больше и больше чисел</p>
24
<p>Рекурсивный процесс - это процесс с отложенным вычислением.</p>
24
<p>Рекурсивный процесс - это процесс с отложенным вычислением.</p>
25
<p>Итеративный процесс постоянно говорит "<em>я сейчас посчитаю все что можно и продолжу</em>" на каждом шаге рекурсии. Ему не нужно ничего запоминать вне вызова, он всегда все считает в первый возможный момент. Каждый шаг рекурсии может существовать в изоляции от прошлых, потому что вся информация передается последовательно.</p>
25
<p>Итеративный процесс постоянно говорит "<em>я сейчас посчитаю все что можно и продолжу</em>" на каждом шаге рекурсии. Ему не нужно ничего запоминать вне вызова, он всегда все считает в первый возможный момент. Каждый шаг рекурсии может существовать в изоляции от прошлых, потому что вся информация передается последовательно.</p>
26
<ul><li>Когда итеративный процесс считает факториал 6, то ему не нужно запоминать числа. Нужно лишь считать и передавать результат дальше, в новый вызов</li>
26
<ul><li>Когда итеративный процесс считает факториал 6, то ему не нужно запоминать числа. Нужно лишь считать и передавать результат дальше, в новый вызов</li>
27
<li>Когда мы находимся в очередном вызове функции, снаружи этого вызова в памяти ничего не нужно запоминать</li>
27
<li>Когда мы находимся в очередном вызове функции, снаружи этого вызова в памяти ничего не нужно запоминать</li>
28
</ul><p>А на этой картинке видно, что использование памяти не растет.</p>
28
</ul><p>А на этой картинке видно, что использование памяти не растет.</p>
29
<p>Подытожим в шуточной форме. Рекурсивный процесс - это чувак, который все дела откладывает на вечер пятницы. В течение недели у него мало работы, а в пятницу завал. Но ему так нравится.</p>
29
<p>Подытожим в шуточной форме. Рекурсивный процесс - это чувак, который все дела откладывает на вечер пятницы. В течение недели у него мало работы, а в пятницу завал. Но ему так нравится.</p>
30
<p>Итеративный процесс - это чувак, который все делает при первой возможности. У него работа равномерно распределена по неделе, а пятница - просто обычный день, но последний.</p>
30
<p>Итеративный процесс - это чувак, который все делает при первой возможности. У него работа равномерно распределена по неделе, а пятница - просто обычный день, но последний.</p>
31
<h2>Что такое рекурсивные функции и в чем особенность их применения</h2>
31
<h2>Что такое рекурсивные функции и в чем особенность их применения</h2>
32
<p>Рекурсивные функции - это те функции, которые используют итеративный процесс. Для каждого рекурсивного вызова в стек вызовов записывается вся информация, связанная с этим вызовом, вроде параметров функции и ее локальных переменных, адреса возврата в точку вызова.</p>
32
<p>Рекурсивные функции - это те функции, которые используют итеративный процесс. Для каждого рекурсивного вызова в стек вызовов записывается вся информация, связанная с этим вызовом, вроде параметров функции и ее локальных переменных, адреса возврата в точку вызова.</p>
33
<p>Для рекурсивной функции выделяется дополнительная область памяти - лексический контекст функции, область видимости -, которая обслуживает рекурсивный вызов. Так как это стек вызовов, то контексты предыдущих рекурсивных вызовов также продолжают занимать память.</p>
33
<p>Для рекурсивной функции выделяется дополнительная область памяти - лексический контекст функции, область видимости -, которая обслуживает рекурсивный вызов. Так как это стек вызовов, то контексты предыдущих рекурсивных вызовов также продолжают занимать память.</p>
34
<p>Достижение большой глубины рекурсии, или же, недостижение терминального условия выхода из рекурсии, приводит к переполнению стека, так как он ограничен в размерах, и аварийному завершению всей программы.</p>
34
<p>Достижение большой глубины рекурсии, или же, недостижение терминального условия выхода из рекурсии, приводит к переполнению стека, так как он ограничен в размерах, и аварийному завершению всей программы.</p>
35
<blockquote><h3>Читайте также:</h3>
35
<blockquote><h3>Читайте также:</h3>
36
<p>Как<a>проверить качество кода</a>: функциональное и нефункциональное тестирование</p>
36
<p>Как<a>проверить качество кода</a>: функциональное и нефункциональное тестирование</p>
37
</blockquote><p>В контексте каждого рекурсивного вызова такой функции хранится вся необходимая информация для его успешного выполнения. Он самодостаточен и никак не зависит от предыдущих контекстов. Помните, что этот чувак ничего не откладывает на потом, на вечер пятницы?</p>
37
</blockquote><p>В контексте каждого рекурсивного вызова такой функции хранится вся необходимая информация для его успешного выполнения. Он самодостаточен и никак не зависит от предыдущих контекстов. Помните, что этот чувак ничего не откладывает на потом, на вечер пятницы?</p>
38
<p>В наших практиках на Хекслете мы реализовывали такое поведение благодаря использованию аккумулятора acc, который передается в качестве аргумента из одного вызова в другой и накапливает в себе результат вычисления необходимого значения.</p>
38
<p>В наших практиках на Хекслете мы реализовывали такое поведение благодаря использованию аккумулятора acc, который передается в качестве аргумента из одного вызова в другой и накапливает в себе результат вычисления необходимого значения.</p>
39
<p>Получается, что, грубо говоря, на каком бы по уровню вложенности рекурсивном вызове мы не находились, все предыдущие уже не имеют значения и являются "бесполезной обузой", нагружающей память. Это распространяется в том числе и на самый последний рекурсивный вызов, где срабатывает терминальное условие. Он готов вернуть готовое вычисленное значение из функции сразу, ему не нужны для этого предыдущие контексты в стеке.</p>
39
<p>Получается, что, грубо говоря, на каком бы по уровню вложенности рекурсивном вызове мы не находились, все предыдущие уже не имеют значения и являются "бесполезной обузой", нагружающей память. Это распространяется в том числе и на самый последний рекурсивный вызов, где срабатывает терминальное условие. Он готов вернуть готовое вычисленное значение из функции сразу, ему не нужны для этого предыдущие контексты в стеке.</p>
40
<h2>Что такое хвостовая рекурсия</h2>
40
<h2>Что такое хвостовая рекурсия</h2>
41
<p>Как использовать преимущества итеративного процесса и одновременно избавиться от недостатка рекурсивных функций, то есть от неумолимого роста использования памяти? Можно избавить процесс от заполнения стека "ненужными" контекстами предыдущих вызовов и обеспечить прямой возврат из функции при достижении терминального условия.</p>
41
<p>Как использовать преимущества итеративного процесса и одновременно избавиться от недостатка рекурсивных функций, то есть от неумолимого роста использования памяти? Можно избавить процесс от заполнения стека "ненужными" контекстами предыдущих вызовов и обеспечить прямой возврат из функции при достижении терминального условия.</p>
42
<p>Для этого служит так называемая оптимизация хвостовой рекурсии (Tail call optimization). Итеративный процесс, который мы рассмотрели, как раз можно отнести к хвостовой рекурсии. Благодаря оптимизации состояния стека, она придает итеративному процессу вид "плоской" итерации. Так исключается его переполнение из-за большой глубины рекурсии.</p>
42
<p>Для этого служит так называемая оптимизация хвостовой рекурсии (Tail call optimization). Итеративный процесс, который мы рассмотрели, как раз можно отнести к хвостовой рекурсии. Благодаря оптимизации состояния стека, она придает итеративному процессу вид "плоской" итерации. Так исключается его переполнение из-за большой глубины рекурсии.</p>
43
<p>Хвостовая рекурсия и ее оптимизация широко используется при написании программ на функциональных языках программирования.</p>
43
<p>Хвостовая рекурсия и ее оптимизация широко используется при написании программ на функциональных языках программирования.</p>