Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Prolog.doc
Скачиваний:
31
Добавлен:
12.03.2015
Размер:
929.28 Кб
Скачать

4.3. Рекурсия и эффективность

Определение рекурсии можно непосредственно выразить утверж­дениями Пролога.

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

Пример 4.3.1

Рассмотрим методы вычисления Х^n с помощью одного только умножения. Здесь n - натуральное число (натуральным числом явля­ется положительное целое число или нуль).

Очевидный способ - умножить Х на себя n раз. Получим следую­щие утверждения:

степень(Х,О,1). /* Х^О равно 1

степень(Х,N,R) :-

М is N - 1,

степень(Х,М,0),

R is Q*X.

Тогда ответом на запрос

?- степень(5,8,S).

будет:

S = 390625

Этот результат получен с помощью 8 умножений (рис.4.3.1).

Но можно также воспользоваться свойствами:

Х^n = Z * Z, где Z = X^(n div 2), если n - четное, и

Х^n = Х^(n - 1) * X, если n - нечетное,

и получить следующие утверждения:

степень_быстро(Х,0,1).

степень_быстро(X,N,R) :-

0 is N mod 2,

М is N div 2,

степень_быстро(Х,М,Q),

R is Q*Q.

степень_быстро(X,N,R) :-

М is N - 1,

степень_быстро(Х,М,Q),

R is Q * X.

Во втором случае понадобится только 4 умножения (рис.4.3.2) при обработке запроса

?- степень_быстро(5,8,S).

и будет получен ответ

S = 390625

Заметим, что в третьем утверждении степень_быстро нам не нужно было проверять, является ли N нечетным. Мы предполагаем, что второе утверждение не сопоставляется с целью в том случае, ес­ли N mod 2 не равно 0, т.е. N не является четным. Следовательно, третье утверждение выбирается только тогда, когда N является не­четным (за исключением вопросов об альтернативных вариантах).

Рис.4.3.1. Трассировка запроса ?-степень(5,8,S)

Рис.4.3.2. Трассировка запроса степень_быстро(5,8,S)

Преимущество, которое имеет утверждение степень_быстропе­ред утверждениемстепень, увеличивается с ростомN. Так, согласо­вание утверждениястепень(2,1024,Х)требует 1024 умножений, в то время как согласование утверждениястепень_быстро(2,1024,Х)тре­бует всего 11 умножений. Необходимость дополнительной проверки четностиNи деленияNпополам приводит к тому, что практически только при большихNпроцедурастепень_быстропредпочтитель­нее, чем процедурастепень.

Пример 4.3.2

Ряд Фибоначчи

0,1,1,2,3,5,8,13,21,34,55,89,144,...

определяется условиями:

f0 = 0

f1 = 1

fn = f(n-l) + f(n-2)

Мы можем непосредственно использовать определение ряда:

фиб(0,0).

фиб(1,1).

фиб(N,X) :-

N1 is N - 1,

N2 is N - 2,

фиб(N1,Х1),

фиб(N2,Х2),

X is Xl + X2.

Для того чтобы согласовать фиб(N,X), потребуется 2*Y-1 рекур­сивных обращений. Здесь N больше нуля, a Y является (N+1)-m чис­лом Фибоначчи.

Так, например, для согласования запроса

?- фиб(10,Х).

при

Х=55

потребуется 177 (89*2-1) обращений.

Однако можно переформулировать задачу следующим образом: найти N-e и (N+1)-e числа Фибоначчи. Тогда мы получим:

/* Нулевое число Фибоначчи равно 0, а

/* предшествующее число не определено

фиб(0,_,0).

/* Первое число Фибоначчи равно 1, а

/* предшествующее равно 0

фиб(1,0,1).

/* N-e число Фибоначчи образуется при

/* сложении двух предшествующих чисел

/* Фибоначчи

фиб(N,F1,F2) :-

M is N- 1,

фиб(М,F0,F1),

F2 is F0 + Fl.

Чтобы найти 10-е число Фибоначчи, сделаем запрос:

?-фиб(10,F1,F2).

получим

F1 = 34

F2 = 55

другие решения (да/нет)? нет

Рис.4.3.3. Сравнение процедур фиб/2 и фиб/3

Для ответа на запрос было произведено 10 обращений. В общем для нахождения N-ro числа Фибоначчи (для N > 0) требуется N обра­щений. На рис.4.3.3 показано, как с ростом N увеличивается преиму­щество второго варианта процедуры (фиб/3) перед первым (фиб/2).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]