- •2.1 Мета роботи
- •2.2 Методичні вказівки з організації самостійної роботи студентів
- •Завдання:
- •Використання команди "cut"
- •5.1 Методичні вказівки до самостійної роботи і виконання роботи
- •Дерева – як типи даних
- •Обхід дерева
- •Створення дерева
- •Бінарні пошукові дерева
- •Сортування на основі дерева
- •61166 Харків, просп. Науки, 14.
Використання команди "cut"
Достатньо просто зробити рекурсивний виклик в останній підцілі останнього речення. Але як гарантувати, що в будь яких інших викликаних процедурах немає альтернатив? Команда cut (!) дозволяє відкидати всі існуючі альтернативи. Щоб встановити її, необхідно використовувати директиву check_determ.
Можна встановити badcount3 таким способом (змінюючи його ім’я в процесі) та залишаючи check без змін:
сutcount3(X) :-
write(‘\r’, X),
NewX = X+1,
check(NewX),
!,
cutcount3(NewX).
Команда "cut", "одного разу дійшовши до цієї точки, не звертає уваги на альтернативні пропозиції цього предикату та альтернативні рішення попередніх підцілей включаючи цю пропозицію". Оскільки альтернативи виключаються, стек не потрібен та рекурсивний виклик може спокійно йти далі.
"Cut" також ефективний в badcount2:
cutcount2(X) :-
X >= 0, !,
write(‘\r’, X),
NewX = X+1,
cutcount2(NewX).
cutcount2(_) :-
write("X is negative.).
Ящо "cut" виконується, комп’ютер вважає, що неперевірених альтернатив, немає і створює стек.
На жаль, "cut" не може допомогти badcount1, якому необхідність стеків не дозволяє нічого робити із неперевіреними альтернативами.
Єдиний спосіб удосконалити badcount1 – зобразитии обчислення так, щоб рекурсивний виклик приходив у кінці пропозиції.
/* Файл Lab3_6.PRO */
рredicate
count(real) % хвостова рекурсія, яка не виснажує пам’ять.
/*Три предиката без хвостової рекурсії. Вони виснажують запас своєї пам’яті через декілька сотен ітерацій.*/
badcount1(real)
badcount2(real)
badcount3(real)
/* Наступні два предикати зображують, як bedcount2 и bedcount3 можуть бути встановлені оголошенням "cut" для виключення неперевірених запитів. Ці версії хвостова рекурсія. */
cutcount2(long)
cutcount3(long)
check(long)
clauses
count(N) :-
write(N), nl,
NewN = N+1,
count(NewN).
/* badcount1:
Рекурсивний виклик не останній крок.*/
badcount1(X) :-
write(X), nl,
NewX = X+1,
badcount1(NewX),
nl.
/* badcount2:
Запит не використовується під час рекурсивного виклику. */
badcount2(X) :-
write(X), nl,
NewX = X+1,
badcount2(NewX).
badcount2(X) :-
X < 0,
write("X is negative.").
/* badcount3:
Неперевірена альтернатива в процедурі, що виконується перед
рекурсивним викликом. */
badcount3(X) :-
write(X), nl,
NewX = X+1,
check(NewX),
badcount1(NewX).
/* cutcount2:
Виконання цього запиту не завершується під час рекурсивного виклику. */
cutcount2(X) :-
X >= 0, !,
write(X),
nl,
NewX = X+1,
cutcount2(NewX).
cutcount2(_) :-
write("X is negative.").
/* cutcount3:
Неперевірена альтернатива в запиті, що виконується перед рекурсивним викликом. */
cutcount3(X) :-
write(X),
nl,
NewX = X+1,
check(NewX),
!,
cutcount3(NewX).
check(Z) :- Z >= 0.
check(Z) :- Z < 0.
Зауважте, що badcount2 і badcount3 гірші, ніж badcount1, тому що вони створюють зворотні точки.
3.4 Контрольні запитання і завдання
Створіть програму «порадник з транспорту». Виберіть або мережу, що складається з міст, або транспортну мережу маршрутів тролейбусів чи автобусів у межах одного міста. Ви повинні інформувати систему про те звідки і куди ви збираєтеся дістатися, а система має видавати рекомендації про те, якими поїздами, автобусами, тролейбусами, літаками тощо треба скористатися, аби дістатися пункту призначення.
Програма може містити, наприклад,
а) факти:
подорож(компанія, пункт_відправлення, пункт_призначення, вид_транспорту),
б) рекурсивну процедуру «можна_подорожувати», яка визначає відношення між двома містами: можна здійснити подорож з одного міста в інше через будь-яку кількість проміжних пунктів.
2. Напишіть програму з хвостовою рекурсією, яка передрукує таблицю ступенів числа 2, як показано нижче:
N 2^N
--- -----
1 2
2 4
3 8
4 16
... ...
10 1024
Зупиніть програму при N = 10.
Напишіть програму з хвостовою рекурсією, яка допускає ввід числа і здатна завершитися двома способами. Вона має починатися множенням числа самого на себе до тих пір, доки не досягне числа 81 або числа, більшого ніж 100. Якщо досягнуто число 81, то друкується "YES", якщо число більше 100 друкується "NO".
Індивідуальні завдання типу знайти значення ряду
.
Реалізувати за допомогою ітеративного і рекурсивного алгоритмів.
Зауваження: оскільки у Пролозі немає операції піднесення до степеня, то
.
№ 4.1
Дано натуральне число N. Обчислити:
S
=
№ 4.2
Дано натуральне число N. Обчислити:
S
=
№
4.3
Дано натуральне число N. Обчислити добуток перших N множників
P
=
№ 4.4
Дано натуральне число N. Обчислити:
№ 4.5
Дано дійсне число Х. Обчислити:
№ 4.6
Дані натуральне n, дійсне x. Обчислити:
№ 4.7
Дані дійсне число а, натуральне число n. Обчислити:
P = a(a+1)…(a+n-1).
№ 4.8
Дані дійсне число а, натуральне число n. Обчислити:
P = a(a-n)(a-2n)…(a-n2).
№ 4.9
Дані дійсне число а, натуральне n. Обчислити:
.
№ 4.10
Дано дійсне число x. Обчислити:
.
№ 4.11
Обчислити: (1+sin 0,1)(1+sin 0,2)…(1+sin10).
№ 4.12
Дані натуральне n, дійсне x. Обчислити:
№ 4.13
Дано натуральне число n. Обчислити:
S=
№ 4. 14
Дано натуральне число n. Обчислити:
P=
№ 4.15
Дано натуральне число n. Обчислити:
P=
.
№ 4.16
Дано натуральне число n. Обчислити:
S=1!+2!+3!+…+n! (n>1).
№ 4.17
Дано натуральне число n. Обчислити:
№ 4.18
Числа Фібоначчі (fn) визначаються формулою
Визначити f40.
№ 4.19
Дано натуральне число n. Обчислити:
y
= 1
.
№ 4. 20
Дано натуральне число n. Обчислити:
y=2
.
№ 4.21
Обчислити:
.
№ 4.22
Обчислити:
y = sin 1+sin 1,1+sin 1,2+…+sin 2.
№ 4.23
Дані натуральні числа n і k. Обчислити:
.
№ 4. 24
Дано натуральне число n. Обчислити:
.
ЛАБОРАТОРНА РОБОТА № 4 СПИСКИ
Списки – це об’єкти, що мають кінцеве число елементів. Оголошують їх додаючи "*" (зірочку) у кінці заздалегідь визначеного типу.
domains
intlist=integer* /*Список цілих чисел*/
Список – це рекурсивний комбінований об’єкт, що складається із голови і хвоста. Голова – перший елемент списку, а хвіст – все інше (без першого елемента). Хвіст списку – завжди список. Голова списку завжди елемент. Список може мати 0 або більше елементів. Вільний список записується так [].
У Пролозі список розглядається як окремий випадок бінарного дерева:
Елементи можуть бути будь-якими, включаючи інші списки. Всі елементи списку мають належати одному й тому ж типу. В Пролозі не можна змішувати типи у списку.
Для розділення голови і хвоста в списку використовують «розділювачі» (кома, [ і ]); У голові списку можна виділити декілька елементів, наприклад, список [a, b, c, d] може бути записаний як:
[a|[b, c, d]] або
[a, b|[c, d]] або
[a, b, c|[d]] або
[a|[b|[c, d]]] або
[a|[b|[c|[d]]]] або навіть
[a|[b|[c|[d|[]]]]]
Пустий список не можна розділити на голову та хвіст.
Порядок елементів у списку суттєвий. Один і той самий об’єкт може зустрічатися в списку декілька разів.
Головний спосіб обробки списку – це перегляд його й обробка кожного елемента, поки не буде досягнуто кінця. Алгоритму цього типу зазвичай потрібно два речення, перше із яких говорить, що робити зі звичайним списком (списком, який можна розділити на голову та хвіст). Друге говорить, що робити із вільним списком. Тобто робота зі списком складається зі рекурсивного виділення голови (та його обробки) до тих пір, доки список не стане вільним.
/* Лістинг програми Lab4_1.pro*/
domains
intlist=integer*
predicates
cr_list (intlist,intlist) % Створення списку
do % Головна процедура
list (intlist) % Вивід списку права рекурсія
list1 (intlist) % Вивід списку ліва рекурсія
member (integer,intlist) % Чи є елемент членом списку
length(intlist,integer) % обчислення довжини списку (ліва рекурсія)
length_of(intlist,integer,integer) % обчислення довжини списку (права рекурсія)
app_el (integer,intlist,intlist) % Додати елемент у початок списку
ins (integer,intlist,intlist) % Додати елемент у довільну позицію списку
del_el (integer,intlist,intlist) % видалення першого входження елемента в
% список
delete (integer,intlist,intlist) % видалення всіх входжень елементів у список
append(intlist, intlist, intlist) % Додати другий список у кінець першого
% списку
sublist(intlist,intlist) % підсписок списку
perest(intlist,intlist) % перестановки
clauses
list([]).
list([X|XS]):-write(X," "),list(Xs).
list1([]).
list1([X|T]):-list1(T),write(X," ").
member(X,[X|Xs]).
member(X,[Y|Ys]):-member(X,Ys).
app_el(X,L,[X|L]).
cr_list(List,NewList):-readint(X),
X<>999,!,
app_el(X,List,TempList),
cr_list(TempList,Newlist).
cr_list(List,List).
length([],0).
length([_|Xs],N):- length(Xs,N1),N=N1+1.
length_of([], Result, Result).
length_of([_|T], Result, K) :-
NewK = K + 1,
length_of(T, Result, NewK).
append([], List, List).
append([X|L1], List2, [X|L3]) :- append(L1, List2, L3).
del_el(X,[X|T],T).
del_el(X,[Y|T],[Y|T1]):-
del_el(X,T,T1).
delete(X,[X|Xs],Ys):-delete(X,XS,Ys).
delete(Z,[X|Xs],[X|Ys]):-delete(Z,Xs,Ys).
delete(X,[],[]).
sublist(S,L):- append(L1,L2,L),append(S,L3,L2).
ins(X,List,Biglist):-del_el(X,Biglist,List),list(Biglist),nl,fail.
perest([],[]).
perest(L,[X|P]):- del_el(X,L,L1),perest(L1,P).
do:-
write("Введіть елементи списку. Ознака закінчення вводу 999."),nl,
cr_list([],Nlist),!,nl,
list(NList),nl,
length(NList,N),
write("Кількість елементів списку =",N),nl.
goal
do.
Розглянемо предикат append, визначений у програмі Lab4_1.PRO. Завантажте програму та прокоментуйте секцію goal. Запустіть такі цільові ствердження:
append([1, 2, 3], [5, 6], L).
append([1, 2], [3], L).
У Пролозі один і той самий предикат може мати декілька варіантів використання.
Класичні предикати Прологу member (елемент списку) і append (додати елемент до списку) дають можливість перевірити чи є елемент у списку, та перевірити чи є один список в іншому відповідно.
Розглядаючи append з декларативної точки зору, ви визначили відношення між трьома списками. Це відношення все одно залишиться, якщо List1 і List3 відомі, а List2 ні. Воно так само справедливо, якщо відомі тільки List3. Наприклад, щоб визначити, які з двох списків можна об’єднати для того, щоб отримати відомий список, потрібно скласти цільове ствердження такої форми:
append(L1, L2, [1, 2, 4]).
За цим цільовим ствердженням Пролог знайде такі рішення:
L1 = [], L2 = [1,2,4]
L1 = [1], L2 = [2,4]
L1 = [1,2], L2 = [4]
L1 = [1,2,4], L2 = []
4 Solutions
Можна також застосувати append, щоб визначити, який список можна під’єднати до [3, 4], щоб отримати список [1, 2, 3, 4]. Запустіть такі цільові ствердження:
append(L1, [3,4], [1,2,3,4]).
Пролог знайде рішення:
L1 = [1,2].
Предикат append визначив відношення між вхідним та вихідним наборами так, що відношення можна застосувати в обох напрямках. Задаючи таке відношення, отримуємо відповіді на запитання:
як відноситься вихід з даним входом? Чи
як відноситься вхід з даним виходом ?
Стан аргументів у разі виклику предиката передається як потік параметрів. Аргумент, що присвоюється чи призначається у момент виклику, називається вхідним аргументом та позначається буквою (i); а вільний аргумент – це вихідний аргумент, що позначається буквою (o).
У предиката append є можливість маніпулювати та переставляти частини так, як необхідно. Однак не для всіх предикатів є можливість бути викликаними з потоком параметрів. Коли в реченні Прологу можна працювати з потоком параметрів, воно називається «інверсним реченням». Коли ви записуєте власні речення в Пролозі, пам’ятайте, що інверсні речення мають додаткові переваги, та створення інверсних речень додає потужності предикатам, які ви пишете.
4.5 Контрольні запитання і завдання
Визначте відношення останнім (Елемент, Список) так, щоб Елемент був останнім елементом списку Список. Напишіть два варіанти визначення: з використанням відношення append і без нього.
Використовуючи відношення append, напишіть предикат, що відповідає викреслюванню трьох останніх елементів списку L, результат – новий список L1. Вказівки: L конкатенація L1 і тривимірного списку.
Напишіть послідовність цілей для породження списку L2, що отримується зі списку L кресленням його трьох перших та трьох останніх елементів.
Визначте два предикати: «парна довжина (Список) ы непарна довжина (Список)» так, щоб вони були істинними, якщо їх аргументами є список «парної» або «непарної» довжини відповідно. Наприклад, [a,b,c,d] – має «парну» довжину, [a,b,c] – має «непарну» довжину.
Визначити відношення звернення (Список, Список), яке звертає список, наприклад, звернення ([a,b,c,d], [d,c,b,a]).
Визначити предикат: «паліндром (Список)» так, щоб він був істинним, якщо список зліва направо і справа наліво читався однаково. Наприклад, [a,b,c,b,a].
Визначте відношення зсув (Список1, Список2) так, щоб Список2 був Списком1, циклічно зсуненим вліворуч на один символ. Наприклад,
зсув ([a,b,c,d], L), L=[b,c,d,a].
Визначте предикат: максспис (Список, Макс) – пошук максимального елемента в списку.
Визначте предикат: сумспис (Список, Сума) – добуток елементів списку.
Визначте предикат: упорядкованим (Список) так, щоб він був істинним, якщо список впорядкований за зростанням або за зменшенням. Наприклад, [1,2,3,4,5].
Визначте відношення
видалити_підсписок (Список1, Список2, Список)
так, щоб зі списку Список2 видалявся підсписок Список1, в результаті чого отримуємо список Список.
Наприклад, видалити_підсписок ([1,2,3,4],[2,3],L), L=[1,4].
Визначити відношення
розбиття_списку (Список, Список1, Список2)
так, щоб воно розподіляло елементи списку між двома списками Список1 і Список2 і щоб ці списки були приблизно однакової довжини.
Наприклад, розбиття_списку ([a,b,c,d,e], [a,c,e],[b,d]).
Визначте процедуру між (N1,N2,X), яка за допомогою перебору породжує список Х усіх цілих чисел, відповідаючи умові N1 х N2.
Видалити всі повторні входження елементів у список. Наприклад: [1,2,2,3] [1,2,3].
Підрахувати число елементів списку без будь-якого вказуваного елемента.
Підрахувати число відповідних символів у списку.
Є список, кожен елемент якого у свою чергу є списком. Знайти середнє арифметичне останніх елементів елементів-списків.
Є список, кожен елемент якого у свою чергу є списком. Вивести найкоротший та найдовший із елементів-списків.
Є список, кожен елемент якого у свою чергу є списком. Відсортувати список верхнього рівня (по довжині елементів-списків другого рівня).
Відсортувати слова у списку за алфавітом.
Підрахувати число букв у кожному слові рядка і сформувати список, елементами якого є числа, отримані в результаті підрахунку.
Посунути циклічно список праворуч на відповідне число елементів.
Посунути циклічно список ліворуч на відповідне число елементів.
ЛАБОРАТОРНА РОБОТА № 5 ДЕРЕВА
