Студопедия — Рекурсия
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Рекурсия






Поиск с возвратом

Одной из важнейших особенностей языка Prolog является возможность поиска всех решений. Поиск всех решений достигается использованием механизма поиска с возвратом.

Можно сформулировать четыре основных правила поиска с возвратом:

- Правило 1: подцели должны быть согласованы по порядку, слева направо;

- Правило 2: предложения проверяются в том порядке, в котором они появляются в тексте программы;

- Правило 3: когда подцель сопоставляется с заголовком правила, тело этого правила должно быть доказано (тело правила состоит, в свою очередь, из новых подцелей, которые должны быть доказаны);

- Правило 4: целевое утверждение считается согласованным, когда соответствующие факты найдены для каждой листьевой вершины дерева целей.

 

Пример:

DOMAINS

name, thing=symbol

 

PREDICATES

hobby (name, thing)

reads (name)

is_inquisitive (name)

 

CLAUSES

hobby (“Ян”, “теннис”).

hobby (“Лена”, “лыжи”).

hobby (X, “книги”):- reads (X), is_inquisitive (X).

hobby (“Лена”, “книги”).

reads (“Ян”).

is_inquisitive (“Ян”).

 

Goal: hobby (Y, “теннис”), hobby (Y, “книги”).

Y=“Ян”

 

Для управления поиском решений существует два стандартных предиката:

- предикат fail, использующийся для поддержания поиска с возвратом;

- предикат! (отсечение), использующийся для предотвращения поиска с возвратом.

 

Предикат fail всегда дает неудачу в доказательстве и, таким образом, поддерживает поиск с возвратом.

Пример.

DOMAINS

name=symbol

 

PREDICATES

father (name, name)

everybody

 

CLAUSES

father (“Павел”, “Петр”).

father (“Петр”, “Михаил”).

father (“Петр”, “Иван”).

everybody:- father (X, Y), write (X, “это отец ”, Y, “а”), nl, fail.

 

GOAL

everybody.

Результатом работы будет вывод следующих сообщений, и работа программы завершится с неуспехом:

Павел это отец Петра

Петр это отец Михаила

Петр это отец Ивана

Предикат! (отсечение) убирает все точки возврата, то есть через отсечение нельзя совершить поиск с возвратом.

Пример.

r(1):-!, a, b, c.

r(2):-!, d.

r(3):-!, e.

r(_):- write (“Это предложение-ловушка”).

 

Практическое задание №2. Рекурсия в Prolog

(выбор варианта по последней цифре номера зачетной книжки)

 

Вариант 0

Подсчитать, сколько раз встречается некоторая буква в строке. Строка и буква должны вводиться с клавиатуры. Для разделения строки на символы использовать стандартный предикат frontchar (String, Char, StringRest), позволяющий разделять строку String на первый символ Char и остаток строки StringRest.

Вариант 1

Вычислить значение n-го члена ряда Фибоначчи: f(0)=0, f(1)=1,
f(n)=f(n-1)+f(n-2).

Вариант 2

Вычислить произведение двух целых положительных чисел (используя суммирование).

Вариант 3

Подсчитать, сколько раз встречается некоторое слово в строке. Строка и слово должны вводиться с клавиатуры. Для разделения строки на слова использовать стандартный предикат fronttoken (String, Lexeme, StringRest), позволяющий разделить строку String на первое слово Lexeme и остаток строки StringRest.

Вариант 4

Поменять порядок следования букв в слове на противоположный. Для разделения строки на символы использовать стандартный предикат frontchar (String, Char, StringRest), позволяющий разделять строку String на первый символ Char и остаток строки StringRest.

Вариант 5

Вычислить сумму ряда целых нечетных чисел от 1 до n.

Вариант 6

Поменять порядок следования слов в предложении на противоположный. Для разделения строки на слова использовать стандартный предикат fronttoken (String, Lexeme, StringRest), позволяющий разделить строку String на первое слово Lexeme и остаток строки StringRest..

Вариант 7

Вычислить сумму ряда целых четных чисел от 2 до n.

Вариант 8

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

Вариант 9

Организовать ввод букв и их соединение в строку до тех пор, не будет введен символ #. Для присоединения символа к строке использовать стандартный предикат frontchar (String, Char, StringRest), позволяющий присоединять символ Char к строке StringRest и получать строку String.

Методические указания:

Рекурсия

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

Например, задача нахождения значения факториала n! сводится к нахождению значения факториала (n-1)! и умножения найденного значения на n.

