Sunteți pe pagina 1din 3

Prelucrarea listelor in Prolog

Probleme rezolvate
1. Se considera doua variante de definire a predicatului de numarare a elementelor dintr-o lista.

Prima varianta, nr_elem(Lista, NrElem), construieste solutia (calculeaza numarul de elemente din
lista) pe ramura de revenire din recursivitate. (Ca în orice limbaj de programare recursiv, parametrii de
iesire ai subprogramelor, deci argumentele sintetizate ale predicatelor în cazul limbajului Prolog, pot fi
calculate fie pe ramura de avans în recursivitate, fie pe ramura de revenire din recursivitate.)

% nr_elem(Lista, NrElem)
nr_elem([], 0).
nr_elem([ _ | Rest], N) :- nr_elem(Rest, N1), N is N1 + 1.

A doua varianta, nr_elem2(Lista, NrElem) calculeaza numarul de elemente din lista pe ramura de
avans în recursivitate. Pentru a realiza acest lucru, se foloseste un predicat ajutator
nr_elem1(Lista, NrAcumulat, NrElem) care are un argument suplimentar fata de predicatul
nr_elem2. Acest argument, NrAcumulat, are rolul de variabila de acumulare a numarului de elemente
din lista pe masura avansului în recursivitate şi este instantiat la primul apel la valoarea 0. În momentul
atingerii punctului de oprire din recursivitate, deci în cazul în care lista ajunge vida, valoarea acumulata
în argumentul NrAcumulat este copiata în cel de-al treilea parametru al predicatului nr_elem1. Se
face apoi revenirea din apelurile recursive succesive fara a efectua nici o alta prelucrare, predicatul
nr_elem1 reuşeşte şi trimite valoarea calculata în NrElem predicatului initial nr_elem2.

% nr_elem2(Lista, NrElem)
% nr_elem1(Lista, NrAcumulat, NrElem)
nr_elem2(Lista, N) :- nr_elem1(Lista, 0, N).
nr_elem1([], N, N).
nr_elem1([ _ | Rest], N1, N2) :- N is N1 + 1, nr_elem1(Rest, N, N2).

2. O abordare similara se poate vedea în cazul celor doua variante de definire a predicatului de
intersectie a doua liste (determinarea elementelor comune celor doua liste).

Prima varianta, inter(Lista1, Lista2, ListaRez), calculeaza solutia (lista intersectie) pe ramura de
revenire din recursivitate. Cea de a doua varianta, int(Lista1, Lista2, ListaRez), calculeaza solutia pe
ramura de avans în recursivitate, utilizând int1(Lista1, Lista2, ListaAcumulare, ListaRez) ca predicat
ajutator cu parametrul suplimentar ListaAcumulare, instantiata la primul apel la lista vida.

% inter(Lista1, Lista2, ListaRez)


member(Elem, [Elem|_]) :- !.
member(Elem, [_|Rest]) :- member(Elem, Rest).
inter([], _, []).
inter([Prim|Rest], Lista2, [Prim|LRez]) :-
member(Prim, Lista2), !,
inter(Rest, Lista2, LRez).
inter([ _ | Rest], Lista2, LRez) :- inter(Rest, Lista2, LRez).

% int(Lista1, Lista2, ListaRez)


% int1(Lista1, Lista2, ListaAcumulare, ListaRez)
int(L1, L2, LRez) :- int1(L1, L2, [], LRez).
int1([], _, L, L).
int1([Prim|Rest], L, L1, L2) :-
member(Prim,L), !,
int1(Rest, L, [Prim | L1], L2).
int1([ _ | Rest], L, L1, L2) :- int1(Rest, L, L1, L2).

Obs. Aceasta tehnica de programare, des întîlnita în programele Prolog, are o serie de avantaje, printre
care o claritate crescuta şi, în principal, utilizarea definitiilor de predicate recursive la urma. Un
predicat recursiv la urma este un predicat în care apelul recursiv al acestuia este ultimul scop din
conjunctia de scopuri care îl defineste şi pentru care nu mai exista nici o regula posibila de aplicat dupa
apelul recursiv. Un astfel de predicat are avantajul ca poate fi apelat recursiv de oricâte ori fara a
genera o depasire a stivei. În plus executia unui astfel de predicat este mai eficienta.

