Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии Программирования. 5 лекция

.pdf
Скачиваний:
12
Добавлен:
27.05.2015
Размер:
925.27 Кб
Скачать

2) Неправильное использование типов

Следующая версия функции является более сложным примером.

В ней условие остановки рекурсии прекращает выполнение только нескольких путей рекурсии, и возникают те же проблемы, что и при выполнении функции BadFactorial, если входные значения отрицательные (или не целые float n вместо int n ).

double BadFib(int n)

{if (n = = 0) return 1; else

return (BadFib(n - 1) + BadFib (n - 2));

}

3) И последняя проблема, связанная с бесконечной рекурсией, заключается в том, что «бесконечная» на

самом деле означает «до тех пор, пока не будет

исчерпано стековое пространство».

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

Следующая функция, которая вычисляет сумму

N + (N -1) + + 2 +1,

приводит к исчерпанию стекового пространства при больших значениях N.

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

double BigAdd (int N) {if( N <= 1) return 1;

else

return N + BigAdd (N - 1);

}

 

4) Потери памяти

При каждом вызове функции, система выделяет память для локальных переменных нового вызова.

Во время сложной последовательности рекурсивных

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

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

Следовательно, не следует использовать большое

количество ненужных переменных.

Следующая версия функции BigAdd еще быстрее

приводит к переполнению стека, чем предыдущая.

double BigAdd (int N)

{int i1, i2, i3; double result; if( N <= 1)

result = 1;

else

result= N + BigAdd (N - 1); return result;

}

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

Function Factorial(ByVal N As

Function BigAdd(ByVal N As

Integer) As Double

Double) As Double

Dim value As Double

Dim value As Double

value = 1#

value = 1#

' Это будет значением функции.

' Это будет значением функции.

Do While N > 1 value = value * N

N = N - 1

' Подготовить аргументы для "рекурсии".

Loop

Factorial = value End Function

Do While N > 1 value = value + N

N = N - 1

' подготовить параметры для "рекурсии".

Loop

BigAdd = value End Function

Замечание

Для алгоритмов вычисления факториала и наибольшего общего

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

Для функции BigAdd, тем не менее, разница огромна. Рекурсивная версия приводит к переполнению стека даже для довольно небольших входных значений. Поскольку нерекурсивная версия не использует стек, она может вычислять результат для значений N вплоть до 10154. После этого

наступит переполнение для данных типа double. Конечно,

выполнение 10154 шагов алгоритма займет очень много времени, поэтому возможно вы не станете проверять этот факт сами. Заметим также, что значение этой функции совпадает со значением более просто вычисляемой функции N * N(N + 1) / 2.

ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