Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / ЛЕКЦИИ / POSIBNIK / ПРОГР НА ПРОЛОГЕ.doc
Скачиваний:
42
Добавлен:
23.03.2015
Размер:
669.7 Кб
Скачать

5.10. Метод організації висхідних рекурсивних обчислень (вро)

За допомогою даного методу можна будувати рекурсивну структуру, починаючи з константного терма, маркіруючего її кінець.

Метод застосовується в таких випадках:

1. Коли для об'єктів структури запропонований особливий порядок, що не може бути забезпечений прогресуючою підстановкою;

2. Коли в рекурсивних станах обчислення залежать від наявного доступу до побудованої на даний момент структури.

Містить такі кроки:

1. Константний терм постає аргументом у викликах процедури;

2. Аргумент кожного рекурсивного виклику – нова структура, одним із компонентів якої служить попередньо побудована структура;

3. Змінна, призначена для розташування в ній кінцевого результату, передається “внутрішнім чином” і до неї не застосовується ніяких підстановок, поки не буде досягнутий базовий стан;

4. У базовому стані зазначена змінна узгоджується з аргументом, що позначає побудовану структуру.

Цей метод протилежний методу спадної рекурсії з прогресуючою підстановкою. Розглянемо цей метод на прикладі розв’язання такої задачі.

Задача. Скласти процедуру, що виконує реверсування списку:

реверс(вихідний_список, реверсований_список)

Будемо будувати результуючий список з кінця. Для цього перекладемо роботу на допоміжну процедуру “прихований_реверс”, додавши до неї ще один параметр – список, побудований до даного моменту. У початковий момент цей допоміжний список буде порожній. Тому можна написати

реверс(L1, L2):-

прихований_реверс(L1, [ ], L2).

Процедуру “прихований_реверс” будемо розробяти методом аналізу станів.

Етапи:

1. Вигляділення двох станів:

а) L1 – порожній;

б) L1 – непорожній.

2. Розпізнання станів за допомогою аргументів, що мають такий вигляд:

а) [ ];

б) [H|T].

3. Реалізація поводження процедури в цих станах у такий спосіб:

а) фактом

прихований_реверс([ ], L, L).

% Якщо перший список порожній, то результатом буде другий

% список

б) правилом

прихований_реверс([H|T], L1, L2):-

прихований_реверс(T, [H|L1], L2).

% Якщо перший список не порожній, то розв’язок нашої

% задачі буде отримано реверсуванням хвоста (список T), коли

% голова вихідного списку ( елемент H) буде додана до

% попередньо реверсованої до цього моменту частини вхідного

% списку (за допомогою рекурсивного виклику)

4. Упорядкування тверджень у процедурі – довільне.

5. Доведення взаємовиключності тверджень: вид першого аргументу в першому і другому твердженні виключають один одного.

У результаті одержимо розв’язок

реверс(L1, L2):-

прихований_реверс(L1, [ ], L2).

прихований_реверс([ ], L, L).

прихований_реверс([H | T], L1, L2).

прихований_реверс(T, [H | L1], L2).

Проілюструємо поводження цієї процедури на прикладі реверсування списку [3, 4, 5, 6] (рис. 19).

Ціль: реверс([3, 4, 5, 6], R).

Вхідний список [3, 4, 5, 6]

(перший аргумент)

Допоміжний список: [ ] Вхід Результуючий список [6, 5, 4, 3]

(другий аргумент)

3

[3] Вихід

4 (Третій аргумент

[4, 3] у базовому

5 стані )

[5, 4, 3]

6

[6, 5, 4, 3] [ ]

Рис. 19. Реверсування списку

Застосуємо цей метод для більш ефективного розв’язку задачі побудови списку чисел Фібоначчі. Раніше ми цю задачу розв’язували спадним методом і відзначали неефективність такого розв’язання.

DOMAINS

список = integer *

PREDICATES

числа_фіб(integer, список)

скр_числа_фіб(integer, integer, список, список)

CLAUSES

числа_фіб(N, L):-

скр_числа_фіб(N, 1, [0, 1], L).

скр_числа_фіб(N, N, L, L).

скр_числа_фіб(N, N1, [Останнє, Передостаннє | T], L2):-

Чергове_число = Останнє + Передостаннє,

N2=N1+1,

скр_числа_фиб(N, N2, [Чергове_число, Останнє, Передостаннє | T], L2).