3. Multimile pot fi reprezentate în Prolog ca liste. Predicatul multime(L, M) transforma lista L in


multimea M.

multime([], []).
multime([X | Rest], Rez) :- member(X, Rest), multime(Rest, Rez).
multime([X | Rest], [X | Rez]) :- not(member(X, Rest)), multime(Rest, Rez).

4. Predicatul de definire a intersecţiei a două liste prezentat anterior se poate aplica şi pentru obţinerea
intersecţiei a două mulţimi. Prezentăm în continuare predicatul de determinare a reuniunii a două
mulţimi.

% reun(+L1,+L2,-L)
reun([],L,L).
reun([X | Rest], L, Rez) :-member(X,L), reun(Rest,L,Rez).
reun([X | Rest], L, [X | Rez]) :-not member(X,L), reun(Rest,L,Rez).

Probleme propuse

1. Eliminarea unui obiect dintr-o lista. Scrieti un predicat care elimina un obiect dintr-o lista. Astfel,
elim(a, [a, b, c], L) va returna în L lista [b, c].

2. Incluziunea listelor. Scrieti un predicat care este adevarat daca o lista este sublista alteia. De
exemplu, sublist([c, d, e], [a, b, c, d, e, f]) este adevarat, iar sublist([b, c, e], [a, b, c, d, e, f]) este fals.
Indicatie: Puteti folosi predicatul append. O lista S este sublista a listei L daca:
Exista o descompunere a lui L în L1 si L2
si
Exista o descompunere a lui L2 în S si L3.

3. Liniarizarea listelor. Scrie predicatul liniar(ListaListe, Lista), unde ListaListe este o lista de
elemente care pot fi rândul lor liste, iar în Lista se construieste liniarizarea listei ListaListe. Astfel,
liniar([1, 2, [3, 4], [5, [6, 7], [[8], 9]]], L) va returna in L lista [1, 2, 3, 4, 5, 6, 7, 8, 9].

4. Scrieti un predicat descomp(N, Lista) care primeste un numar întreg N si întoarce o lista a factorilor
primi ai numarului N; de exemplu: descomp(12, [2, 2, 3]) este adevarat.

5. Scrieti un predicat invers(Lista, ListaInversata) care inverseaza elementele unei liste; sa se scrie doua
variante ale predicatului de inversare a unei liste: o varianta în care lista inversata este calculata pe
ramura de revenire din recursivitate şi o varianta în care lista inversata este calculata pe ramura de
avans în recursivitate.

6. Scrieti un predicat palindrom(Lista) care verifica daca o lista este palindrom. (Un palindrom este o
secventa care, daca este parcursa de la stânga la dreapta sau de la dreapta la stânga, este identica; de
exemplu: [a, b, c, b, a] sau [a, b, c, c, b, a].)

7. Sa se modifice predicatul anterior astfel incit sa genereze liste palindrom cu elemente 0 si 1.

8. Scrieti un predicat rotire(Lista, Directie, Nr, ListaRez) care roteste Lista cu un număr de Nr elemente
la stânga (dacă Directie = stg) sau la dreapta (dacă Directie = dr), depunând rezultatul în ListaRez.

9. Sa se scrie predicatul substitutie(X, Y, L1, L2), unde L2 este rezultatul substituirii tuturor aparitiilor
lui X din lista L1 cu Y.
Ex: substitutie(a, x, [a, [b,a,] c], L2) va produce: L2 = [x, [b, x], c].

10. Sa se scrie predicatul imparte(L, L1, L2) care împarte lista L în doua subliste L1 si L2, care au un
numar de elemente aproximativ egal, fara a calcula lungimea listei L.
Ex: imparte([a, b, c, d, e], L1, L2) va produce: L2 = [a, b, c] si L3 = [d, e].

11. Sa se scrie un predicat evenmember(Elem,Lista) care spune daca Elem se afla in Lista pe o pozitie
para. De exemplu, apelul evenmember(X,[1,5,3,4]) va returna pe rind solutiile
X = 5;
X = 4.

12. Sa se scrie un predicat imparte(L1,L2,L3) care imparte lista L1 in doua liste L2 si L3, L2 continind
elementele de pe pozitii impare iar L3 pe cele de pe pozitii pare.
Ex: imparte([a,b,c,d,e],L2,L3) va produce L2=[a,c,e] si L3=[b,d].

S-ar putea să vă placă și