Когда рекурсию использовать не нужно
Рекурсивные алгоритмы особенно подходят для задач, где обрабатываемые данные определяются в терминах рекурсии. Однако это не означает, что такое рекурсивное определение данных гарантирует бесспорность употребления для решения задачи рекурсивного алгоритма. Фактически объяснение концепций рекурсивных алгоритмов на неподходящих для этого примерах и вызвало широко распространенное предубеждение против использования рекурсий в программировании; их даже сделали синонимом неэффективности.
Программы, в которых следует избегать алгоритмической рекурсии, можно охарактеризовать некоторой схемой, отражающей их строение (специфично, что тут есть единственное обращение к Р в конце или начале всей конструкции):
P IF В THEN S; P END, (3.6)
P S; IF В THEN P END. (3.7)
Такие схемы естественны в ситуациях, где вычисляемые значения определяются с помощью простых рекуррентных отношений. Возьмем хорошо известный пример вычисления факториала
i=0,1,2,3,4,5,...,
fi=1, 1, 2, 6, 24, 120,....
Первое из чисел определяется явно – f0 = 1, а последующие определяются рекурсивным образом с помощью предшествующего числа:
Такое рекуррентное отношение предполагает рекурсивный алгоритм вычисления n-го факториального числа. Если мы введем две переменные i и f, обозначающие на i-м уровне рекурсии, то обнаружим, что для перехода к следующему числу последовательности нужно проделать такие вычисления:
i++; f*=i;
откуда получаем простую рекурсивную программу:
Однако более часто употребляется и полностью эквивалентна ей запись, где вместо Р приведена так называемая процедура-функция, т. е. процедура, с которой связывается значение–результат и которую поэтому можно применять прямо как составляющую выражения. В этом случае переменная F становится излишней, а роль i явно выполняет параметр процедуры:
PROCEDURE F (I: INTEGER): INTEGER; BEGIN
IF I > 0 THEN RETURN I*F(I-1) ELSE RETURN 1 END END F;
Теперь уже ясно, что в нашем примере рекурсия крайне просто заменяется итерацией. Это проделано в такой программе:
I := 0; F : = 1;
WHILE I < n DO I := 1+1; F := I*F END;
Конечно, существуют и более сложные схемы рекурсий, которые можно и необходимо переводить в итеративную форму. Возьмем в качестве примера вычисление чисел Фибоначчи, определяемых рекурсивным соотношением
fibn+1 =fibn + fibn–i для n > 0 (3.16)
и fib1 =1; fib0 =0.
Прямое, "наивное", переписывание приводит к рекурсивной программе:
PROCEDURE Fib(i: INTEGER): INTEGER;
BEGIN
IF n = 0 THEN RETURN 0
ELSIF n = 1 THEN RETURN 1 (3.17)
ELSE RETURN Fib(n-1)+Fib{n-2)
END
END Fib;
Вычисление fib путем обращения к Fib(n) приводит к рекурсивным активациям этой процедуры-функции. Как часто это происходит? Каждое обращение с п > 1 приводит еще к двум обращениям, т. е. общее число вызовов растет экспоненциально (рис. 3.2).

Ясно, что такая программа практического интереса не представляет.
Однако, к счастью, числа Фибоначчи можно вычислять и по итеративной схеме, где с помощью вспомогательных переменных х = fibi и у = fibi-i удается избежать повторных вычислений одной и той же величины:
i = 1; х = 1; у = 0;
WHILE i < n DO z = х; х+ = y, у := z; i++ END;
И
