
3. Рекурсия
В C# метод может вызывать сам себя. Этот процесс называется рекурсией, а метод, который сам себя вызывает, называется рекурсивным. Ключевым компонентом рекурсивного метода является оператор для вызова этого же метода.
Классическим примером рекурсии является вычисление факториала числа. Факториалом числа N называется произведение всех целых чисел от 1 до N (скажем, факториал числа 3 равен произведению 1x2x3 = 6). В следующей программе представлен рекурсивный метод, предназначенный для вычисления факториала числа. Для сравнения ранее рассмотрен равнозначный метод, выполняющий те же функции без использования рекурсии.
Алгоритм работы обычного метода прост – в нем использует цикл, где последовательно умножаются все целые числа от 1 до числа, факториал, которого нужно вычислить.
Работа рекурсивного метода FtR немного сложнее. Если вызвать метод FtR с аргументом 1, то метод возвращает единицу. Это значение так же будет использоваться при возврате управления предыдущему методу в выражении FtR(n-1)*n. При выполнении этого выражения метод FtR вызывается с n-1. Этот процесс повторяется до тех пор, пока значение переменной n не будет равно 1. Так, при вычислении факториала числа 2 первый вызов метода FtR с аргументом 2 приведет ко второму вызову этого же метода, но уже с аргументом 1. При получении этого аргумента метод возвратит число 1, которое затем будет умножено на 2. То есть ответ — значение 2. Можно поместить оператор MessageBox.Show() в метод FtR, который будет выводить на экрана аргумент каждого вызова и промежуточные результаты.
Когда метод вызывает сам себя, в стек помещаются новые локальные переменные и параметры, а код метода выполняется с этими новыми переменными с самого начала. Рекурсивные вызовы не создают новую копию метода, новыми являются только аргументы. После возвращения рекурсивным методом значения старые локальные переменные и параметры удаляются из стека, а управление программой передается оператору, следующему затем, из которого был вызван метод.
Рекурсивные версии многих программ могут выполняться медленнее своих итеративных (использующих обычные методы и циклы) аналогов, так как при дополнительных вызовах метода появляются непроизводительные издержки. В результате слишком большого количества рекурсивных вызовов создастся много новых локальных переменных и параметров, а это может перегрузить стек, что приведет к возникновению исключительной ситуации. Обычно это происходит, если в программе неправильно определено условие: метод вместо вызова самого себя должен вернуть значение.
Основное преимущество рекурсии заключается в том, что некоторые алгоритмы рекурсивно могут быть реализованы проще и эффективнее, чем их итеративный вариант. Рекурсивные решения требуются и при решении некоторых задач, связанных с разработкой искусственного интеллекта.
Как правило, для возврата из метода значения без выполнения рекурсивного вызова используется условный оператор, такой как if. Учтите, что при неправильном определении условного выражения после вызова метод будет бесконечно вызывать сам себя. У начинающих программистов такая ошибка при использовании рекурсии встречается достаточно часто. Рекомендуется для контроля над выполнением программы использовать операторы отладки.