PREDICATES

factorial (integer, real)

CLAUSES

factorial (0, 1):-!. %факториал 0! равен 1 (граничное условие,
%останавливающее рекурсию)

factorial (N, FactN):- M=N-1, factorial (M, FactM), FactN= FactM*N.

%факториал n! равен (n-1)!*n (рекурсивное условие)

Goal: factorial (3, FactN)

FactN=6

 

Для наглядного представления нахождения решения удобно использовать дерево целей:

 

У рекурсии есть большой недостаток, она требует памяти. Избежать этого недостатка позволяет хвостовая рекурсия.

Рекурсия является хвостовой, если выполняются следующие условия:

- рекурсивный вызов является самой последней подцелью выражения;

- ранее в предложении не было возвратных точек.

 

Пример хвостовой рекурсии:

PREDICATES

count (real)

CLAUSES

count (N):- write (N), nl, NewN=N+1, count (NewN).

GOAL

count (1).

 

Примеры нехвостовой рекурсии:

PREDICATES

badcount1 (real)

badcount2 (real)

badcount3 (real)

CLAUSES

% рекурсивный вызов ‑ не последняя подцель в предложении

badcount1 (N):- write (N), NewN=N+1, count (NewN), nl.

% перед рекурсивным вызовом в предложении есть точка возврата

badcount2 (N):- N>=0, write (N), nl, NewN=N-1, badcount2 (NewN).

badcount2 (N):- write (“N – отрицательное число”).

% перед рекурсивным вызовом в предложении есть точка возврата

badcount3 (N):- write (N), nl, NewN=N+1, check(NewN), badcount3 (NewN).

check (M):- M>=0.

check (M):- M<0.

 

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

 

badcount2 (N):- N>=0,!, write (N), nl, NewN=N-1, badcount2 (NewN).

badcount2 (N):- write (“N – отрицательное число”).

badcount3 (N):- write (N), nl, NewN=N+1, check(NewN),!, badcount3 (NewN).

check (M):- M>=0.

check (M):- M<0.

 

Практическое задание №3.

Знакомство с основами функционального программирования в Lisp

(выбор варианта по последней цифре номера зачетной книжки)

 

Вариант 0

Определить рекурсивную функцию, возвращающую значение n-го члена ряда Фибоначчи: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2).

Вариант 1

Определить рекурсивную функцию для удаления последнего элемента списка.

Вариант 2

Определить рекурсивную функцию, возвращающую произведение двух целых положительных чисел (использовать суммирование).

Вариант 3

Определить рекурсивную функцию, возвращающую последний элемент списка.

Вариант 4

Определить рекурсивную функцию, возвращающую значение суммы ряда целых четных чисел от 2 до n.

Вариант 5

Определить рекурсивную функцию, возвращающую список, из которого удалены 2-ой, 4-ый и т.д. элементы.

Вариант 6

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

 

 

Вариант 7

Определить рекурсивную функцию, возвращающую количество определенных элементов в списке.

Вариант 8

Определить рекурсивную функцию для циклического сдвига списка вправо на один элемент.

Вариант 9

Определить рекурсивную функцию, возвращающую список, из которого удалены 1-ой, 3-ый и т.д. элементы.

 

Методические указания:







Дата добавления: 2015-08-29; просмотров: 1099. Нарушение авторских прав; Мы поможем в написании вашей работы!



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

Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

Тема: Составление цепи питания Цель: расширить знания о биотических факторах среды. Оборудование:гербарные растения...

В эволюции растений и животных. Цель: выявить ароморфозы и идиоадаптации у растений Цель: выявить ароморфозы и идиоадаптации у растений. Оборудование: гербарные растения, чучела хордовых (рыб, земноводных, птиц, пресмыкающихся, млекопитающих), коллекции насекомых, влажные препараты паразитических червей, мох, хвощ, папоротник...

Типовые примеры и методы их решения. Пример 2.5.1. На вклад начисляются сложные проценты: а) ежегодно; б) ежеквартально; в) ежемесячно Пример 2.5.1. На вклад начисляются сложные проценты: а) ежегодно; б) ежеквартально; в) ежемесячно. Какова должна быть годовая номинальная процентная ставка...

Именные части речи, их общие и отличительные признаки Именные части речи в русском языке — это имя существительное, имя прилагательное, имя числительное, местоимение...

Интуитивное мышление Мышление — это пси­хический процесс, обеспечивающий познание сущности предме­тов и явлений и самого субъекта...

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

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия