Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / РЕКУРСИЯ.doc
Скачиваний:
37
Добавлен:
23.03.2015
Размер:
89.09 Кб
Скачать
    1. Рекурсія

Поряд з методом пошуку з поверненням (backtracking), рекурсія в мові ПРОЛОГ є одним з основних засобів побудови повторюваних дій у програмі. Тому вона вимагає більш детального аналізу в нашому курсі.

Звичайно, усяке нове поняття визначається через інші поняття, що передбачаються уже відомими.

Наприклад, визначення тангенса tg(x) = sin(x) / cos(x). Тобто тангенс визначається через sin, cos та /. Рухаючись від обумовленого поняття до використовуваного у визначеннях, ми, зрештою, приходимо до первинних (не обумовлених у рамках даної математичної теорії) понять (наприклад, крапка, пряма, число і т.і.).

Схожа ситуація виникає й у програмуванні. Кожну програму можна розглядати як набір операцій, кожна з яких визначає деяку нову команду через інші, що передбачаються відомими. Рухаючись від обумовленої команди до використовуваних, ми, зрештою, повинні прийти до невизначуваних понять, тобто до команд, що входять у систему команд виконавця для якого пишеться наша програма.

Але й у математиці й у програмуванні іноді зустрічаються “визначення”, що не укладаються в цю схему.

Наприклад.

fact (n) = 1, якщо n = 0

(*)

fact(n) = n*fact(n-1), якщо n>0

На перший погляд це визначення здається безглуздим, але воно працює:

fact (0) = 1, fact (1) = 1 * fact (1) = 1, fact (2) = 2*fact (1) = 2 і т.і.

Це визначення відрізняється від марних, хоча і вірних визначень

fact (n) = fact (n+2) / ((n+1)*(n+2)) або

fact (n) = fact (n)

У чому відмінності? Перша рівність є насправді не визначенням, а вимогою до функцій. Друге – найбільш слабка вимога – їй задовільняє будь-яка функція. Перша – більш сильна вимога, але йому задовольняє і така функція як

fact1(n) = C*fact1(n)

при будь-якому натуральному C.

І нарешті, вимозі (*) задовольняє лише одна функція. І це можна строго довести. Такі визначення прийнято називати рекурсивними. Рекурсивний – значить той, що використовує самого себе.

Такі визначення часто зустрічаються в житті.

Наприклад.

З'ЯСУВАТИ ЗНАЧЕННЯ СЛОВА:

1) Знайти слово в словнику.

2) Прочитати статтю, що пояснює значення цього слова.

Якщо пояснення зрозуміле, тобто стаття не містить незрозумілих слів, ПРОДОВЖ ЧИТАННЯ З ОСТАННЬОГО ПЕРЕРВАНОГО МІСЦЯ.

Якщо в поясненні зустрічається незнайоме слово, то ПРИПИНИ ЧИТАННЯ, ЗАПАМ'ЯТАЙ МІСЦЕ ПРИПИНЕННЯ і з'ясуй значення незнайомого слова, дотримуючи сукупності правил З'ЯСУВАТИ ЗНАЧЕННЯ СЛОВА.

Мова йде не про порочне коло визначень, а про образ дій, що придатний для використання і цілком виконуємий.

Інший приклад: родинні відносини.

X і Y є РОДИЧАМИ, якщо

а) Y – батько, мати, син, чи дочка X;

б) існує такий Z, що X є РОДИЧЕМ Z, а Z є РОДИЧЕМ Y.

      1. Рекурсія в програмуванні

Рекурсія, тобто можливість ввести у визначення об'єкта посилання на сам об'єкт, часто використовується в програмуванні. Рекурсія - це один з фундаментальних інструментів, що є у розпорядженні програміста і вона заслуговує більш уважного підходу до себе. Рекурсивні визначення часто використовуються в програмуванні для визначення рекурсивних структур даних.

Наприклад, при програмуванні мовою ПАСКАЛЬ.

TYPE /* Лінійний односпрямований список */

ListPtr = ^List;

List = record

Info: InfoType;

Next: ListPtr;

end;

або

TYPE /* Бінарне дерево */

BinTreePtr = ^BinTree;

BinTree = record

Info: InfoType;

Left: BinTreePtr;

Right: BinTreePtr;

end;

Для обробки рекурсивних структур зручно використовувати рекурсивні алгоритми. Наприклад, висота бінарного дерева може бути визначена за допомогою рекурсивної функції

0, якщо t = nil

Висота(t) = 

1 + max( Висота( left(t)), Висота( right(t) ) ), якщо t  nil

Це визначення легко описується рекурсивною функцією на Паскалі.

function Height(t: BinTreePtr): byte;

begin

if t = nil then

Height := 0

else

Height := max (Height(t^.Left), Height(t^.Right))

end;

Соседние файлы в папке Библиотека