Sunteți pe pagina 1din 100

Cuprins

1. Lucrul cu masive memorate în zona HEAP ....................................................... 3

2. Implementarea structurii de listă în limbajul Pascal ................................... 11

3. Grafuri. Implementări în limbajul Pascal ........................................................ 39

4. Arbori ...................................................................................................................... 48

5. Algoritmi recursivi. Metodele divide et impera şi backtracking ............ 54

6. Reprezentarea vizuală a datelor ....................................................................... 75

7. Obiecte în Pascal .................................................................................................. 87

Bibliografie ................................................................................................................. 100


1. LUCRUL CU MASIVE MEMORATE
ÎN ZONA HEAP

Problema 1. Fie x un vector de numere reale, preluat de la tastatură şi


memorat dinamic. Scrieţi programul Pascal pentru sortarea lui x.

uses crt;
type
vector=array[1..100] of real;
pvect=^vector;
var
x:pvect;
i,j,n:byte;
aux:real;

begin
clrscr;
write('Dimensiunea:');
readln(n);
new(x);
writeln('Elementele vectorului:');
for i:=1 to n do
begin
write('x[',i,']=');
readln(x^[i]);
end;
for i:=1 to n-1 do
for j:=i+1 to n do
if x^[i]>x^[j] then
begin
aux:=x^[i];
x^[i]:=x^[j];
x^[j]:=aux;
end;
writeln('Vectorul sortat');
for i:=1 to n do
write(x^[i]:7:2,' ');
dispose(x);
readln;
end.

3
Programarea calculatoarelor. Aplicaţii

Problema 2. Fie x un vector preluat de la tastatură şi memorat în zona heap.


Scrieţi programul Pascal pentru căutarea unui element dat, cheie, în x. Dacă cheie
este element al vectorului x, să se determine prima poziţie de apariţie.

uses crt;
type
vector=array[1..100] of real;
pvect=^vector;
var
x:pvect;
i,n,prima:byte;
cheie:real;
gasit:boolean;

begin
clrscr;
write('Dimensiunea:');
readln(n);
getmem(x,sizeof(vector));
writeln('Elementele vectorului:');
for i:=1 to n do
begin
write('x[',i,']=');
readln(x^[i]);
end;
write('Cheia de cautare');
readln(cheie);
i:=1;
gasit:=false;
while(i<=n)and(not gasit) do
if x^[i]=cheie then
begin
prima:=i;
gasit:=true;
end
else
i:=i+1;
if gasit then
writeln('Prima aparitie a elementului ',cheie:7:2,' in vector
este ',i)
else
writeln('Elementul ',cheie:7:2,' nu apare in vector');
freemem(x,sizeof(vector));
readln;
end.
Problema 3. Scrieţi programul pentru calculul produsului scalar al doi
vectori citiţi de la tastatură şi memoraţi dinamic. Produsul scalar este calculat într-o
funcţie.
uses crt;
type
vector=array[1..100] of real;
pvect=^vector;
var
x,y:pvect;
i,n:byte;
function produs_scalar(var x,y:pvect;n:byte):real;
var

4
Lucrul cu masive memorate în zona heap

i:byte;
ps:real;
begin
ps:=0;
for i:=1 to n do
ps:=ps+x^[i]*y^[i];
produs_scalar:=ps;
end;
begin
clrscr;
write('Dimensiunea:');
readln(n);
getmem(x,sizeof(vector));
writeln('Elementele primului vector:');
for i:=1 to n do
begin
write('x[',i,']=');
readln(x^[i]);
end;
getmem(y,sizeof(vector));
writeln('Elementele celui de-al doilea vector:');
for i:=1 to n do
begin
write('y[',i,']=');
readln(y^[i]);
end;
writeln('Produsul scalar este ',produs_scalar(x,y,n):9:2);
freemem(y,sizeof(vector));
freemem(x,sizeof(vector));
readln;
end.

Problema 4. Scrieţi programul pentru interclasarea a doi vectori sortaţi


crescător. Vectorii de interclasat, precum şi vectorul rezultat al interclasării sunt
memoraţi dinamic. Interclasarea este realizată într-un subprogram.
uses crt;
type
vector=array[1..100] of real;
vector1=array[1..200] of real;
pvect=^vector;
pvect1=^vector1;
var
x,y:pvect;
z:pvect1;
i,n,m:byte;
procedure interclasare(var x,y:pvect;var z:pvect1;m,n:byte);
var
i,j,k:byte;
begin
i:=1;j:=1;k:=1;
while(i<=m)and(j<=n) do
begin
if(x^[i]<y^[j]) then
begin
z^[k]:=x^[i];
inc(i);
end
else

5
Programarea calculatoarelor. Aplicaţii

begin
z^[k]:=y^[j];
inc(j);
end;
inc(k);
end;
if i<=m then
while(i<=m) do
begin
z^[k]:=x^[i];
inc(i);inc(k);
end
else
while(j<=n) do
begin
z^[k]:=y^[j];
inc(j);inc(k);
end;
end;

begin
clrscr;
write('Dimensiunea primului vector:');
readln(m);
new(x);
writeln('Elementele primului vector:');
for i:=1 to m do
begin
write('x[',i,']=');
readln(x^[i]);
end;
write('Dimensiunea celui de-al doilea vector:');
readln(n);
new(y);
writeln('Elementele celui de-al doilea vector:');
for i:=1 to n do
begin
write('y[',i,']=');
readln(y^[i]);
end;
new(z);
interclasare(x,y,z,m,n);
writeln('Vectorul rezultat al interclasarii ');
for i:=1 to m+n do
write(z^[i]:7:2,' ');
dispose(x);
dispose(y);
dispose(z);
readln;
end.

Problema 5. Scrieţi programul Pascal pentru calculul transpusei unei


matrice. Matricea de intrare şi transpusa acesteia sunt memorate dinamic.

uses crt;
type
matrice=array[1..10,1..10] of real;
pmat=^matrice;
var

6
Lucrul cu masive memorate în zona heap

a,b:pmat;
i,j,n,m:byte;

begin
clrscr;
write('Numarul de linii ');
readln(m);
write('Numarul de coloane');
readln(n);
new(a);
new(b);
writeln('Elementele matricei:');
for i:=1 to m do
for j:=1 to n do
begin
write('a[',i,',',j,']=');
readln(a^[i,j]);
end;
for i:=1 to n do
for j:=1 to m do
b^[i,j]:=a^[j,i];
writeln('Matricea transpusa ');
for i:=1 to n do
begin
for j:=1 to m do
write(b^[i,j]:10:2);
writeln;
end;
dispose(a);
dispose(b);
readln;
end.

Problema 6. Scrieţi programul Pascal pentru calculul sumei a două matrice.


Matricele utilizate sunt memorate în zona heap.

uses crt;
type
matrice=array[1..10,1..10] of real;
pmat=^matrice;
var
a,b,c:pmat;
i,j,n,m:byte;
begin
clrscr;
write('Numarul de linii ');
readln(m);
write('Numarul de coloane ');
readln(n);
new(a);
new(b);
new(c);
writeln('Elementele primei matrice:');
for i:=1 to m do
for j:=1 to n do
begin
write('a[',i,',',j,']=');
readln(a^[i,j]);
end;

7
Programarea calculatoarelor. Aplicaţii

writeln('Elementele celei de-a doua matrice:');


for i:=1 to m do
for j:=1 to n do
begin
write('b[',i,',',j,']=');
readln(b^[i,j]);
end;
for i:=1 to m do
for j:=1 to n do
c^[i,j]:=a^[i,j]+b^[i,j];
writeln('Matricea suma ');
for i:=1 to m do
begin
for j:=1 to n do
write(c^[i,j]:10:2);
writeln;
end;
dispose(a);
dispose(b);
dispose(c);
readln;
end.

Problema 7. Scrieţi programul Pascal pentru calculul prousului a două


matrice. Matricele utilizate sunt memorate în zona heap.

uses crt;
type
matrice=array[1..10,1..10] of real;
pmat=^matrice;

var
a,b,c:pmat;
i,j,n,m,p,k:byte;
begin
clrscr;
write('Numarul de linii al primei matrice');
readln(m);
write('Numarul de coloane al primei matrice');
readln(n);
write('Numarul de coloane al celei de-a doua matrice');
readln(p);
new(a);
new(b);
new(c);
writeln('Elementele primei matrice:');
for i:=1 to m do
for j:=1 to n do
begin
write('a[',i,',',j,']=');
readln(a^[i,j]);
end;
writeln('Elementele celei de-a doua matrice:');
for i:=1 to n do
for j:=1 to p do
begin
write('b[',i,',',j,']=');
readln(b^[i,j]);
end;
for i:=1 to m do

8
Lucrul cu masive memorate în zona heap

for j:=1 to p do
begin
c^[i,j]:=0;
for k:=1 to n do
c^[i,j]:=c^[i,j]+a^[i,k]*b^[k,j];
end;
writeln('Matricea produs ');
for i:=1 to m do
begin
for j:=1 to p do
write(c^[i,j]:10:2);
writeln;
end;
dispose(a);
dispose(b);
dispose(c);
readln;
end.

Exerciţii

1. Scrieţi programul pentru calculul sumei elementelor unei matrice


memorate dinamic.
2. Scrieţi programul pentru ordonarea descrescătoare a fiecărei linii dintr-o
matrice memorată în zona heap.
3. Scrieţi subprogramul pentru determinarea tuturor poziţiilor de apariţie ale
unei chei într-un vector. Vectorul este considerat memorat dinamic.
4. Scrieţi subprogramul pentru calculul mediei geometrice a elementelor
pozitive dintr-un vector memorat dinamic.
5. Scrieţi un program pentru verificarea simetriei unei matrice memorate în
heap.
6. Scrieţi o funcţie pentru calculul normei unui vector memorat dinamic.
7. Scrieţi programul pentru calculul sumei elementelor de pe diagonala
principală a unei matrice. Matricea este memorată dinamic.
8. Scrieţi programul pentru calculul amplitudinii unui vector memorat
dinamic.
9. Scrieţi un subprogram pentru numărarea elementelor impare de pe
diagonala secundară a unei matrice.
10. Scrieţi un program pentru calculul mediei armonice a elementelor strict
pozitive ale fiecărei coloane dintr-o matrice. Matricea de intrare şi vectorul rezultat
sunt memorate în heap.
11. Scrieţi programul Pascal pentru sortarea descrescătoare a fiecărei
coloane dintr-o matrice memorate dinamic.
12. Scrieţi o funcţie pentru calculul mediei elementelor pare ale unei matrice
memorate în heap.
13. Scrieţi programul pentru calculul numărului de elemente nule de sub
diagonala principală a unei matrice memorate dinamic.
14. Scrieţi programul pentru calculul celui mai mare divizor comun al unui
şir de numere întregi memorat într-un vector dinamic.
9
Programarea calculatoarelor. Aplicaţii

15. Scrieţi un subprogram pentru numărarea tuturor elementelor prime ale


unei matrice dinamice.

Informaţii ajutătoare
1. Media geometrică a unui şir x de n numere reale strict pozitive este
definită prin
n
mg = n ∏xi =1
i .

2. Fie A o matrice pătratică, de dimensiune n. Matricea A este simetrică dacă


şi numai dacă, pentru orice 1 ≤ i < j ≤ n , ai , j = a j ,i .
3. Norma unui vector x de n numere reale este definită prin
n
x = x, x = ∑x
i =1
2
i .

4. Amplitudinea unui vector x de n numere reale este definită prin


A = max xi − min xi .
i =1,..., n i =1,..., n

5. Media armonică a unui şir x de n numere reale strict pozitive este definită
prin
n
mar = n
.
1

i =1 x i
6. Fie n un număr natural nenul. O posibilitate de verificare a proprietăţii de
de a fi prim a numărului n este următoarea: n este prim dacă, pentru orice
2 ≤ i ≤ [ n ] , i nu divide n.

10
2. IMPLEMENTAREA STRUCTURII DE
LISTĂ ÎN LIMBAJUL PASCAL

2.1. Aplicaţii cu liste lineare

Problema 1. Scrieţi un subprogram pentru inserarea unui nod la sfârşitul unei


liste lineare.

a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure inserare_la_sfarsit1(var l:lst; var n:word;


d:tip_informatie;var test:boolean);
var i:word;
begin
test:=true;
if n=max then test:=false
else
begin
n:=n+1;
atribuie(l[n],d);
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure inserare_la_sfarsit2(var cap:lista;


d:tip_informatie;var test:boolean);
var p,ultim:lista;
begin
test:=true;
if MaxAvail<sizeof(nod) then test:=false
else
begin
new(p);
p^.leg:=nil;
atribuie(p^.inf,d);
if cap=nil then
cap:=p

11
Programarea calculatoarelor. Aplicaţii

else begin
ultim:=cap;
while ultim^.leg<>nil do
ultim:=ultim^.leg;
ultim^.leg:=p;
end;
end;
end;

c) Lista reprezentată prin structură dinamică dublu înlănţuită

procedure inserare_la_sfarsit3(var cap:lista;


d:tip_informatie;var test:boolean);
var p,ultim:lista;
begin
test:=true;
if MaxAvail<sizeof(nod) then test:=false
else
begin
new(p);
p^.dr:=nil;
atribuie(p^.inf,d);
if cap=nil then
cap:=p
else begin
ultim:=cap;
while ultim^.dr<>nil do
ultim:=ultim^.dr;
ultim^.dr:=p;
p^.st:=ultim;
end;
end;
end;

Problema 2. Să se scrie un subprogram pentru inserarea datei d înaintea


primei componente care îndeplineşte o condiţie dată într-o listă lineară.
Includerea unei noi date într-o listă deja creată poate fi realizată înaintea/după
primul element care îndeplineşte o anumită condiţie. Funcţia Pascal function
conditie(a,b:tip_informatie):boolean calculează true, dacă condiţia formulată este
îndeplinită de perechea (a,b), altfel calculează false.
a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure inserare_inainte1(var l:lst;


var n:word;d:tip_informatie;var test:boolean);
var i,j:word;
begin
test:=true;
if n=max then test:=false
else
begin
i:=1;
while(i<=n)and (not conditie(l[i],d)) do i:=i+1;
if i<=n then
begin
for j:=n downto i do atribuie(l[j+1],l[j]);
atribuie(l[i],d);
n:=n+1;
end

12
Implementarea structurii de listă în limbajul Pascal

else test:=false;
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure inserare_inainte2(var cap:lista;d:tip_informatie;var


test:boolean);
var p1,p2,p:lista;
begin
test:=true;
if MaxAvail<sizeof(nod) then test:=false
else begin
if cap=nil then
test:=false
else begin
p2:=nil;
p1:=cap;
while (p1<>nil) and (not conditie(p1^.inf,d)) do
begin
p2:=p1;
p1:=p1^.leg;
end;
if p1=nil then test:=false
else
begin
new (p);
atribuie(p^.inf,d);
if p1=cap then
begin
p^.leg:=cap;
cap:=p;
end
else begin
p^.leg:=p1;
p2^.leg:=p;
end;
end;
end;
end;
end;

Problema 3. Scrieţi un subprogram pentru inserarea unei date d după prima


componentă care îndeplineşte o condiţia dată dintr-o listă lineară. Pentru funcţia
condiţie vezi problema 2.

a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure inserare_dupa1(var l:lst; var


n:word;d:tip_informatie;var test:boolean);
var i,j:word;
begin
test:=true;
if n=max then test:=false
else
begin
i:=1;
while(i<=n)and (not conditie(l[i],d)) do i:=i+1;

13
Programarea calculatoarelor. Aplicaţii

if i<=n then
begin
for j:=n downto i+1 do
atribuie(l[j+1],l[j]);
atribuie(l[i+1],d);
n:=n+1;
end
else test:=false;
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită


procedure inserare_dupa2(cap:lista;d:tip_informatie;var
test:boolean);
var p,p1:lista;
begin
if MaxAvail<sizeof(nod) then test:=false
else
begin
test:=true;
p:=cap;
while(p<>nil) and (not conditie(p^.inf,d)) do
p:=p^.leg;
if p=nil then test:=false
else begin
new(p1);
atribuie(p1^.inf,d);
p1^.leg:=p^.leg;
p^.leg:=p1;
end;
end;
end;

Problema 4. Scrieţi un subprogram pentru eliminarea ultimei componente a


unei liste lineare.

a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure elimina_ultima1(var l:lst; var n:word; var


d:tip_informatie;var test:boolean);
var i:word;
begin
test:=true;
if n=0 then test:=false
else
begin
atribuie(d,l[n]);
n:=n-1;
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure elimina_ultima2(var cap:ptlista;var d:tip_informatie;


var test:boolean);
var p,p1:lista;
begin
test:=true;

14
Implementarea structurii de listă în limbajul Pascal

if cap=nil then
test:=false
else
begin
p:=cap;
if p^.leg=nil then
begin
atribuie(d,p^.inf);
cap:=nil;
dispose(p);
end
else begin
while (p^.leg^.leg<>nil) do
p:=p^.leg;
p1:=p^.leg;
atribuie(d,p1^.inf);
p^.leg:=nil;
dispose(p1);
end;
end;
end;

Problema 5. Scrieţi un subprogram pentru eliminarea primului nod al unei


liste lineare pentru care câmpul de informaţie îndeplineşte o condiţie dată.
Funcţia Pascal conditie(a,b:tip_informatie):boolean calculează true, dacă
condiţia formulată este îndeplinită de perechea (a,b), altfel calculează false.
Parametrul d_cmp intervine în condiţia formulată asupra componentei de eliminat.

a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure elimina1(var l:lst; var n:word;d_cmp:tip_informatie;


var d:tip_informatie; var test:boolean);
var i,j:word;
begin
test:=true;
if n=0 then test:=false
else
begin
i:=1;
while(i<=n)and (not conditie(l[i],d_cmp)) do
i:=i+1;
if i<=n then
begin
atribuie(d,l[i]);
for j:=i to n-1 do
atribuie(l[j],l[j+1]);
n:=n-1;
end
else test:=false;
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure elimina2(var cap:lista; d_cmp:tip_informatie;


var d:tip_informatie;var test:boolean);
var p1,p2:lista;
begin

15
Programarea calculatoarelor. Aplicaţii

test:=true;
if cap=nil then test:=false
else begin
p2:=nil;
p1:=cap;
while (p1<>nil) and (not conditie(p1^.inf,d_cmp)) do
begin
p2:=p1;
p1:=p1^.leg;
end;
if p1=nil then test:=false
else
begin
atribuie(d,p1^.inf);
if p2<> nil then p2^.leg:=p1^.leg
else cap:=cap^.leg;
dispose(p1);
end;
end;
end;
end;

Problema 6. Scrieţi o procedură Pascal pentru eliminarea celulei care precede


primei componente al cărei câmp de informaţie îndeplineşte o condiţie dată, în cadrul
unei liste lineare.
Pentru funcţia condiţie vezi problema 5.

a) Lista reprezentată prin structură statică (masiv unidimensional)


procedure elimina_inainte1(var l:lst;
var n:word;d_cmp:tip_informatie;
var d:tip_informatie; var test:boolean);
var i,j:word;
begin
test:=true;
if n=0 then test:=false
else
begin
i:=1;
while(i<=n)and (not conditie(l[i],d_cmp)) do i:=i+1;
if (i>1) and (i<=n) then
begin
atribuie(d,l[i-1]);
for j:=i-1 to n-1 do atribuie(l[j],l[j+1]);
n:=n-1;
end
else test:=false;
end;
end;
b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure elimina_inainte2(var cap:lista; d_cmp:tip_informatie;


var d:tip_informatie;var test:boolean);
var p1,p2:ptlista;
begin
test:=true;
if (cap=nil) or (conditie(cap^.inf,d_cmp)) then
test:=false
else begin

16
Implementarea structurii de listă în limbajul Pascal

p2:=nil; p1:=cap;
while (p1^.leg<>nil) and (not conditie(p1^.leg^.inf,d_cmp)
do
begin
p2:=p1;
p1:=p1^.leg;
end;
if p1^.leg=nil then
test:=false
else if p1=cap then
begin
atribuie(cap^.inf,d);
cap:=cap^.leg;
dispose(p1);
end
else begin
p2^.leg:=p1^.leg;
atribuie(p1^.inf,d);
dispose(p1);
end;
end;
end;

Problema 7. Scrieţi un subprogram Pascal pentru eliminarea celulei care


succede primei componente al cărei câmp de informaţie îndeplineşte o condiţie dată,
în cadrul unei liste lineare.
Pentru funcţia condiţie vezi problema 5.

a) Lista reprezentată prin structură statică (masiv unidimensional)

procedure elimina_dupa1(var l:lst;


var n:word;d_cmp:tip_informatie;
var d:tip_informatie; var test:boolean);
var i,j:word;
begin
test:=true;
if n=0 then test:=false
else
begin
i:=1;
while(i<=n)and (not conditie(l[i],d_cmp)) do i:=i+1;
if (i<n) then
begin
atribuie(d,l[i+1]);
for j:=i+1 to n-1 do atribuie(l[j],l[j+1]);
n:=n-1;
end
else test:=false;
end;
end;

b) Lista reprezentată prin structură dinamică simplu înlănţuită

procedure elimina_dupa2(var cap:lista; d_cmp:tip_informatie;


var d:tip_informatie;var test:boolean);
var p,p1:ptlista;
begin
test:=true;

17
Programarea calculatoarelor. Aplicaţii

if cap=nil then
test:=false
else begin
p:=cap;
while (p<>nil) and (not conditie(p^.inf,d_cmp)) do
p:=p^.leg;
if (p=nil) or (p^.leg=nil) then
test:=false
else begin
p1:=p^.leg;
atribuie( d,p1^.inf);
p^.leg:=p1^.leg;
dispose(p1);
end;
end;
end;

Exerciţii

1. Să se elaboreze o procedură pentru crearea unei liste dinamice dublu


înlănţuite prin apelul repetat al procedurii inserare_la_inceput3.
2. Scrieţi o procedură pentru inserarea într-o listă dinamică dublu înlănţuită a
unei date, înaintea primei componente care îndeplineşte o condiţie formulată.
3. Realizaţi un subprogram pentru inserarea unei date într-o listă dinamică
dublu înlănţuită, după prima componentă care îndeplineşte condiţia formulată.
4. Să se elaboreze o procedură pentru eliminarea ultimei componente dintr-o
listă dublu înlănţuită.
5. Să se scrie o procedură pentru eliminarea dintr-o listă dublu înlănţuită a
primei componente care îndeplineşte o condiţie formulată.
6. Realizaţi o procedură pentru eliminarea dintr-o listă dublu înlănţuită a
componentei care precede primei celule care îndeplineşte o condiţie formulată.
7. Să se scrie o procedură pentru eliminarea dintr-o listă dublu înlănţuită a
componentei care urmează primei celule care îndeplineşte o condiţie formulată.
8. Scrieţi o procedură pentru inserarea într-o listă dinamică simplu înlănţuită
a unei date, înaintea ultimei componente care îndeplineşte o condiţie formulată.
9. Realizaţi un subprogram pentru inserarea într-o listă dinamică a unei date,
după cea de-a n-a componentă care îndeplineşte o condiţie formulată, pentru n dat.
10. Să se scrie o procedură pentru eliminarea dintr-o listă a ultimei
componente care îndeplineşte o condiţie formulată.
11. Realizaţi o procedură pentru eliminarea dintr-o listă dinamică a
componentei care precede cea de-a n-a celulă care îndeplineşte o condiţie formulată,
pentru n dat.
12. Să se scrie o procedură pentru eliminarea dintr-o listă dublu înlănţuită a
componentei care urmează ultimei celule care îndeplineşte o condiţie formulată.
13. Să se scrie o procedură care realizează concatenarea a două liste simplu
înlănţuite. Prin concatenare se înţelege secvenţa rezultată din componentele primei
liste urmate de componentele celei de-a doua.

18
Implementarea structurii de listă în limbajul Pascal

14. Fie A lista ale cărei componente sunt coeficienţii formei canonice a unui
polinom şi b un număr real dat. Să se calculeze valoarea polinomului în punctul b şi
lista B a coeficienţilor câtului polinomului dat prin X-b.

2.2. Liste circulare

Problema 1. Fie x1,…,xn cuvinte şi p ≥ 1 un număr natural dat. Să se scrie un


program pentru obţinerea secvenţei de cuvinte rezultată prin alegerea cu eliminare a
celui de-al p-lea cuvânt din secvenţa considerată. Numărătoarea începe cu x1 şi
alegerea cuvintelor este realizată prin parcurgerea secvenţială cu reluare de la
începutul listei de cuvinte rămase.

program aplicatie;
uses crt;
type
tip_informatie=string;
clista=^nod;
nod=record
inf:tip_informatie;
leg:clista;
end;
var
ultim:clista;
m:word;
procedure atribuie(var d:tip_informatie;s:tip_informatie);
begin
d:=s;
end;

procedure inserare_la_sfarsit(var
ultim:clista;d:tip_informatie;var test:boolean);
var
p:clista;
cap:clista;
begin
test:=true;
if MaxAvail<sizeof(nod) then test:=false
else
begin
new(p);
atribuie(p^.inf,d);
if ultim=nil then
begin
ultim:=p;
ultim^.leg:=ultim;
end
else
begin
cap:=ultim^.leg;
p^.leg:=cap;
ultim^.leg:=p;
ultim:=p;
end;

19
Programarea calculatoarelor. Aplicaţii

end;
end;
procedure creare_lista_circulara(var ultim:clista);
var
d:tip_informatie;
test:boolean;
begin
checkeof:=true;
ultim:=nil;
while not eof do
begin
readln(d);
inserare_la_sfarsit(ultim,d,test);
end;
reset(input);
end;
procedure elimina_p(var ultim:clista;m:word);
var
p,q:clista;
i:word;
begin
if ultim<>nil then
if m=1 then
while (ultim<>nil) do
begin
p:=ultim^.leg;
writeln(p^.inf);
if ultim=ultim^.leg then ultim:=nil;
ultim^.leg:=p^.leg;
dispose(p);
end
else
begin
p:=ultim^.leg;
while(p<>nil) do
if p=p^.leg then
begin
writeln(p^.inf);
dispose(p);
ultim:=nil;
p:=nil;
end
else
if p<>nil then
begin
for i:=1 to m-2 do p:=p^.leg;
q:=p^.leg;
p^.leg:=q^.leg;
writeln(q^.inf);
dispose(q);
p:=p^.leg;
end;
end
else writeln('Secventa este vida!');
end;

begin
clrscr;
writeln('Dati secventa de cuvinte:');
creare_lista_circulara(ultim);
write('Dati m=');readln(m);
elimina_p(ultim,m);
20
Implementarea structurii de listă în limbajul Pascal

readln;
end.

Exerciţii

1. Scrieţi o procedură pentru inserarea unei componente într-o listă circulară,


pe poziţia p dată.
2. Scrieţi o procedură pentru eliminarea dintr-o listă circulară a celei de-a p-a
componente; p dat.
3. Scrieţi o procedură pentru realizarea operaţiei de concatenare a două liste
circulare.
4. Presupunem că A şi B sunt două liste circulare nevide şi p1 indică adresa
ultimului nod din lista A, p2 indică adresa ultimului nod din B. Stabiliţi efectul
secvenţei de instrucţiuni:
t:=p1^.leg;
p1^.leg:=p2^.leg;
p2^.leg:=t;
5. Fie A o listă circulară nevidă şi p1, p2 adresele a două noduri diferite din
A. Stabiliţi efectul secvenţei de instrucţiuni:
t:=p1^.leg;
p1^.leg:=p2^.leg;
p2^.leg:=t;
6. Scrieţi un program pentru următorul joc cu doi parteneri. Se consideră o
secvenţă de numere întregi, nu neapărat distincte; o singură componentă a secvenţei
este egală cu 0. La momentul iniţial se consideră prima componentă a secvenţei.
Jucătorii efectuează alternativ câte o mutare conform următoarei reguli: dacă pe
poziţia curentă în secvenţă este un număr pozitiv n, atunci poziţia curentă este
deplasată cu n locaţii către dreapta (cu reluarea secvenţei date), iar dacă este un
număr negativ –n, poziţia curentă este deplasată cu n locaţii către stânga (cu reluarea
secvenţei date). Jocul continuă până când unul dintre jucători determină ca poziţie
curentă pe cea corespunzătoare componentei egale cu 0 şi este declarat câştigător sau
până când sunt efectuate nmax mutări. Dacă jocul se termină prin efectuarea de către
unul dintre jucători a ultimei dintre cele nmax mutări, atunci el câştigă dacă poziţia
curentă în acel moment este la dreapta poziţiei corespunzătoare componentei egale
cu 0, altfel este declarat câştigător celălalt jucător.

2.3. Aplicaţii ale structurilor stivă şi coadă

Problema 1. Evaluarea expresiilor aritmetice


Deoarece operatorii aritmetici binari au asociate niveluri de precedenţă
predefinite, este posibilă scrierea neparantezată a anumitor expresii aritmetice. De
21
Programarea calculatoarelor. Aplicaţii

exemplu, 5+3 × 7=26 deoarece operaţia de multiplicare are nivel de precedenţă


superior operaţiei de adunare. Dacă, însă, se doreşte ca operaţia de adunare să fie
efectuată înaintea celei de multiplicare, expresia trebuie scrisă (5+3) × 7, rezultatul
evaluării fiind 56. Pentru creşterea eficienţei algoritmilor de prelucrare a expresiilor
aritmetice, care depinde de prezenţa/absenţa parantezării, s-au căutat modalităţi de
reprezentare neambiguă a expresiilor fără utilizarea parantezelor. Două astfel de
modalităţi sunt date de reprezentările postfix (forma poloneză inversă) şi prefix
(forma poloneză directă), introduse de matematicianul polonez Lukasiewicz.
În reprezentarea prefix, fiecare subexpresie a expresiei este redată prin:
simbol_operaţie, operand1, operand2, iar în reprezentarea postfix, fiecare subexpresie
este redată prin: operand1, operand2, simbol_operaţie. Convenţional, scrierea uzuală
(cu paranteze) este numită reprezentarea infix.

Exemplu
2.1. Pentru expresia aritmetică reprezentată infix astfel:
((a+b)*c)/((a+c)*(b+d)), reprezentările prefix şi postfix corespunzătoare sunt:
prefix: /*+abc*+ac+bd
postfix: ab+c*ac+bd+*/

Reprezentarea postfix oferă facilităţi deosebite în evaluarea expresiilor şi, ca


atare, este preferată ca mod de reprezentare, fiind referită ca notaţie poloneză.
Deoarece memoria calculatorului este organizată ca stivă, evaluarea unei expresii
reprezentate postfix revine la prelucrarea expresiei de la stânga la dreapta, simbol cu
simbol, astfel:
-dacă simbolul curent este o dată de tip operand, atunci el este depus în
stivă;
-altfel, sunt extraşi cu eliminare primii doi operanzi din stivă, este efectuată
operaţia corespunzătoare simbolului respectiv şi rezultatul (dată de tip
operand) este depus în stivă.
Expresia este corectă dacă este posibilă aplicarea schemei de calcul descrise
pentru toate simbolurile expresiei, situaţie în care, după ce ultimul simbol al expresiei
a fost prelucrat, stiva conţine un singur element care reprezintă valoarea expresiei.

Exemple

2.2. Presupunem că valorile variabilelor sunt: a=2, b=1, c=1, d=0. Evaluarea
expresiei ab+c*ac+bd+*/ este descrisă prin:

Secvenţa simbolurilor Simbol Stiva


neprelucrate curent
ab+c*ac+bd+*/ Ø
b+c*ac+bd+*/ a Ø
+c*ac+bd+*/ b 2
c*ac+bd+*/ + 1,2

22
Implementarea structurii de listă în limbajul Pascal

*ac+bd+*/ c 3
ac+bd+*/ * 1,3
c+bd+*/ a 3
+bd+*/ c 2,3
bd+*/ + 1,2,3
d+*/ b 3,3
+*/ d 1,3,3
*/ + 0,1,3,3
/ * 1,3,3
/ 3,3
1

2.3. Presupunem că valorile variabilelor sunt: a=2, b=1, c=1, d=0. Evaluarea
expresiei ab+c*+ac+bd+*/ este descrisă prin:

Secvenţa simbolurilor Simbol Stiva


neprelucrate curent
ab+c*ac+bd+*/ Ø
b+c*’ac+bd+*/ a Ø
+c*+ac+bd+*/ b 2
c*+ac+bd+*/ + 1,2
*+ac+bd+*/ c 3
+ac+bd+*/ * 1,3
ac+bd+*/ + 3
Eroare (stiva conţine un singur operand)

2.4. Presupunem că valorile variabilelor sunt: a=2, b=1, c=1, d=1. Evaluarea
expresiei ab+c*dac+bd+*/ este descrisă prin:

Secvenţa simbolurilor Simbol Stiva


neprelucrate curent
ab+c*dac+bd+*/ Ø
b+c*dac+bd+*/ a Ø
+c*dac+bd+*/ b 2
c*dac+bd+*/ + 1,2
*dac+bd+*/ c 3
dac+bd+*/ * 1,3
ac+bd+*/ d 1,3
c+bd+*/ a 2,1,3
+bd+*/ c 1,2,1,3
bd+*/ + 3,1,3
d+*/ b 1,3,1,3
+*/ d 1,1,3,1,3

23
Programarea calculatoarelor. Aplicaţii

*/ + 2,3,1,3
/ * 6,1,3
/ 6,3
6,3
Eroare: stiva conţine 2 elemente şi expresia a fost
analizată în întregime

Procedura eval(expresie,n,valoare,test) realizează implementarea calculului


descris anterior, unde:
- expresie este lista simbolurilor reprezentării postfix a expresiei aritmetice
de evaluat;
- n este numărul de simboluri din reprezentarea postfix;
- valoare este rezultatul evaluării expresiei, dacă scrierea este corectă;
- test este parametrul care controlează corectitudinea expresiei şi
posibilitatea efectuării operaţiilor indicate. La terminarea calculului:
test=1, dacă expresia este corectă şi evaluarea este posibilă; test=2, dacă
expresia este incorect scrisă; test=3, dacă evaluarea nu este posibilă (este
iniţiată împărţirea la 0); test=4, dacă este semnalată depăşire de stivă la
inserarea unui simbol de tip operand.

Procedura locală citeste_si_construieste_tabela(expresie,n,tabela) iniţiază


citirea expresiei a cărei evaluare este dorită, precum şi valoarea asociată fiecărui
simbol corespunzător unui operand, reprezentat de câte o literă format mic a
alfabetului latin. Pentru duplicatele aceluiaşi operand în expresie, valoarea asociată
se citeşte o singură dată, la prima apariţie a lui în cadrul expresiei postfix. Funcţia
operatie(a,b,op) returnează valoarea subexpresiei a op b. Variabila locală s din
procedura eval reprezintă stiva (reprezentată static) în care sunt memorate valorile
calculate şi valorile asociate simbolurilor ce desemnează operanzii.

const max=500;
type stiva=array[1..max]of real;
tab=array['a'..'z']of real;
var e:string; n:word;v:real;t:byte;i:word;p:word;
procedure push(var s:stiva;var n:word;x:real;var t:boolean);
var i:word;
begin
t:=true;
if (n=max) then t:=true
else begin
for i:=n downto 1 do s[i+1]:=s[i];
s[1]:=x;n:=n+1;
end;
end;
procedure pop(var x:real; var s:stiva;var n:word;var
t:boolean);
var i:word;
begin
t:=true;

24
Implementarea structurii de listă în limbajul Pascal

if n=0 then t:=false


else begin
x:=s[1];
for i:=1 to n-1 do s[i]:=s[i+1];
n:=n-1;
end;
end;
procedure citeste_si_construieste_tabela(var
expresie:string;var n:word;var tabela:tab);
var
c:char;i:word;
citit:array['a'..'z']of boolean;
begin
for c:='a'to'z' do
begin
tabela[c]:=0;
citit[c]:=false;
end;
readln(expresie);
n:=length(expresie);
for i:=1 to n do
if (expresie[i]in['a'..'z'])and
(not citit[expresie[i]]) then
begin
write('Valoarea variabilei ', expresie[i],'
este:');
readln(tabela[expresie[i]]);
citit[expresie[i]]:=true;
end;
end;
procedure eval(var expresie:string; var n:word; var
valoare:real; var test:byte);
var s:stiva;
i:word;
t:boolean;
a,b:real;
tabela:tab;
x:real;

function operatie(a,b:real;op:char):real;
begin
case op of
'+': operatie:=a+b;
'-':operatie:=a-b;
'/':operatie:=a/b;
'*':operatie:=a*b;
end;
end;

begin
citeste_si_construieste_tabela(expresie,n,tabela);
test:=1;
i:=1;
p:=0;
while(i<=n)and(test=1) do
begin
if (expresie[i] in ['+','-','*','/'])then
begin
pop(b,s,p,t);
if(t) then
25
Programarea calculatoarelor. Aplicaţii

begin
pop(a,s,p,t);
if(t) then
if(expresie[i]='/')and(b=0) then
test:=3
else
begin
push(s,p,operatie(a,b,expresie[i]),t);
if not t then
test:=4;
end
else test:=2;
end
else test:=2
end
else begin
push(s,p,tabela[expresie[i]],t);
if not t then
test:=4;
end;
i:=i+1;
end;
valoare:=s[1];
if (p<>1) and (test=1) then test:=2;
end;
begin
eval(e,n,v,t);
case t of
1: writeln(v:10:3);
2:writeln('Expresie incorecta');
3:writeln('Impartire la 0');
4:writeln('Depasire de stiva');
end;
readln;
end.

Problema 2. Determinarea reprezentării postfix a unei expresii aritmetice


Aşa cum a rezultat din aplicaţia precedentă, este uşor de implementat un
algoritm pentru evaluarea unei expresii aritmetice dată în reprezentarea postfix.
Scrierea postfixată, însă, nu este curent utilizată şi, ca atare, devine necesară găsirea
unei metode care să calculeze reprezentarea postfix corespunzătoare unei expresii
parantezate infix.
Traducerea unei expresii din reprezentarea infix în cea postfix poate fi realizată
pe baza a două structuri: o stivă şi o matrice de precedenţă. Matricea de precedenţă
conţine informaţiile referitoare la acţiunile ce trebuie iniţiate, definite în funcţie de
simbolul curent analizat din cadrul reprezentării şi simbolul din vârful stivei. Tipul
simbolului curent analizat din reprezentare este utilizat pentru selectarea unei coloane
a matricei iar tipul simbolului din vârful stivei este utilizat pentru alegerea unei linii a
matricei.
Pentru simplificare va fi introdus un simbol special “#”, numit santinelă (end
marker). Se presupune că simbolurile unei reprezentări sunt: operanzi (desemnaţi
prin câte o singură literă, format mic), paranteze şi operatori (‘+’,’-‘,’*’,’/’).
Semnificaţia fiecărui simbol este stabilită de funcţia Pascal articol(c):tip_simbol .

26
Implementarea structurii de listă în limbajul Pascal

type tip_simbol = (terminare, operand, adunare_scadere,


inmultire_impartire, paranteza_stanga, paranteza_dreapta);
function articol(c:char):tip_simbol;
begin
articol:=operand;
case c of
‘#’: articol:=terminare;
‘+’,’-‘:articol:=adunare_scadere;
‘*’,’/’:articol:=inmultire_impartire;
‘(‘:articol:=paranteza_stanga;
‘)’:articol:=paranteza_dreapta;
end;
end;

Atât reprezentarea infix a expresiei, cât şi echivalentul ei postfix sunt de tip


string. Simbolurile reprezentării infix sunt analizate secvenţial de la stânga la dreapta,
iar simbolurile reprezentării postfix sunt determinate în funcţie de simbolul curent
analizat, stiva şi matricea de precedenţă construită. Stiva este utilizată pentru
reţinerea simbolurilor care desemnează operatori şi paranteze; iniţial unicul simbol
din stivă este ‘#’. Dacă simbolul curent analizat este un operand, atunci el se copiază
la dreapta secvenţei generate. Dacă simbolul curent analizat din secvenţa dată este un
operator sau o paranteză stângă, atunci acest simbol va fi introdus în stivă şi va fi
iniţiată acţiunea de continuare. Dacă simbolul curent analizat este paranteză dreaptă,
atunci se copiază, cu eliminare din stivă, în secvenţa calculată toate simbolurile
operator până la întâlnirea primei paranteze stângi, iar paranteza stângă este eliminată
din stivă.
Detectarea cazurilor de eroare a parantezării în scrierea infix determină
acţiunea eroare, care, de exemplu, setează un parametru pe valoarea true.
Metoda considerată pentru calculul reprezentării postfix revine la inspectarea
simbol cu simbol a reprezentării iniţiale şi generarea simbolurilor reprezentării
postfix pe baza informaţiilor memorate în stivă. Metoda poate fi ilustrată utilizând
următoarele acţiuni :
- salvează, determină adăugarea unui simbol la dreapta în secvenţa
calculată;
- continuă, corespunde operaţiei de adăugare a simbolului curent în stivă,
urmată de trecerea la următorul simbol din secvenţa dată;
- pop_salvează, determină copierea cu eliminare a vârfului stivei la dreapta
secvenţei generate;
- pop1, determină eliminarea vârfului stivei şi trecerea la următorul simbol
din secvenţa infix;
- terminare, este iniţiată în cazul în care reprezentarea infix dată este corectă
şi calculul se încheie cu succes;
- eroare, este iniţiată în cazul în care se decide că reprezentarea infix dată
este incorectă din punct de vedere al parantezării.

Exemple

27
Programarea calculatoarelor. Aplicaţii

2.5. Evoluţia algoritmului pentru determinarea reprezentării postfix a


expresiei (a+b*c)/(d-e) este prezentată în tabela care urmează. Prima coloană a
tabelei indică poziţia simbolului curent analizat în expresia dată.

Indice Acţiune Stivă Secvenţa generată


simbol
0 iniţializează #
1 continuă (#
2 salvează (# a
3 continuă +(# a
4 salvează +(# ab
5 continuă *+(# ab
6 salvează *+(# abc
7 pop_salvează +(# abc*
7 pop_salvează (# abc*+
7 pop1 # abc*+
8 continuă /# abc*+
9 continuă (/# abc*+
10 salvează (/# abc*+d
11 continuă -(/# abc*+d
12 salvează -(/# abc*+de
13 pop_salvează (/# abc*+de-
13 pop1 /# abc*+de-
13 pop_salvează # abc*+de-/
13 terminare

2.6. Evoluţia algoritmului pentru determinarea reprezentării postfix a


expresiei (a+b*c))/(d-e) este prezentată în tabela care urmează.

Indice Acţiune Stivă Secvenţa generată


simbol
0 iniţializează #
1 continuă (#
2 salvează (# a
3 continuă +(# a
4 salvează +(# ab
5 continuă *+(# ab
6 salvează *+(# abc
7 pop_salvează +(# abc*
7 pop_salvează (# abc*+
7 pop1 # abc*+
8 pop_salvează # abc*+
8 eroare # abc*+

28
Implementarea structurii de listă în limbajul Pascal

În continuare este prezentat programul Pascal care implementează algoritmul


pentru calculul reprezentării postfix corespunzătoare unei expresii aritmetice
parantezate.

const max=500;
type stiva=array[1..max]of char;
tip_simbol=(gata,operand,adunare_scadere,inmultire_impartire,
paranteza_stanga,paranteza_dreapta);
actiune=(continua,salveaza,pop1,pop_salveaza,terminare,
eroare);
matrice_precedenta=array[tip_simbol,tip_simbol] of
actiune;
var infix,postfix:string; n:word;t:boolean;

procedure push(var s:stiva;var n:word;x:char;var t:boolean);


var i:word;
begin
t:=true;
if (n=max) then
t:=true
else begin
for i:=n downto 1 do s[i+1]:=s[i];
s[1]:=x;n:=n+1;
end;
end;
procedure pop(var x:char; var s:stiva;var n:word;var
t:boolean);
var i:word;
begin
t:=true;
if s[1]='#' then
t:=false
else begin
x:=s[1];
for i:=1 to n-1 do
s[i]:=s[i+1];
n:=n-1;
end;
end;
function articol(c:char):tip_simbol;
begin
articol:=operand;
case c of
'#':articol:=gata;
'+','-':articol:=adunare_scadere;
'*','/':articol:=inmultire_impartire;
'(':articol:=paranteza_stanga;
')':articol:=paranteza_dreapta;
end;
end;
procedure construieste_precedenta(var
precedenta:matrice_precedenta);
begin
precedenta[gata,gata]:=terminare;

29
Programarea calculatoarelor. Aplicaţii

precedenta[gata,operand]:=continua;
precedenta[gata,adunare_scadere]:=salveaza;
precedenta[gata,inmultire_impartire]:=salveaza;
precedenta[gata,paranteza_stanga]:=salveaza;
precedenta[gata,paranteza_dreapta]:=eroare;
precedenta[operand,gata]:=eroare;
precedenta[operand,operand]:=eroare;
precedenta[operand,adunare_scadere]:=eroare;
precedenta[operand,inmultire_impartire]:=eroare;
precedenta[operand,paranteza_stanga]:=eroare;
precedenta[operand,paranteza_dreapta]:=eroare;
precedenta[adunare_scadere,gata]:=pop_salveaza;
precedenta[adunare_scadere,operand]:=continua;
precedenta[adunare_scadere,adunare_scadere]:=pop_salveaza;
precedenta[adunare_scadere,inmultire_impartire]:=salveaza;
precedenta[adunare_scadere,paranteza_stanga]:=salveaza;
precedenta[adunare_scadere,paranteza_dreapta]:=pop_salveaza;
precedenta[inmultire_impartire,gata]:=pop_salveaza;
precedenta[inmultire_impartire,operand]:=continua;
precedenta[inmultire_impartire,adunare_scadere]:=pop_salveaza;
precedenta[inmultire_impartire,inmultire_impartire]:=pop_salvea
za;
precedenta[inmultire_impartire,paranteza_stanga]:=salveaza;
precedenta[inmultire_impartire,paranteza_dreapta]:=pop_salveaza
;
precedenta[paranteza_stanga,gata]:=eroare;
precedenta[paranteza_stanga,operand]:=continua;
precedenta[paranteza_stanga,adunare_scadere]:=salveaza;
precedenta[paranteza_stanga,inmultire_impartire]:=salveaza;
precedenta[paranteza_stanga,paranteza_stanga]:=salveaza;
precedenta[paranteza_stanga,paranteza_dreapta]:=pop1;
precedenta[paranteza_dreapta,gata]:=eroare;
precedenta[paranteza_dreapta,operand]:=eroare;
precedenta[paranteza_dreapta,adunare_scadere]:=eroare;
precedenta[paranteza_dreapta,inmultire_impartire]:=eroare;
precedenta[paranteza_dreapta,paranteza_stanga]:=eroare;
precedenta[paranteza_dreapta,paranteza_dreapta]:=eroare;
end;
procedure infix_postfix(infix:string; n:word; var
postfix:string;var corect:boolean);
var
p,index_infix,index_postfix:word;
lin,col:tip_simbol;
s:stiva;
c:char;
precedenta:matrice_precedenta;
t,stop,iesire:boolean;
sir:string;
begin
construieste_precedenta(precedenta);
p:=0;
postfix:='';
push(s,p,'#',t);
index_postfix:=1;
index_infix:=1;
corect:=true;iesire:=false;
while(index_infix<=n) and not iesire do
begin
stop:=false;
col:=articol(infix[index_infix]);
while not stop do
begin
30
Implementarea structurii de listă în limbajul Pascal

lin:=articol(s[1]);
case precedenta[lin,col] of
continua: begin
postfix[0]:=chr(ord(postfix[0])+1);
postfix[index_postfix]:=infix[index_infix];
inc(index_postfix);
stop:=true;
end;
salveaza: begin
push(s,p,infix[index_infix],t);
stop:=true;
end;
pop_salveaza: begin
postfix[0]:=chr(ord(postfix[0])+1);
pop(postfix[index_postfix],s,p,t);
index_postfix:=index_postfix+1;
end;
pop1: begin
pop(c,s,p,t);
if t then stop:=true
else begin
corect:=false;
iesire:=true;
stop:=true;
end;
end;
terminare: begin
stop:=true;
end;
eroare: begin
stop:=true;
corect:=false;
iesire:=true;
end;
end;
end;
inc(index_infix);
end;
end;
begin
writeln('Expresia infix:');readln(infix);
n:=length(infix);
infix_postfix(infix,n,postfix,t);
if t then
writeln('Forma postfix este: ', postfix)
else writeln('Expresie incorect parantezata!');
readln;
end.

Problema 3
Se consideră următorul joc cu doi parteneri. Presupunem că sunt date două
pachete de k şi respectiv n cartonaşe, pe fiecare cartonaş fiind înscris unul dintre
simbolurile ‘@’, ‘$’. Jucătorii întorc alternativ câte un cartonaş din pachetul care
iniţial a avut n cartonaşe, pe care îl compară cu cartonaşul aflat la începutul celui de-
al doilea pachet. Dacă simbolurile înscrise pe cele două cartonaşe coincid, atunci sunt
eliminate din cel de-al doilea pachet toate cartonaşele, începând cu primul, până la
primul cartonaş pe care este înscris celălalt simbol. Dacă simbolurile înscrise pe cele

31
Programarea calculatoarelor. Aplicaţii

două cartonaşe sunt diferite, atunci cartonaşul întors se adaugă la sfârşitul pachetului.
Dacă la o mutare sunt eliminate toate cartonaşele din pachet, atunci jucătorul care a
efectuat acea mutare este declarat câştigător şi jocul se încheie. Dacă după
întoarcerea ultimului cartonaş de către unul dintre jucători mai sunt cartonaşe încă
neeliminate, atunci celălalt jucător este declarat câştigător şi jocul se încheie.
Pachetul de n cartonaşe care sunt întoarse succesiv de către jucători este
generat aleator şi reprezentat în program în variabila p. Cel de-al doilea pachet este,
de asemenea, generat aleator şi este reprezentat în program prin lista coadă
determinată de adresa ultim.

În continuare este prezentat programul pentru rezolvarea acestei probleme.


Procedura atribuie realizează atribuirea unei variabile de tip tip_informaţie (cu două
valori, 0 sau 1). Procedura inserare_coada implementează algoritmul de inserare a
unui nou nod într-o structură de coadă. Procedura elimina_coada realizează
eliminarea unui nod dintr-o coadă. Procedura afis_coada realizează afişarea fiecărui
element al structurii de coadă considerate.
Prin apelul procedurilor genereaza şi gen sunt calculate structurile de
pachet., respectiv coadă iniţială. Generarea este realizată aleator cu distribuţie
uniformă, în intervalul [0,1]. Prin procedura joc este ralizată simularea desfăşurării
unui joc, conform regulilor mai sus menţionate.

uses crt;
type
tip_informatie=0..1;
lista=^nod;
nod=record
inf:tip_informatie;
leg:lista;
end;
pachet=array[1..256] of tip_informatie;
var
n,k,c:byte;
t:text;
procedure atribuie(var d:tip_informatie;s:tip_informatie);
begin
d:=s;
end;
procedure inserare_coada(var ultim:lista;d:tip_informatie;var
test:boolean);
var p:lista;
begin
test:=true;
if MaxAvail<sizeof(nod) then test:=false
else
begin
new(p);
atribuie(p^.inf,d);
if ultim=nil then
begin
ultim:=p;
ultim^.leg:=ultim;
end

32
Implementarea structurii de listă în limbajul Pascal

else
begin
p^.leg:=ultim^.leg;
ultim^.leg:=p;
ultim:=p;
end;
end;
end;

procedure elimina_coada(var ultim:lista;var


d:tip_informatie;var test:boolean);
var
prim:lista;
begin
test:=true;
if ultim=nil then test:=false
else
begin
prim:=ultim^.leg;
if prim=ultim then
ultim:=nil
else
ultim^.leg:=prim^.leg;
dispose(prim);
end;
end;
procedure genereaza(var ultim:lista;k:byte);
var
d:tip_informatie;
test:boolean;
i:byte;
begin
writeln(t,'Coada initiala:');
ultim:=nil;
randomize;
for i:=1 to k do
begin
d:=ord(random(1000)>500);
inserare_coada(ultim,d,test);
if d<0.5 then write(t,'@ ')
else write(t,'$ ');
end;
writeln(t);
end;
procedure afis_coada(ultim:lista);
var p:lista;
begin
writeln(t,'Coada:');
if ultim<>nil then
begin
p:=ultim^.leg;
repeat
if p^.inf=0 then write(t,'@ ')
else write(t,'$ ');
p:=p^.leg;
until p=ultim^.leg;
end;
writeln(t);
end;
procedure gen(var p:pachet;n:byte);
var
33
Programarea calculatoarelor. Aplicaţii

i:byte;
begin
randomize;
writeln(t,'Pachetul initial:');
for i:=1 to n do
begin
p[i]:=ord(random(100)>50);
if p[i]=0 then write(t,'@ ')
else write(t,'$ ');
end;
writeln(t);
end;
procedure joc(n,k:byte;var castigator:byte);
var
ultim,prim:lista;
i,j:byte;
p:pachet;
d:tip_informatie;
test:boolean;
begin
gen(p,n);
genereaza(ultim,k);
i:=1;
while (i<=n) and (ultim<>nil) do
begin
writeln(t,'Muta jucatorul ',2-i mod 2);
writeln(t);
writeln(t,'Rezultatul:');
prim:=ultim^.leg;
if p[i]<>prim^.inf then
inserare_coada(ultim,p[i],test)
else
while (ultim<>nil)and(p[i]=prim^.inf) do
begin
elimina_coada(ultim,d,test);
if ultim<>nil then
prim:=ultim^.leg
else castigator:=2-i mod 2;
end;
writeln(t,'Pachetul ramas:');
for j:=i+1 to n do
if p[j]=0 then
write(t,'@ ')
else write(t,'$ ');
writeln(t);
afis_coada(ultim);
writeln(t);
i:=i+1;
end;
if ultim<>nil then
castigator:=2-(n+1) mod 2;
end;
begin
clrscr;
assign(t,'joc.txt');rewrite(t);
write('Numarul de cartonase din pachet:');readln(n);
write('Numarul de cartonase din coada initiala:');readln(k);
writeln(t,'Numarul de cartonase din pachet',n);
writeln(t,'Numarul de cartonase din coada initiala:',k);
joc(n,k,c);
writeln(t,'Castigatorul este jucatorul:',c);
34
Implementarea structurii de listă în limbajul Pascal

close(t);
end.

În continuare este prezentat n exemplu de execuţie a programului przentat


mai sus.

Numarul de cartonase din pachet25


Numarul de cartonase din coada initiala:23
Pachetul initial:
@ $ @ $ @ @ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada initiala:
$ $ $ @ $ @ $ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
$ @ $ @ @ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ @ $ @ $ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
@ $ @ @ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ $ @ $ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
$ @ @ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ @ $ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
@ @ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ $ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
@ @ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @
Muta jucatorul 2
Rezultatul:

35
Programarea calculatoarelor. Aplicaţii

Pachetul ramas:
@ $ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @ @
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
$ $ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ $ @ @ @ $ $ $ @ $ $ $ @ $ $ @ @ @
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ @ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ @ @ $ $ $ @ $ $ $ @ $ $ @ @ @
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
@ $ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ @ @ $ $ $ @ $ $ $ @ $ $ @ @ @ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ $ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ @ $ $ $ @ $ $ @ @ @ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
$ $ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ $ $ $ @ $ $ @ @ @ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ @ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ $ $ $ @ $ $ @ @ @ $ $
Muta jucatorul 1
Rezultatul:

36
Implementarea structurii de listă în limbajul Pascal

Pachetul ramas:
@ $ @ $ $ $ @ $ @ @ @ @
Coada:
@ $ $ $ @ $ $ @ @ @ $ $ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ @ $ $ $ @ $ @ @ @ @
Coada:
$ $ $ @ $ $ @ @ @ $ $ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
@ $ $ $ @ $ @ @ @ @
Coada:
@ $ $ @ @ @ $ $ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ $ $ @ $ @ @ @ @
Coada:
$ $ @ @ @ $ $ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
$ $ @ $ @ @ @ @
Coada:
@ @ @ $ $ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:
$ @ $ @ @ @ @
Coada:
@ @ @ $ $ $ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
@ $ @ @ @ @
Coada:
@ @ @ $ $ $ $ $
Muta jucatorul 2
Rezultatul:
Pachetul ramas:

37
Programarea calculatoarelor. Aplicaţii

$ @ @ @ @
Coada:
$ $ $ $ $
Muta jucatorul 1
Rezultatul:
Pachetul ramas:
@ @ @ @
Coada:
Castigatorul este jucatorul:1

Exerciţii

1. Să se realizeze programul pentru evaluarea unei expresii aritmetice


oarecare utilizând o structură de stivă dinamică.
2. Să se realizeze programul pentru operaţiile de inserare şi eliminare pentru
o listă coadă reprezentată printr-o structură dinamică lineară.
3. Aplicaţi algoritmul pentru obţinerea reprezentării postfix a expresiei (a-b-
c)/d+e*(f-g*(h-i))*j#.
4. Aplicaţi algoritmul pentru evaluarea reprezentării postfix corespunzătoare
expresiei (a-b-c)/d+e*(f-g*(h-i))*j, unde a=7, b=h=3, c=d=2, e=1, f=i=5, g=j=2.
5. Propuneţi un algoritm pentru obţinerea reprezentării infix corespunzătoare
unei reprezentări postfix date.
6. Propuneţi un algoritm pentru obţinerea reprezentării prefix
corespunzătoare unei reprezentări infix date.
7. Propuneţi un algoritm pentru obţinerea reprezentării infix corespunzătoare
unei reprezentări prefix date.
8. Propuneţi un algoritm pentru obţinerea reprezentării prefix
corespunzătoare unei reprezentări postfix date.
9. Propuneţi un algoritm pentru obţinerea reprezentării postfix
corespunzătoare unei reprezentări prefix date.
10. Scrieţi un algoritm pentru extragerea dintr-o stivă a celui de-al n-lea
element.
11. Scrieţi un algoritm pentru extragerea dintr-o coadă a celui de-al n-lea
element.
12. Scrieţi un algoritm pentru inserarea într-o stivă a unei noi componente
pe poziţia n.
13. Scrieţi un algoritm pentru inserarea într-o coadă a unei noi componente
pe poziţia n.
14. Fie S1, S2 două stive. Scrieţi un program care să construiască lista L
rezultată prin concatenarea stivelor S1 şi S2.

38
3. GRAFURI. IMPLEMENTĂRI ÎN
LIMBAJUL PASCAL

Problema 1. Să se genereze reprezentarea unui graf dat prin listă de liste şi


să se vizualizeze structura prin parcurgere.

uses crt;
type
{lista vecinilor}
ptnod1=^nod1;
nod1=record
vecin:byte;
leg1:ptnod1;
end;

{lista L_nod, a nodurilor grafului}


ptlnod=^lnod;
lnod=record
nod:byte;
ptvecini:ptnod1;
leg:ptlnod;
end;

var
prim,actual,ultim:ptlnod;
vp,va,vu:ptnod1;
inf,n,i,j,m:byte;
begin
clrscr;
write('Numarul de noduri:');
readln(n);
prim:=nil; ultim:=nil;
{crearea listei L_nod}
for i:=1 to n do
begin
new(actual);
actual^.nod:=i;
actual^.leg:=nil;
{crearea listei vecinilor}
write('Numarul de vecini ai nodului ',i,':');
readln(m);
vp:=nil;va:=nil;

39
Programarea calculatoarelor. Aplicaţii

for j:=1 to m do
begin
new(va);
write('Vecinul ',j,':');
readln(inf);
va^.vecin:=inf;
va^.leg1:=nil;
if vp=nil then
begin
vp:=va;vu:=va;
end
else
begin
vu^.leg1:=va;vu:=va;
end;
end;
actual^.ptvecini:=vp;
if prim=nil then
begin
prim:=actual;
ultim:=actual;
end
else
begin
ultim^.leg:=actual;
ultim:=actual;
end;
end;
{scrierea grafului nod-vecin}
writeln;
actual:=prim;
while actual<>nil do
begin
write('Nodul ',actual^.nod,' are vecinii:');
vp:=actual^.ptvecini;
while vp<>nil do
begin
write(vp^.vecin,' ');
vp:=vp^.leg1;
end;
writeln;
actual:=actual^.leg;
end;
readln;
end.

Problema 2. Scrieţi un program Pascal pentru implementarea celei de-a doua


variante de parcurgere DF aplicată unui graf G=(V,E), V = n (Vezi cartea
Programarea calculatoarelor. Tehnica programării în limbajul Pascal).

Structurile de date utilizate pentru rezolvarea problemei sunt:


• o structură de tip stivă, S, reprezentată printr-o listă dinamică simplu
înlănţuită.
• un vector c cu n componente, în care:
1, dacă i a fost vizitat
ci = 
0, altfel
40
Grafuri. Implementări în limbajul Pascal

Componentele vectorului c vor fi iniţializate cu valoarea 0.


• o funcţie urm(i) care determină primul dintre vecinii vârfului argument incă
nevizitat. În momentul vizitării unui vârf, operaţie însoţită de afişarea vârfului
respectiv, componenta corespunzătoare lui din vectorul c este modificată (devine
egală cu 1).
Vârfurile grafului sunt numerotate de la 1 la n, vârful iniţial este vârful 1.
Graful este reprezentat prin matricea de adiacenţă. Accesul la stiva S este realizat
prin intermediul procedurilor push şi pop pentru introducerea, respectiv extragerea
unui element.

uses crt;
type
ptstiva=^stiva;
stiva=record
inf:byte;
leg:ptstiva;
end;
var
prim:ptstiva;
c:array[1..20] of byte;
a:array[1..20,1..20] of byte;
i,j,k,n:byte;
gata:boolean;
procedure push(var p:ptstiva;i:byte);
var a:ptstiva;
begin
new(a);
a^.inf:=i;
a^.leg:=p;
p:=a;
end;
procedure pop(var p:ptstiva;var i:byte);
var a:ptstiva;
begin
if p<>nil then
begin
i:=p^.inf;
a:=p;
p:=p^.leg;
dispose(a);
end;
end;
function urm(i:byte):integer;
var k:byte;
gasit:boolean;
begin
k:=1;
gasit:=false;
while(k<=n)and not gasit do
if (a[i,k]=1) and (c[k]=0)then
begin
gasit:=true; urm:=k;
end
else inc(k);

41
Programarea calculatoarelor. Aplicaţii

if not gasit then urm:=0;


end;
begin {program principal}
clrscr;
write('Numarul de varfuri:');
readln(n);
writeln('Matricea de adiacenta');
for i:=1 to n do
for j:=1 to n do
begin
write('a[',i,',',j,']=');
readln(a[i,j]);
end;
for i:=2 to n do
c[i]:=0;
readln;
clrscr;
writeln('Incepem parcurgerea de la nodul 1');
c[1]:=1;
prim:=nil;
write(1,' ');
i:=1;
push(prim,i);
gata:=false;
repeat
k:=urm(i);
if k=0 then
if prim=nil then
gata:=true
else pop(prim,i)
else begin
write(k,' ');
c[k]:=1;
push(prim,k);
i:=k;
end;
until gata;
readln;
end.

Problema 3. Scrieţi programul Pascal pentru determinarea componentei


conexe care conţine un vârf dat, într-un graf G=(V,E), V = n .

În continuare se presupune graful reprezentat în formă tabelară. Procedurile


utilizate efectuează următoarele operaţii:
- procedure copiaza(var v1,v2:vector;n:integer): copiază vectorul v1 de
dimensiune n în vectorul v2;
- procedure adauga(var v:vector;var n:integer;el:integer): extinde vectorul cu n
componente v prin adaugarea elementului el ca a n+1-a componentă dacă
valoarea el nu se regăseşte printre componentele lui v;
- procedure mcopiaza(var v1,v2:mat;n:integer): copiază matricea v1 cu n linii şi 2
coloane în matricea v2 (perechile de componente corespunzătoare fiecărei linii a
matricei v1 reprezintă muchii ale grafului);

42
Grafuri. Implementări în limbajul Pascal

- procedure madauga(var v:mat;var n:integer;el1,el2:integer): extinde matricea v


prin adaugarea elementului liniei suplimentare (el1, el2) reprezentând o muchie a
grafului dacă aceasta nu este deja reprezentată în v;
Variabilele globale folosite au următoarea semnificaţie:
- n,m: numărul vârfurilor, respectiv al muchiilor grafului;
- v0,v : la fiecare iteraţie, conţin componentele mulţimilor Vi-1 şi respectiv Vi;
- e0,e: la fiecare iteraţie, conţin componentele mulţimilor Ei-1 şi respectiv Ei;
- dv,dv0: dimensiunile vectorilor v, respectiv v0;
- de,de0: numărul liniilor matricelor e, respectiv e0.

uses crt;
type
vector=array[1..20]of integer;
mat=array[1..200,1..2] of integer;
var a,e,e0:mat;
v,v0:vector;
i,j,k,m,n,l:integer;
dv,dv0,de,de0:integer;
gata:boolean;
procedure copiaza(var v1,v2:vector;n:integer);
var i:byte;
begin
for i:=1 to n do
v2[i]:=v1[i];
end;
procedure adauga(var v:vector;var n:integer;el:integer);
var i:integer;
adaug:boolean;
begin
i:=1;
adaug:=true;
while adaug and(i<=n) do
if el=v[i] then
daug:=false
else i:=i+1;
if adaug then
begin
n:=n+1;
v[n]:=el;
end;
end;
procedure mcopiaza(var v1,v2:mat;n:integer);
var i:byte;
begin
for i:=1 to n do
begin
v2[i,1]:=v1[i,1];
v2[i,2]:=v1[i,2];
end;
end;
procedure madauga(var v:mat;var n:integer;el1,el2:integer);
var i:integer;
adaug:boolean;
begin

43
Programarea calculatoarelor. Aplicaţii

i:=1;adaug:=true;
while adaug and(i<=n) do
if ((el1=v[i,1])and(el2=v[i,2])) or
((el1=v[i,2])and(el2=v[i,1]))
then adaug:=false
else i:=i+1;
if adaug then
begin
n:=n+1;
v[n,1]:=el1;
v[n,2]:=el2;
end;
end;
begin {program principal}
clrscr;
write('Numarul de varfuri:');
readln(n);
write('Numarul de muchii:');
readln(m);
for i:=1 to m do
for j:=1 to 2 do
begin
write('a[',i,',',j,']=');
readln(a[i,j]);
end;
write('Varful pentru care se det. comp. conexa:');
readln(k);
v0[1]:=k;
dv:=1;
dv0:=1;
de:=0;
de0:=0;
v[1]:=k;
gata:=false;
repeat
for l:=1 to dv0 do
for j:=1 to m do
if (a[j,1]=v0[l])then
begin
madauga(e,de,a[j,1],a[j,2]);
adauga(v,dv,a[j,2])
end
else if (a[j,2]=v0[l])then
begin
adauga(v,dv,a[j,1]);
madauga(e,de,a[j,2],a[j,1]);
end;
if (dv0=dv)and(de0=de) then
gata:=true
else begin
copiaza(v,v0,dv);
mcopiaza(e,e0,de);
dv0:=dv;
de0:=de;
end;
until (gata);
for i:=1 to dv do
write(v[i],' ');
writeln;
for i:=1 to de do
writeln(e[i,1],'---->',e[i,2]);

44
Grafuri. Implementări în limbajul Pascal

readln;
end.

Problema 4. Să se realizeze implementarea Pascal pentru algoritmul Yen.


Graful este repezentat prin matricea ponderilor. Valoarea ponderii 10000 semnifică
absenţa muchiei.
uses crt;
var
d,w:array[1..20,1..20] of real;
k,i,j,n,l,j0:byte;
v,b:array[1..20] of real;
min:real;

function minim(x,y:real):real;
begin
if x<y then minim:=x
else minim:=y;
end;
begin
clrscr;
write('Numarul de varfuri ale grafului:');
readln(n);
writeln('Matricea ponderilor:');
for i:=1 to n do
for j:=1 to n do
if i<>j then
begin
write('w[',i,',',j,']=');
readln(w[i,j]);
d[i,j]:=w[i,j];
end
else begin
w[i,j]:=10000;
d[i,j]:=10000;
end;
write('Varful dorit:');
readln(k);
for i:=1 to n do v[i]:=1;
v[k]:=0;b[k]:=0;
for i:=1 to n do
begin
min:=10000;
for j:=1 to n do
if (v[j]=1)and(d[k,j]<min)then
begin
j0:=j;
min:=d[k,j];
end;
for j:=1 to n do
d[k,j]:=minim(d[k,j],d[k,j0]+d[j0,j]);
v[j0]:=0;
b[j0]:=d[k,j0];
end;
writeln('Distantele minime de la ',k,' la celelalte varfuri ');
for i:=1 to n do
begin
write(k,'---->',i);
writeln(':',b[i]);
end;
readln;

45
Programarea calculatoarelor. Aplicaţii

end.

Exerciţii

1. Să se scrie un program pentru citirea matricei de adiacenţă a unui graf,


generarea reprezentării tabelare şi obţinerea listei vecinilor fiecărui vârf al grafului.
2. Să se scrie un program pentru parcurgerea BF în prima variantă de
prezentare (a se vedea Capitolul 3 din Programarea calculatoarelor. Tehnica
programării în limbajul PascalI).
3. Să se scrie un program pentru implementarea parcurgerii BF aplicată
unui graf reprezentat prin liste.
4. Să se scrie un program pentru implementarea parcurgerii DF în prima
variantă de prezentare (a se vedea Capitolul 3 din Programarea calculatoarelor.
Tehnica programării în limbajul PascalI).
5. Să se scrie un program pentru implementarea parcurgerii DF aplicată
unui graf reprezentat prin liste.
6. Să se scrie un program pentru verificarea faptului că o secvenţă de
vârfuri într-un graf este un drum.
7. Să se scrie o procedură pentru determinarea tuturor subdrumurilor
elementare ale unui drum dat.
8. Să se scrie o procedură pentru verificarea conexităţii unui graf pe baza
parcurgerii BF.
9. Să se scrie o procedură pentru verificarea conexităţii unui graf pe baza
parcurgerii DF.
10. Să se scrie o procedură pentru calculul matricei existenţei drumurilor
(1) ( 2) ( n −1)
într-un graf cu n vârfuri, M = A ⊕ A ⊕ Κ ⊕ A .
11. Să se scrie o procedură pentru verificarea conexităţii unui graf pe baza
algoritmului Roy-Warshall.
12. Să se scrie un program pentru determinarea tuturor componentelor
conexe ale unui graf.
13. Să se scrie un program pentru implementarea algoritmului Dijkstra,
graful fiind conex şi reprezentat prin matricea ponderilor
14. Să se scrie un program pentru implementarea algoritmului Dijkstra,
graful fiind conex şi reprezentat prin liste.
15. Să se scrie un program pentru determinarea într-un graf ponderat conex a
perechilor de vârfuri (u, v) cu proprietatea că D(u,v)= max{D(x,y)/x,y∈V, x≠y}.
16. Să se scrie un program pentru determinarea într-un graf ponderat conex a
perechilor de vârfuri (u, v) cu proprietatea că D(u,v)= min{D(x,y)/x,y∈V, x≠y}.
17. Modificaţi programul pentru algoritmul Dijkstra pentru calculul valorilor
D(u , v) = min{L{Γ), Γ ∈ D uv } şi a câte unui u-v drum Γ astfel încât L( Γ )=D(u,v),
pentru toate perechile de vârfuri distincte u,v ale unui graf ponderat conex.
18. Propuneţi o variantă a algoritmului Dijkstra pentru calculul valorilor
Q( v 0 , v} = max{L(Γ), Γ ∈ D v0 v } şi a câte unui v0-v drum Γ astfel încât

46
Grafuri. Implementări în limbajul Pascal

L( Γ )=Q(v0,v), pentru toţi v∈V\{v0} unde v0 este un vârf fixat al unui graf ponderat
conex.

47
4. ARBORI

Problema 1. Realizaţi un program Pascal pentru implementarea algoritmului


Kruskal.

uses crt;
var a:array[1..200,1..3] of integer;
tata:array[1..20] of integer;
i,j,k,p,v1,v2,c:integer;
m,n:integer;
contor:integer;
begin
clrscr;
write(‘Numarul de varfuri:’);
readln(n);
write(‘Numarul de muchii:’);
readln(m);
for i:=1 to m do
for j:=1 to 3 do
begin
write('a[',i,',',j,']=');
readln(a[i,j]);
end;
for i:=1 to n do tata[i]:=-1;
c:=0;
j:=1;i:=0;
repeat
v1:=a[j,1];
v2:=a[j,2];
k:=v2;
while tata[k]>0 do
k:=tata[k];
p:=v1;
while tata[p]>0 do
p:=tata[p];
if k<>p then
begin
if tata[k]<tata[p] then begin
tata[k]:=tata[k]+tata[p];
tata[p]:=k;
end
else begin
tata[p]:=tata[k]+tata[p];

48
Programarea calculatoarelor. Aplicaţii

tata[k]:=p;
end;
c:=c+a[j,3];
writeln(v1,'---->',v2,' ',a[j,3]);
i:=i+1;
end;
j:=j+1;
until i=n-1;
writeln('Costul arborelui:',c);
readln;
end.

Observaţie În cele ce urmează este folosită următoarea structura de date


Pascal pentru definirea unui arbore binar:

type arb=^nod;
nod=record;
inf:integer;
fius,fiud:arb;
end;

Problema 2. Scrieţi o funcţie pentru calculul nivelului unui arbore binar.


Prin definiţie, nivelul unui arbore este numărul de muchii de pe un cel mai lung drum
de la rădăcină la un nod terminal.

function nivel(r:arb):word;
var n,n1,n2:word;
begin
if r=nil then nivel:=0
else
begin
n1:=nivel(r^.fius);
n2:=nivel(r^.fiud);
if(n1>n2) then
n:=n1
else n:=n2;
nivel:=1+n;
end;
end;

Problema 3. Scrieţi un subprogram pentru numărarea nodurilor cu informaţie


pară, respectiv a nodurilor cu informaţie impară dintr-un arbore binar.

procedure numara(r:arb; var np:integer; var ni:integer);


var np1,np2,ni1,ni2:integer;
begin
if r=nil then
begin
np:=0;
ni:=0;
end
else begin
numara(r^.fius,np1,ni1);
numara(r^.fiud,np2,ni2);

49
Arbori

np:=np1+np2;
ni:=ni1+ni2;
if(r^.inf mod 2 =0) then
inc(np)
else inc(ni);
end;
end;

Problema 4. Scrieţi o procedură pentru inserarea unui nod într-un arbore de


sortare.

procedure ins(var v:arb;nr:integer);


begin
if v=nil then
begin
new(v);
v^.inf:=nr;
v^.fiud:=nil;
v^.fius:=nil;
end
else if v^.inf>nr then
ins(v^.fius,nr)
else if v^.inf=nr then
writeln('Nr redefinit')
else ins(v^.fiud,nr);
end;

Problema 5. Utilizând subprogramul de la problema 3, scrieţi un program


Pascal pentru crearea unui arbore de sortare şi sortarea crescătoare a vectorului
asociat de informaţii. Informaţiile asociate nodurilor arborelui sunt citite de la
tastatură, până la întâlnirea marcatorului standard de sfârşit de fişier.

uses crt;
type arb=^nod;
nod=record
inf:integer;
fius,fiud:arb;
end;
var r:arb;
i:integer;

procedure SRD(r:arb);
begin
if(r<>nil) then
begin
SRD(r^.fius);
write(r^.inf,' ');
SRD(r^.fiud);
end;
end;
procedure ins(var v:arb;nr:integer);
begin
if v=nil then
begin
new(v);v^.inf:=nr;
v^.fiud:=nil;
v^.fius:=nil;

50
Programarea calculatoarelor. Aplicaţii

end
else if v^.inf>nr then
ins(v^.fius,nr)
else if v^.inf=nr then
writeln('Nr redefinit')
else ins(v^.fiud,nr);
end;
begin
clrscr;
r:=nil;
checkeof:=true;
write('Informatia:');
while not eof do
begin
readln(i);
ins(r,i);
write('Informatia');
end;
writeln('Vectorul sortat este ');
SRD(r);
reset(input);
readln;
end.

Problema 6. Scrieţi un subprogram pentru căutarea unei informaţii într-un


arbore de sortare.
Funcţia cauta returnează valoarea true, dacă informaţia a fost găsită în
arbore, altfel returnează false.

function cauta(r:arb;info:integer):boolean;
begin
if r=nil then
cauta:=false
else if r^.inf=info then
cauta:=true
else if r^.inf>info then
cauta:=cauta(r^.fius,info)
else cauta:=cauta(r^.fiud,info);
end;
Problema 7. Scrieţi o procedură pentru ştergerea unei informaţii dintr-un
arbore de sortare.

procedure sterge(var v:arb;cheie:integer);


var
p1, p,aux:arb;
begin
if v=nil then
writeln('Nu exista cheie')
else if v^.inf<cheie then
sterge(v^.fiud,cheie)
else if v^.inf>cheie then
sterge(v^.fius,cheie)
else if v^.fius=nil then
begin
aux:=v;
v:=v^.fiud;
dispose(aux);
end

51
Arbori

else begin
p:=v^.fius;
while p^.fiud<> nil do
begin
p1:=p;
p:=p^.fiud;
end;
if p=v^.fius then
begin
aux:=p;
v^.inf:=p^.inf;
v^.fius:=p^.fius;
dispose(aux);
end
else begin
v^.inf:=p^.inf;
aux:=p;
p:=p^.fius;
p1^.fiud:=p;
dispose(aux);
end;
end;
end;

Problema 8. Scrieţi subprogramele pentru implementarea celor două etape


ale algoritmului de construcţie a arborelui de derivare asociat unei expresii date (a se
vedea cartea Programarea calculatoarelor. Tehnica programării în limbajul Pascal).

procedure prioritati(var s:string; var prioritate:vect);


var
i,j,dim:byte;
begin
{stabilirea prioritatilor}
j:=0; dim:=0;
for i:=1 to length(s) do
case s[i] of
‘)’:j:=j-10;
‘(‘:j:=j+10;
‘+’,’-‘: begin
inc(dim);
prioritate[dim]:=j+1;
end
‘*’,’/’: begin
inc(dim);
prioritate[dim]:=j+10;
end
else begin
inc(dim);
prioritate[dim]:=maxint;
end;
end;
{eliminarea parantezelor din s}
i:=1;
while(i<=length(s)) do
if s[i] in [‘)’,’(‘] then delete(s,i,1)
else inc(i);
{aici dim=length(s), deci dim nu trebuie dat ca parametru de
iesire}
end;

52
Programarea calculatoarelor. Aplicaţii

procedure cr_der(var r:arb;p,u:byte;var s:string;


var prioritate:vect);
var
i,j:byte;
min:integer;
begin
min:=prioritate[u];
i:=u;
for j:=u downto p do
if prioritate[j]<min then
begin
min:=prioritate[j];
i:=j;
end;
new(r) ;
r^.inf:=s[i];
if p=u then
begin
r^.fius:=nil;
r^.fiud:=nil;
end
else begin
cr_der(r^.fius,p,i-1,s,prioritate);
cr_der(r.fiud,i+1,u,s,prioritate);
end;
end;

Exerciţii

1. Scrieţi un program pentru crearea unei structuri arborescente


corespunzătoare unui arbore orientat.
2. Realizaţi o procedură pentru parcurgerea în A-preordine a unui arbore
orientat reprezentat prin listă de liste.
3. Realizaţi o procedură pentru parcurgerea în A-postordine a unui arbore
orientat reprezentat prin listă de liste.
4. Realizaţi programul pentru parcurgerile A-preordine şi A-postordine a
arborilor reprezentaţi prin rădăcină şi vectorii FIU, FRATE.
5. Realizaţi o procedură pentru parcurgerea în A-preordine a unui arbore
orientat reprezentat printr-o structură de date arborescentă.
6. Realizaţi o procedură pentru parcurgerea în A-postordine a unui arbore
orientat reprezentat prin rădăcină şi vectorii FIU, FRATE.
7. Scrieţi o procedură care realizează parcurgerea pe nivele a unui arbore
orientat reprezentat printr-o structură de date arborescentă.
8. Scrieţi o procedură pentru testarea fapului că un arbore binar este arbore
de sortare.
9. Scrieţi o procedură pentru crearea unui arbore binar.
10. Realizaţi o procedură pentru scrierea unei expresii aritmetice în forma
poloneză inversă.
11. Scrieţi o procedură pentru pentru eliminarea parantezelor “inutile” ale
unei expresii.

53
5. ALGORITMI RECURSIVI.
METODELE DIVIDE ET IMPERA ŞI
BACKTRACKING

Problema 1. Scrieţi funcţiile Pascal pentru calculul termenilor de rang n


(pentru n dat) din şirurile definite prin relaţiile:
a n = αa n −1 + βbn −1 , bn = γa n −1 + δbn −1 ,
unde a0 , b0 , α , β ,γ ,δ sunt numere reale date.
Considerând a0,b0,alfa, beta, gama, delta variabile globale, funcţiile Pascal
A(n) şi B(n) calculează termenii de rang n din cele două şiruri.

function B(n:word):real;forward;

function A(n:word):real;
begin
if n=0 then A:=a0
else A:=alfa* A(n-1)+ beta*B(n-1);
end;
function B(n:word):real;
begin
if n=0 then B:=b0
else B:=gama* A(n-1)+ delta*B(n-1);
end;

Problema 2. Să se scrie un subprogram care citeşte o secvenţă oarecare de


cuvinte a1, a2,….., an terminată cu simbolul # şi afişează anan-1…a1.

uses crt;
procedure Trick;
var
cuvant:string;
begin
readln(cuvant);

54
Programarea calculatoarelor. Aplicaţii

if cuvant<>'#' then
begin
Trick;
writeln(cuvant);
end
end;
begin
clrscr;
trick;
readln;
end.

Problema 3. Fie o listă dinamică identificată prin variabila cap. Realizaţi o


procedură recursivă pentru parcurgerea listei de la prima componentă către ultima.

procedure parcurgere1(cap:lista);
begin
if cap<>nil then
begin
prelucreaza(cap);
parcurgere(cap^.leg);
end;
end;

Problema 4. Fie o listă dinamică identificată prin variabila cap. Realizaţi o


procedură recursivă pentru parcurgerea listei, elementele accesate fiind prelucrate în
ordinea inversă ordinei în care apar în listă (de la ultima componentă către prima).

procedure parcurgere2(cap:lista);
begin
if cap<>nil then
begin
parcurgere(cap^.leg);
prelucreaza(cap);
end;
end;

Problema 5. Fie o listă dinamică identificată prin variabila cap. Se


presupune că valorile memorate în câmpurile de informaţie sunt numere reale.
Calculaţi maximul şi minimul valorilor memorate în listă.

procedure max_min(cap:lista; var max,min:real; var


test:boolean);
begin
test:=true;
if cap=nil then
test:=false
else
if cap^.leg=nil then
begin
max:=cap^.inf;
min: =cap^.inf;
end
else
begin
max_min(cap^.leg,max,min,test);

55
Algoritmi recursivi. Metodele Divide et impera şi backtracking

if cap^.inf>max then
max:= cap^.inf
else if cap^.inf<min then
min:= cap^.inf;
end;
end;

Problema 6. Scrieţi programul pentru aplicarea schemei Horner pentru


calculul valorii unui polinom de grad cel mult 100, într-un punct, a, dat. Coeficienţii
polinomului de grad n sunt memoraţi în variabila p, în ordinea descrescătoare a
puterilor.

type pol=array[1..101]of real;


var
p:pol;
i,grad:byte;
a:real;
function valoare(var p:pol;n:byte;a:real):real;
begin
if n>1 then
valoare:=p[n]+a*valoare(p,n-1,a)
else valoare:=p[1];
end;
begin
readln(grad);
for i:=1 to grad+1 do
readln(p[i]);
readln(a);
writeln(valoare(p,grad+1,a));
readln;
end.

Problema 7. Fie funcţia h definită recursiv pe mulţimea {0,1,...,9} , cu valori


în mulţimea cuvintelor prin relaţia
0 , x = 0
h( x ) = 
h( x − 1 )xh( x − 1 ), 1 ≤ x ≤ 9
Scrieţi programul pentru alculul cuvîntului care este valoarea funcţiei h(x)
pentru x dat. De exemplu:
- pentru x=0 cuvântul este ‘0’;
- pentru x=1, cuvântul este ‘010’;
- pentru x=2, cuvântul este ‘0102010’.
uses crt;
var
x:0..9;
function h(x:byte):string;
begin
if x=0 then
h:='0'
else
h:=h(x-1)+chr(x+ord('0'))+h(x-1);
end;

56
Programarea calculatoarelor. Aplicaţii

begin
clrscr;
readln(x);
writeln(h(x));
readln;
end.

Problema 8. Funcţia Ackermann este definită pentru argumentele m,n


numere naturale prin:
n + 1, m = 0

a( m , n ) = a( m − 1,1 ), n = 0
a( m − 1, a( m , n − 1 )), altfel

Scrieţi o funcţie pentru calculul valorii a(m,n), pentru m şi n partametri
cunoscuţi.

function Ackermann(m,n:byte):word;
begin
if m=0 then
Ackermann:=n+1
else if n=0 then
Ackermann:= Ackermann(m-1,1)
else
Ackermann:= Ackermann(m-1,Ackermann(m,n-1));
end;

Problema 9. Problema turnurilor din Hanoi. Se presupune că există trei tije


a, b, c, pe tija a fiind plasate n discuri de diametre diferite în ordinea descrescătoare a
acestora. Se cere să se deplaseze cele n discuri pe tija c astfel încât să fie îndeplinite
condiţiile:
- la fiecare mutare este deplasat unul dintre discurile aflate pe poziţia
superioară pe una din tije;
- oricare din discuri poate fi aşezat numai pe un disc de diametru mai mare;
- tija b poate fi folosită pentru deplasări intermediare.
Presupunând că discurile sunt numerotate în ordinea crescătoare a
diametrelor cu etichetele1, 2, 3, o soluţie a problemei, pentru n=3, poate fi descrisă
astfel.

Tija a Tija b Tija c Mutarea efectuată


1 a⇒c
2
3
2 1 a⇒b
3
3 2 1 c⇒b
3 1 a⇒c
2

57
Algoritmi recursivi. Metodele Divide et impera şi backtracking

1 3 b⇒a
2
1 2 3 b⇒c
1 2 a⇒c
3
1
2
3

Notând cu P(n,a,c) problema transferului celor n discuri de pe tija a pe tija c,


pentru rezolvarea ei putem raţiona în modul următor. Dacă s-a rezolvat problema
P(n-1,a,b), atunci discul de diametru maxim care se află încă pe tija a este deplasat
pe tija c şi în continuare se rezolvă problema P(n-1,b,c). Soluţia recursivă este
prezentată în procedura Hanoi.

uses crt;
var
n,a,b,c:byte;
procedure Hanoi(n,a,b,c:byte);
begin
if n>0 then
begin
Hanoi(n-1,a,c,b);
writeln('Transfer disc de pe tija ',a,' pe tija ',b);
Hanoi(n-1,c,b,a);
end;
end;
begin
clrscr;
readln(n);
Hanoi(n,1,2,3);
readln;
end.

Problema 10. Scrieţi o funcţie Pascal recursivă pentru calculul celui mai mic
multiplu comun al două numere naturale a şi b.
Este aplicată următoarea definiţiei pentru calculul (a,b):
a , a = b

( a ,b ) = ( a − b ,b ), a > b
( a ,b − a ), b > a

function cmmdc(a,b:word):word;
begin
if a=b then
cmmdc:=a
else if a>b then
cmmdc:=cmmdc(a-b,b)
else
cmmdc:=cmmdc(a,b-a);

58
Programarea calculatoarelor. Aplicaţii

end;

Problema 11. Căutarea în vectori sortaţi (căutarea binară).


Se presupune că v este un tablou unidimensional de numere reale sortat
crescător şi k este un număr real dat. Problema este de a identifica (dacă există) o
valoare poz, astfel încât v[poz]=k. Procedura recursivă caut(s,d:byte;var pozitie:byte)
implementează căutarea descrisă pentru componentele de ranguri
p , p = s , s + 1,..., d ; tabloul v este variabilă globală.

program cautare_binara;
uses crt;
var
n,i,poz:byte;
v:array[1..100] of real;
k:real;
procedure caut(s,d:byte;var pozitie:byte);
var
i:byte;
begin
if s<=d then
begin
i:=(s+d)div 2;
if k=v[i] then
pozitie:=i
else if k>v[i] then
caut(i+1,d,pozitie)
else caut(s,i-1,pozitie);
end
else poz:=0;
end;
begin {program principal}
clrscr;
write('Dati dimensiunea vectorului:');
readln(n);
writeln('Elementele vectorului:');
for i:=1 to n do
readln(v[i]);
write('Dati cheia de cautare:');
readln(k);
caut(1,n,poz);
if poz=0 then writeln('Cautare fara succes')
else
writeln('Elementul cautat se afla pe pozitia ',poz,' in
vector');
end.

Problema 12. Sortarea crescătoare prin inserare.


Pentru sortarea crescătoare a unei secvenţe de numere reale se poate raţiona
astfel: dacă P(n) este problema sortării crescătoare a secvenţei a1, a2,…,an şi P(n-1)
este problema sortării primelor n-1 componente, atunci soluţia problemei P(n) rezultă
din soluţia problemei P(n-1) prin inserarea lui an în soluţia problemei P(n-1). Fiecare

59
Algoritmi recursivi. Metodele Divide et impera şi backtracking

problemă intermediară P(k), k = 2 ,..., n este rezolvată aplicând aceeaşi metodă, P(1)
este o problemă “gata rezolvată” (condiţie terminală).
Procedura insera(x,n) realizează inserarea valorii x în vectorul y pe poziţia n.
Procedura inssort(n) realizează sortarea vectorului cu n componente prin inserţie,
utilzând metoda “Divide et impera”.

program inter_sort;
uses crt;

var
n,i:word;
v:array[1..1000] of real;
procedure insera(x:real;n:word);
var
i,j:word;
begin
i:=1;
while(i<=n)and(x>v[i]) do
inc(i);
for j:=n+1 downto i+1 do
v[j]:=v[j-1];
v[i]:=x;
end;

procedure inssort(n:word);
var
i:word;
begin
if n>1 then
begin
inssort(n-1);
insera(v[n],n-1);
end;
end;
begin {program principal}
clrscr;
readln(n);
for i:=1 to n do
readln(v[i]);
inssort(n);
for i:=1 to n do
write(v[i]:4:2,' ');
readln;
end.

Problema 13. Sortarea crescătoare prin interclasare a unei secvenţe de


numere reale.
Pentru sortarea crescătoare a unei secvenţe de numere reale se poate proceda
astfel: dacă P(l,r) este problema sortării crescătoare a secvenţei al, al+1,…,ar, atunci
soluţia problemei P(1,n) rezultă prin interclasarea soluţiilor problemelor P(1,m),
n 
P(m+1,n), unde m =   . Problemele intermediare P(l,r), l<r sunt rezolvate pe
2
baza aceleiaşi metode. P(l,l) este o problemă “gata rezolvată” (condiţie terminală).

60
Programarea calculatoarelor. Aplicaţii

Procedura interc(l,m,r) realizează interclasarea secvenţelor sortate vl, vl+1, …,


vm, respectiv vm+1, vm+2, …, vr în vectorul v. Procedura inters(l,r) realizează sortarea
secvenţei vl, vl+1, …, vr din vectorul v, utilzând metoda “Divide et impera”.

program inter_sort;
uses crt;
var
n,i:word;
v:array[1..1000] of real;
par:array[1..1000] of real;
procedure interc(l,m,r:word);
var
i,j,k:word;
begin
if l<r then
begin
i:=l;
j:=m+1;
k:=1;
while(i<=m) and (j<=r) do
begin
if v[i]<v[j] then
begin
par[k]:=v[i];
i:=i+1;
k:=k+1;
end
else begin
par[k]:=v[j];
j:=j+1;
k:=k+1;
end;
end;
if i<=m then
for j:=i to m do
begin
par[k]:=v[j];
k:=k+1;
end
else
for i:=j to r do
begin
par[k]:=v[i];
k:=k+1;
end;
end;
for i:=0 to r-l do
v[l+i]:=par[i+1];
end;
procedure inters(l,r:word);
var
i:word;
begin
if l<r then
begin
i:=(l+r)div 2;
inters(l,i);
inters(i+1,r);
interc(l,i,r);

61
Algoritmi recursivi. Metodele Divide et impera şi backtracking

end;
end;
begin {program principal}
clrscr;
readln(n);
for i:=1 to n do
readln(v[i]);
inters(1,n);
for i:=1 to n do
write(v[i],' ');
end.

Problema 14. Să se scrie un program pentru calculul formei prefix a unei


expresii parantezate date E.
Expresia este construită pe baza unui singur tip de operator care este
comutativ. Calculul formei prefix se realizează prin parcurgerea de la stânga la
dreapta a secvenţei de simboluri din expresie.

Descrierea algoritmului:
1) Dacă E=(expr) operator rest, atunci scrie operator, parcurge expr,
parcurge expresia rest.
2) Dacă E=literal operator rest, atunci scrie operator, parcurge literal,
parcurge rest.
3) Dacă E=(expr), atunci elimină parantezele, parcurge expr.

Programul preordine implementează algoritmul descris în ipoteza că


expresia E este corect scrisă din punct de vedere sintactic.

program preordine;
uses crt;
type
sirr=string[30];
const
nr:shortint=0;
op='*';
var
sir:sirr;
lung,i:byte;
a:char;
procedure preord(sir0:sirr);
var
sir1,sir2:string;
i,j:byte;
b,bo:boolean;
begin
b:=false;
bo:=true;
if(length(sir0)=1) then
write(sir0[1])
else
for i:=1 to length(sir0) do
if(bo) then
begin
case sir0[i] of

62
Programarea calculatoarelor. Aplicaţii

'(': begin
nr:=nr+1;
b:=true;
end;
')': nr:=nr-1;
end;{case}
if((nr=0) and b and (i<length(sir0))) then
begin
if (sir0[i]=')') then
sir1:=copy(sir0,2,i-2)
else
sir1:=copy(sir0,1,i);
sir2:=copy(sir0,i+2,length(sir0)-i-1);
write(sir0[i+1]);
preord(sir1);
preord(sir2);
b:=true;
bo:=false;
end;
if((nr=0)and not(b) and (i<length(sir0))) then
if(sir0[i+1] = op)then
begin
sir1:=copy(sir0,1,i);
sir2:=copy(sir0,i+2,length(sir0)-i-1);
write(sir0[i+1]);
preord(sir1);
preord(sir2);
b:=false;
bo:=false;
end;
if((nr=0) and (i=length(sir0))) then
if(sir0[1]='(') then
begin
sir1:=copy(sir0,2,i-2);
preord(sir1);
bo:=false;
end
else begin
write(sir0[2]);
sir1:=copy(sir0,1,1);
sir2:=copy(sir0,3,i-2);
preord(sir1);
preord(sir2);
bo:=false
end;
end;{if}
end;
begin {program principal}
clrscr;
write('Introduceti expresia ');
readln(sir);
lung:=ORD(sir[0]);
if ( lung<1) then
writeln('Expresie vida!')
else preord(sir);
writeln;
end.

Problema 15. Să se scrie programul pentru generarea tuturor submulţimilor


mulţimii S={1, 2,..., n}, n ≤ 7.

63
Algoritmi recursivi. Metodele Divide et impera şi backtracking

Vor fi generate succesiv toate submulţimile cu k elemente, k=1, 2,…, n.


Fiecare submulţime SubS este reprezentată prin funcţia indicator, valorile acesteia
fiind componentele vectorului SubS:
0, S[i] ∉ SubS
SubS[i] = 
1, altfel
Condiţiile de continuare corespund caracterizării unei submulţimi. Generarea
unei soluţii (submulţime cu k elemente) este realizată când suma comonentelor
vectorului SubS este egală cu k. Fiecare submulţime generată este memorată într-un
vector de lungime 2n, care, în final, va reprezenta toate submulţimile lui S (P({1, 2,...,
n})). Programul Pascal este:

program submultime;
type elem=0..1;
sub=array[1..7] of elem;
var
n,dim:byte;
x:sub;
tot:array[1..32] of sub;
k,j:integer;
nr:byte;
function suma(t,k:byte):boolean;
var
s,i:byte;
begin
s:=0;
for i:=1 to t do
s:=s+x[i];
if s<=k then
suma:=true
else suma:=false;
end;
function sumaf:byte;
var
s,i:byte;
begin
s:=0;
for i:=1 to n do
s:=s+x[i];
sumaf:=s;
end;
procedure back(k,t:byte);
var
i:byte;
begin
if (t=n+1) then
if(sumaf=k) then
begin
inc(nr);
for i:=1 to n do
tot[nr][i]:=x[i];
end
else

64
Programarea calculatoarelor. Aplicaţii

else
for i:=2 downto 1 do
begin
x[t]:=i-1;
if suma(t,k) then
back(k,t+1);
end;
end;

begin
readln(n);
nr:=0;
for dim:=1 to n do
back(dim,1);
writeln('Submultimile sunt:');
for k:=1 to nr do
begin
for j:=1 to n do
if tot[k][j]=1 then
write(j,' ');
writeln;
end;
end.

Problema 16. Să se genereze toate secvenţele de câte p componente, două


câte două distincte, din mulţimea {1, 2,..., n}, n ≤ 7, p≤ n dat.
Determinarea unei soluţii are loc atunci când k devine p+1 (s-a generat o
secvenţă de p elemente, două câte două distincte, din mulţimea {1, 2,..., n}).

program secvente;
uses crt;
type tip_elem=0..7;
var
x:array[1..7] of tip_elem;
n,p:byte;

function init:byte;
begin
init:=0;
end;
function succ(k:byte):boolean;
begin
if x[k]<n then
succ:=true
else
succ:=false;
inc(x[k]);
end;
function continuare(k:byte):boolean;
var i:byte;
begin
i:=1;
while(i<k)and(x[i]<>x[k]) do
inc(i);
continuare:=i=k;
end;

65
Algoritmi recursivi. Metodele Divide et impera şi backtracking

procedure final;
var i:byte;
begin
for i:=1 to p do
write(x[i],' ');
readln;
end;
procedure back(k:byte);
begin
if k=p+1 then
final
else
begin
x[k]:=init;
while succ(k) do
if continuare(k) then
back(k+1);
end;
end;
begin
clrscr;
write('n si p');
readln(n,p);
back(1);
end.

Problema 17. Să se genereze toate configuraţiilor în care 8 regine pot fi


plasate pe o tablă de şah astfel încât să nu se atace reciproc (nici o pereche de regine
nu trebuie plasată pe aceeaşi linie, coloană sau diagonală).
Configuraţiile sunt generate prin plasarea succesivă a reginelor în câte o linie
a tablei; iniţial tabla este liberă. Deoarece pe fiecare linie şi coloană a tablei de şah
trebuie plasată o singură regină, configuraţiile sunt reprezentate succesiv printr-un
vector cu 8 componente conf. Valoarea componentei i din vectorul conf reprezintă
indicele coloanei în care este plasată regina aflată pe linia i. Din această reprezentare
rezultă că două regine nu pot fi plasate pe aceeaşi linie a tablei de şah.
Funcţia booleană is_ok(k) calculează true dacă şi numai dacă, la adăugarea
celei de-a k regine, configuraţia rezultată este corectă, adică:
- conf[k]<>conf[i], 1 ≤ i ≤ k − 1 (reginele de pe liniile i şi k sunt
plasate pe coloane diferite)
- conf [k ] − conf [i] ≠ k − i (reginele de pe liniile i şi k sunt plasate pe
diagonale diferite).
. Procedura regine implementează metoda backtracking pentru rezolvarea
problemei.

program regine8;
uses crt;
type
configuratie=array[1..8] of byte;
var
conf:configuratie;
function is_ok(k:byte):boolean;

66
Programarea calculatoarelor. Aplicaţii

var
i:byte;
ok:boolean;
begin
ok:=true;i:=1;
while (ok) and (i<k) do
if (conf[k]=conf[i]) or
(abs(conf[k]-conf[i])=abs(k-i)) then ok:=false
else inc(i);
is_ok:=ok;
end;
procedure scrie_sol;
var
i:byte;
c:char;
begin
writeln('Configuratie corecta:');
for i:=1 to 8 do
begin
write('Regina ',i,' se afla pe ');
writeln('Linia: ',i,' coloana: ',conf[i]);
end;
c:=readkey;
end;

procedure regine(i:byte);
var
k:byte;
begin
if i=9 then scrie_sol
else begin
for k:=1 to 8 do
begin
conf[i]:=k;
if is_ok(i) then regine(i+1);
end;
end;
end;
begin
clrscr;
regine(1);
end.

Problema 18. Fie o hartă cu n ţări, n ≤ 30. Să se scrie programul care


determină colorarea hărţii cu m culori, m ≤ 7 , astfel încât oricare două ţări vecine să
fie colorate diferit.
Reprezentarea hărţii se face printr-o tabelă, A, cu n × n componente definite
astfel:
1, ţările i, j sunt vecine
A[i, j] =  .
0, altfel
Funcţia verifica(k) returnează valoarea true dacă şi numai dacă colorarea
primelor k ţări respectă condiţia din enunţ. Procedura color implementează metoda
backtracking aplicată pentru rezolvarea problemei.

67
Algoritmi recursivi. Metodele Divide et impera şi backtracking

program colorare;
uses crt;
var
A:array[1..30,1..30] of byte;
i,j:byte;
sol:array[1..30] of byte;
n:byte;
m:byte;

const culoare:array[1..7] of
string=('alb','negru','rosu','albastru','gri',‘galben',
'verde');
function verifica(k:byte):boolean;
var
i:byte;
ok:boolean;
begin
ok:=true;
i:=1;
while(i<k) and (ok) do
if (sol[i]=sol[k]) and (A[i,k]=1) then
ok:=false
else inc(i);
verifica:=ok;
end;

procedure scrie;
var
i:byte;
c:char;
begin
for i:=1 to n do
writeln('Tara ',i,' are culoarea ',culoare[sol[i]]);
writeln;
c:=readkey;
end;

procedure color(k:byte);
var
i:byte;
begin
if k=n+1 then scrie
else
for i:=1 to m do
begin
sol[k]:=i;
if verifica(k) then
color(k+1);
end;
end;
begin
clrscr;
write('Numarul de tari:');
readln(n);
writeln('Matricea vecinilor (pe linii, fiece componenta se
separa prin spatiu de urmatoarea ):');
for i:=1 to n do
begin
for j:=1 to n do
68
Programarea calculatoarelor. Aplicaţii

read(A[i,j]);
readln;
end;
write('Numarul de culori: ');
readln(m);
color(1);
end.

Problema 19. Se presupune că pe malul unui râu se află o barcă, trei


misionari şi trei canibali “parţial educaţi“. Misionarii şi canibalii doresc să traverseze
râul, dar barca nu poate transporta decât cel mult două persoane. Deoarece canibalii
sunt numai “parţial educaţi”, nu se poate avea încredere în ei, aşa că trebuie ca, în
orice moment, pe cele două maluri, numărul misionarilor să fie cel puţin egal cu cel
al canibalilor. Să se scrie un program pentru rezolvarea problemei, indicându-se, la
fiecare moment, numărul misionarilor şi al canibalilor pe fiecare dintre maluri şi
poziţia bărcii.

program canibali;
uses crt;
type stare=record
ncs,ncd,nms,nmd:0..3;
{ numarul de canibali si misionari de pe malurile
stang si drept ale raului}
pb:-1..1;
{ pozitia barcii}
end;
var
sol:array[1..50] of stare;
mut:array[1..2,1..5] of integer;
f:text;

function visit(st:stare; l:integer):boolean;


{ true- starea st a fost trecuta anterior in solutie
false- in caz contrar}
var
i:integer;
v:boolean;
begin
v:=true;
for i:=1 to l do
if (sol[i].ncs=st.ncs) and
(sol[i].ncd=st.ncd) and
(sol[i].nmd=st.nmd) and
(sol[i].nms=st.nms) and
(sol[i].pb=st.pb) then
v:=false;
visit:=not(v);
end;
function pot_muta(st:stare;j:integer):boolean;
{ true- starea st poate fi acceptata
false- in caz contrar}
var
pot:boolean;
begin
pot:=false;

69
Algoritmi recursivi. Metodele Divide et impera şi backtracking

if st.pb=-1 then
if(st.ncs>=mut[1,j]) and
(st.nms>=mut[2,j]) then
pot:=true;
if st.pb=1 then
if(st.ncd>=mut[1,j]) and
(st.nmd>=mut[2,j]) then
pot:=true;
pot_muta:=pot;
end;
procedure back(st:stare;l:integer);
var
st1:stare;
i,j:integer;
ch:char;
begin
st:=sol[l];
if(st.ncd+st.nmd=6) and(st.pb=1) then
begin
for i:=1 to l do
begin
write(f,'Mal st.: canibali=');
write(f,sol[i].ncs);
write(f,' , misionari=');
write(f,sol[i].nms);
write(f,' Mal dr.: canibali=');
write(f,sol[i].ncd);
write(f,' , misionari=');
write(f,sol[i].nmd);
write(f,' barca pe malul ');
if sol[i].pb=-1 then
write(f,'stang')
else
write(f,'drept');
writeln(f);
end;
writeln(f);
end
else
for j:=1 to 5 do
if((st.ncs+st.pb*mut[1,j]<=st.nms+st.pb*mut[2,j]) or
(st.nms+st.pb*mut[2,j]=0)) and
((st.ncd-st.pb*mut[1,j]<=st.nmd-st.pb*mut[2,j]) or
(st.nmd-st.pb*mut[2,j]=0)) and
((st.nms+st.pb*mut[2,j])>=0) and
((st.ncs+st.pb*mut[1,j])>=0) and
((st.nmd-st.pb*mut[2,j])>=0) and
((st.ncd-st.pb*mut[1,j])>=0) and pot_muta(st,j)
then begin
st1:=st;
st1.ncs:=st1.ncs+st1.pb*mut[1,j];
st1.nms:=st1.nms+st1.pb*mut[2,j];
st1.nmd:=st1.nmd-st1.pb*mut[2,j];
st1.ncd:=st1.ncd-st1.pb*mut[1,j];
st1.pb:=-st1.pb;
if not(visit(st1,l)) then
begin
sol[l+1]:=st1;
back(st1,l+1);
end;
end;
end;
70
Programarea calculatoarelor. Aplicaţii

begin
assign(f,'canibali.txt');
rewrite(f);
sol[1].nms:=3;
sol[1].ncd:=0;
sol[1].ncs:=3;
sol[1].nmd:=0;
sol[1].pb:=-1;
mut[1,1]:=0;
mut[2,1]:=1;
mut[1,2]:=1;
mut[2,2]:=0;
mut[1,3]:=1;
mut[2,3]:=1;
mut[1,4]:=2;
mut[2,4]:=0;
mut[1,5]:=0;
mut[2,5]:=2;
back(sol[1],1);
close(f);
end.

Soluţiile problemei calculate de program sunt:

Mal stâng Mal drept Poziţie barcă


Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 barca pe malul stang
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul drept
Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 barca pe malul stang
Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 barca pe malul drept
Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul stang
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul drept
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul stang
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul drept
Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 barca pe malul stang
Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 barca pe malul drept
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul stang
Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 barca pe malul drept

Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 barca pe malul stang
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul drept
Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 barca pe malul stang
Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 barca pe malul drept
Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul stang
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul drept
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul stang
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul drept
Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 barca pe malul stang
Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 barca pe malul drept
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul stang
Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 barca pe malul drept

Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 barca pe malul stang

71
Algoritmi recursivi. Metodele Divide et impera şi backtracking

Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul drept
Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 barca pe malul stang
Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 barca pe malul drept
Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul stang
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul drept
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul stang
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul drept
Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 barca pe malul stang
Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 barca pe malul drept
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul stang
Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 barca pe malul drept

Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 barca pe malul stang
Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul drept
Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 barca pe malul stang
Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 barca pe malul drept
Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 barca pe malul stang
Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 barca pe malul drept
Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 barca pe malul stang
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul drept
Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 barca pe malul stang
Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 barca pe malul drept
Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 barca pe malul stang
Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 barca pe malul drept

Exerciţii

1. Să se stabilească evoluţia în stiva memoriei calculatorului determinată de


apelul Ackerman(3,2).
2. Să se scrie o procedură recursivă pentru sortarea crescătoare a unei
secvenţe de numere prin metoda bulelor.
3. Să se scrie o procedură recursivă pentru sortarea crescătoare a unei
secvenţe de numere prin inserţie.
4. Scrieţi o procedură recursivă pentru calculul celui mai mare divizor
comun al numerelor întregi a1, a2, …, an, n dat.
5. Să se scrie o funcţie recursivă pentru calculul celui de-al n-lea termen al
2 x + 1, x < 2
şirului a n = f ο f ο ... ο f ( x 0 ) , unde x0 este dat şi f ( x ) =  .
1 4 2 4 3 1, x ≥ 2
n ori

6. Să se scrie o procedură recursivă pentru eliminarea dintr-o listă dinamică


a tuturor componentelor ce satisfac o proprietate dată, definită de: function
COND(nod):boolean.

72
Programarea calculatoarelor. Aplicaţii

7. Să se scrie o funcţie recursivă pentru calculul valorilor funcţiei Manna-


 x − 1, x ≥ 12
Pnueli f : Z → Z , definită prin: f ( x ) =  .
 f ( f ( x + 2 )), x < 12
8. Să se scrie o procedură recursivă pentru determinarea termenilor de rang
a n − 1 + bn − 1
n dat din şirurile: a n = , bn = a n −1bn −1 , a0 = a > 0 , b0 = b > 0 .
2
9. Fie funcţia t definită pe mulţimea numerelor naturale nenule definită
m , n = 1

prin: h( m , n ) = n , m = 1 , unde a,b sunt numere întregi. Să se
ah( m , n − 1 ) + bh( m − 1, n )

scrie o funcţie Pascal recursivă pentru calculul valorii h(m,n), m,n,a,b daţi.
10. Fie n număr natural impar. Realizaţi o procedură recursivă P(n) care
desenează un careu de n2 celule în care sunt înscrise numerele 1,2,…,(n+1) /2 după
modelul următor.
3 3 3 3 3
2 2 2 3 2 2 2 3
Pentru n=3 ⇒ 2 1 2 , pentru n=5 ⇒ 3 2 1 2 3 .
2 2 2 3 2 2 2 3
3 3 3 3 3
11. Să se srie un program care calculează suma elementelor unui vector pe
baza metodei “Divide et impera”.
12. Să se scrie un program pentru calculul celui mai mare divizor comun al n
numere naturale.
13. Să se scrie un program pentru calculul mediei aritmetice a unui şir de
numere pe baza metodei “Divide et impera”.
14. Se consideră placă dreptunghiulară în care sunt făcute n perforaţii
punctiforme de poziţii (x,y) cunoscute. Să se scrie un program care să determine un
dreptunghi de arie maximă, cu laturile paralele cu laturile plăcii, care se poate decupa
din placa iniţială astfel încât să nu conţină în interior nici o perforaţie.
15. Realizaţi programul Pascal pentru implementarea următorului joc. Se
consideră n copii aşezaţi în cerc. Fiecare al p-lea copil este eliminat din cerc pe baza
unei numărători. Numărătoarea începe cu cel de-al k-lea copil şi, după fiecare
eliminare, se continuă cu următorul copil de după cel eliminat. Copilul care câştigă
este cel care iese ultimul din cerc.
16. Se presupune cunoscută funcţia bijectivă g:{1,2,…,n}→{1,2,…,n}. Să se
scrie programul care determină toate funcţiile bijective f:{1,2,…,n}→{1,2,…,n}, cu
proprietatea că f○g=g○f.
17. Se presupune cunoscută funcţia bijectivă g:{1,2,…,n}→{1,2,…,n}. Să se
scrie programul care determină toate funcţiile bijective f:{1,2,…,n}→{1,2,…,n}, cu
proprietatea că f○f=g.
73
Algoritmi recursivi. Metodele Divide et impera şi backtracking

18. Fie a1, a2,…,an o secvenţă de numere reale. Să se scrie programul pentru
determinarea valorii maxime k şi secvenţele 1 ≤ i1<i2<…<ik ≤ n, astfel încât
a i1 < ai2 < ... < aik .
19. Fie A o tabelă n × n astfel încât A[i,j] ≥ 0, 1 ≤ i , j ≤ n , reprezentând
cotele unui relief. Se presupune că în celula A[i0,j0] se “toarnă apă” astfel încât se
formează posibil mai multe “râuleţe” (funcţie de diferenţele de nivel). Să se scrie un
program care determină toate “râuleţele” formate.
20. Fie A o tabelă n × n astfel încât A[i,j] ∈ R, 1 ≤ i , j ≤ n . Valorile
pozitive din tabelă reprezintă recompense, iar cele negative reprezintă amenzi.
Celulele A[i,j] şi A[k,p] sunt vecine dacă i=k şi j=p ± 1, sau j=p şi i=k ± 1
1 ≤ i , j , k , p ≤ n . Să se scrie programul care determină o secvenţă de celule vecine,
având prima componentă A[1,1] şi ultima A[n,n], astfel încât suma valorilor celulelor
secvenţei să fie maximă.
21. Să se scrie programul pentru determinarea numărului minim de culori
necesar realizării unei hărţi în care oricare două ţări vecine să fie colorate diferit.
22. Se consideră o matrice A cu m linii şi n coloane reprezentând un labirint.
Fiecare componentă A[i,j], 1 ≤ i ≤ m , 1 ≤ j ≤ n semnifică ieşirile din camera (i,j),
astfel: pentru fiecare dintre cele 4 direcţii posibile (N, S, E, V) se reţine 1, dacă se
poate ieşi spre acea direcţie, altfel se memorează 0; şirul binar NSEV este convertit
în baza 10, valoarea fiind memorată în componenta corespunzătoare camerei (i,j). Fie
(i0,j0), 1 ≤ i0 ≤ m , 1 ≤ j0 ≤ n o cameră arbitrară din labirint. Să se determine:
a) toate variantele de ieşire din labirint pornind din acea
cameră;
b) cea mai scurtă variantă de ieşire din labirint (cu trecere
printr-un număr minim de camere).
23. Un comis-voiajor terbuie să viziteze n oraşe, etichetate cu numere de la 1
la n. Iniţial acesta se află în oraşul etichetat cu 1. Comis-voiajorul doreşte să revină în
oraşul din care a plecat, trecând o singură dată prin toate celelalte oraşe.
a) Cunoscându-se legăturile existente între oraşe, se cere
determinarea tuturor drumurilor posibile pe care le poate efectua comis-
voiajorul.
b) Cunoscându-se legăturile existente între oraşe şi costul
deplasării de la un oraş la altul (în cazul în care deplasarea este posibilă),
se cere determinarea unui drum de cost minim.

74
6. REPREZENTAREA VIZUALĂ
A DATELOR

Problema 1. Scrieţi un program Pascal pentru citirea unui caracter şi


analizarea lui, astfel: dacă a fost apăsată o tastă săgeată, este afişată tasta acţionată.
Procesul se încheie când s-a apăsat tasta ENTER.

Program CitTaste;
Uses CRT;
Var oprire:boolean;
ch1, ch2:char;
Begin
oprire:=false;
ch1:=ReadKey;
While not oprire do
Begin
If ch1=#13 then
Oprire:=true
else
Begin
ch2:=ReadKey;
If ch1=#0 then
case ch2 of
#72:Writeln(’S-a apasat sageata-sus’);
#75:Writeln(’S-a apasat sageata-stânga’);
#77:Writeln(’S-a apasat sageata-dreapta’);
#80:Writeln(’S-a apasat sageata-jos’);
end;
ch1:=Read Key;
End;
End;
Writeln(’Gata’);
Readln;
End.

Problema 2. Scrieţi un program Pascal pentru “intonarea” gamei “Do


major”, până la apăsarea unei taste.

Program GamaDo;
Uses CRT;
Const

75
Programarea calculatoarelor. Aplicaţii

Nota Array [1..8] of Word=(523,587,659,698,784,880,988,1046);


Durata:Word=500;
Var
i:byte;
gata:Boolean;
Begin
gata:=False;
While not gata do
Begin
For i:=1 to 8 do
Begin
Sound(Nota[i]);
Delay(Durata);
Nosound;
End;
If KeyPressed then
gata:=True;
End;
End.

Problema 3. Să se realizeze programul Pascal pentrui trasarea unui cerc, cu


centrul în mijlocul ecranului, utilizând o placă grafică EGA de înaltă rezoluţie.
Programul solicită raza cercului (în număr de pixeli). De remarcat, modul de
definire a centrului ecranului prin integrarea sistemului grafic şi utilizarea funcţiei de
tipul String, GraphErrorMsg, pentru afişarea mesajului care explică eroarea la
iniţializare.

Program ExGraph1;
Uses Graph;
VAR
Raza:word;
GraphDriver, GraphMode, GraphErr: Integer;
BEGIN
GraphDriver:=EGA;
GraphMode:=EGAHi;
InitGraph (GraphDriver,GraphMode,'');
If GraphErr=GrOk then
Begin {acceptare raza si desenare}
Write ('Raza cercului:');
Readln (Raza);
While Raza>300 Do
Begin
Writeln ('Raza prea mare ! Reveniti');
Write ('Raza cercului:'); Readln (Raza)
End;
Circle (GetMaxX div 2, GetMaxY div 2, Raza);
CloseGraph
End
else { Situatie de eroare}
Writeln ('Eroare:', GraphErrorMsg (GraphErr));
END.

Problema 4. Să se deseneze curbele Hilbert H4.


Pot fi realizate desene prin compunerea într-o manieră recursivă a unor
figuri geometrice primitive. Compunerea constă în repetarea primitivelor considerate
şi a rezultatelor obţinute prin rotirea lor într-un sens sau celălalt.

76
Reprezentarea vizuală a datelor

Astfel, dacă mulţimea de primitive H0 constă dintr-un punct şi pentru


compunere este considerat un segment de lungime h, atunci: H1 rezultă din patru
exemple (copii, realizări, instanţe, ‘clone’) de primitive din H0 unite prin segmente
de lungime h; H2 rezultă din 16 exemple din H0 unite prin 15 segmente de lungime
h/2 şamd. De asemenea, H2 se poate obţine prin interconectarea a patru copii ale lui
H1 rotite cu unghiuri drepte şi prin interconectarea punctelor izolate prin segmente de
aceeaşi lungime.
Generalizând, o curbă Hn rezultă din patru copii ale unei curbe Hn-1, punctele
izolate fiind unite prin segmente de lungime hn=h/2n. Curbele rezultate se numesc
curbele Hilbert Hi, i ≥ 0.

H1 H2 H3
Dacă cele patru părţi ale unei curbe Hilbert Hk sunt notate A, B, C, D şi se
reprezintă prin săgeţi rutinele care desenează segmentele care le interconectează,
atunci rezultă următoarele scheme recursive.

A: D ← A↓ A→ B

B: C↑B→B↓ A

C: B→C↑C ←D

D: A↓ D ← D↑C

Programul următor desenează curbele Hilbert H4.

uses graph;
const n=4;h0=212;
var
i,h,x,y,x0,y0:integer;
GD,GM:integer;
procedure B(i:integer);forward;
procedure D(i:integer);forward;
procedure C(i:integer);forward;
procedure A(i:integer);
begin
if i>0 then

77
Programarea calculatoarelor. Aplicaţii

begin
D(i-1); x:=x-h;
Lineto(x,y);
A(i-1); y:=y-h;
Lineto(x,y);
A(i-1); x:=x+h;
Lineto(x,y);
B(i-1);
end;
end;
procedure B(i:integer);
begin
if i>0 then
begin
C(i-1); y:=y+h;
Lineto(x,y);
B(i-1); x:=x+h;
Lineto(x,y);
B(i-1); y:=y-h;
Lineto(x,y);
A(i-1);
end;
end;

procedure C(i:integer);
begin
if i>0 then
begin
B(i-1); x:=x+h;
Lineto(x,y);
C(i-1); y:=y+h;
Lineto(x,y);
C(i-1); x:=x-h;
Lineto(x,y);
D(i-1);
end;
end;
procedure D(i:integer);
begin
if i>0 then
begin
A(i-1); y:=y-h;
Lineto(x,y);
D(i-1); x:=x-h;
Lineto(x,y);
D(i-1); y:=y+h;
Lineto(x,y);
C(i-1);
end;
end;
begin
GD:=Detect;
Initgraph(GD,GM,'c:\pascal6\bgi');
SetBkColor(BLACK);SetColor(RED);
i:=0;h:=h0;
x0:=h div 2;
y0:=x0;
repeat
inc(i);
h:=h div 2;
x0:=x0+(h div 2);
78
Reprezentarea vizuală a datelor

y0:=y0+(h div 2);


x:=x0;y:=y0;
Moveto(x,y);
A(i);
until i=n;
readln;
end.

Rezultatul execuţiei programului este figurat în 6.1.

Problema 5. Scrieţi un program Pascal pentru desenarea curbelor Sierpinski


S4.
În cazul curbelor Hilbert, toate unghiurile determinate de segmentele care
unesc punctele sunt de măsură 900. Dacă se consideră ca valori pentru măsurile
unghiurilor determinate de aceste segmente 450, 900, 1350, rezultă curbele Sierpinski
Sn, n ≥ 1.
Recursia pentru obţinerea curbelor Sierpinski poate fi descrisă astfel.

S: A B C D

A: A B⇒D A

B: B C⇓ A B

C: C D ⇐B C

D: D A⇑ C D

unde săgeţile duble indică segmente de lungime 2h.

79
Programarea calculatoarelor. Aplicaţii

Fig. 6.1. - Curbele Hilbert H4.

Următorul program desenează curbele Sierpinski S4.

uses graph;
const n=4;h0=412;
var
i,h,x,y,x0,y0:integer;
GD,GM:integer;
procedure B(i:integer);forward;
procedure D(i:integer);forward;
procedure C(i:integer);forward;
procedure A(i:integer);
begin
if i>0 then
begin
A(i-1);
x:=x+h;y:=y-h;
Lineto(x,y);
B(i-1);
x:=x+2*h;
Lineto(x,y);
D(i-1);
x:=x+h;y:=y+h;
Lineto(x,y);
A(i-1);
end;

80
Reprezentarea vizuală a datelor

end;

procedure B(i:integer);
begin
if i>0 then
begin
B(i-1);
x:=x-h;y:=y-h;
Lineto(x,y);
C(i-1);
y:=y-2*h;
Lineto(x,y);
A(i-1);
x:=x+h;y:=y-h;
Lineto(x,y);
B(i-1);
end;
end;
procedure C(i:integer);
begin
if i>0 then
begin
C(i-1);
x:=x-h;y:=y+h;
Lineto(x,y);
D(i-1);
x:=x-2*h;Lineto(x,y);
B(i-1);
x:=x-h;y:=y-h;
Lineto(x,y);
C(i-1);
end;
end;
procedure D(i:integer);
begin
if i>0 then
begin
D(i-1);
x:=x+h;y:=y+h;
Lineto(x,y);
A(i-1);
y:=y+2*h;Lineto(x,y);
C(i-1);
x:=x-h;y:=y+h;
Lineto(x,y);
D(i-1);
end;
end;

begin
GD:=Detect;
Initgraph(GD,GM,'c:\pascal6\bgi');
SetBkColor(15);
SetColor(7);
i:=0;
h:=h0 div 4;
x0:=2*h;
y0:=3*h;
repeat
inc(i);
81
Programarea calculatoarelor. Aplicaţii

x0:=x0-h;
h:=h div 2;
y0:=y0+h;
x:=x0;y:=y0; Moveto(x,y);
A(i);x:=x+h;y:=y-h;
Lineto(x,y);
B(i);x:=x-h;y:=y-h;
Lineto(x,y);
C(i);x:=x-h;y:=y+h;
Lineto(x,y);
D(i);x:=x+h;y:=y+h;
Lineto(x,y);
until i=n;
readln;
end.

Problema 6. Scrieţi un program pentru obţinerea tututor tipurilor de haşuri,


considerând numai culorile alb şi negru.

Program HashTip:
Uses Graph;
CONST
MatTxt:Array [1..2,1..6] Of String[10]=
(('Empty','Solid','Line','LtSlash','Slash','BkSlash'),
('LtBkSlash','Hatch','Interleave','WideDot','CloseDot'));
VAR
I,J,X,Y:Integer;
Gr,Grmode:Integer;
BEGIN
Gr:=Detect;
InitGraph(Gr,Grmode,'C:\Tp\Bgi')
ClearDevice;
SetBkColor(0);
SetColor(15);
SetTextStyle(SmallFont,HorizDir,4);
SetTextJustify(CenterText,CenterText);
V:=20;
For I:=1 to 2 do
BEGIN
X:=50;
For J:=1 to 6 do
BEGIN
Set(FillStyle(6∗(I-1)+J-1,15);
Rectangle(x-1,y-1,x+41,y+31);
Bar(x,y,z+10,y+30);
OutTextXY((x+20),Y+40,MatTxt[I,J]);
X:=X+60;
End;
Y:=Y+60;
End;
X:=X div 2 -35;
Rectangle(x-1,y-1,x+11,y+31);
Bar(X,Y,X+10,Y+30);
OutTextXY(X+15,Y+10,'User');
Readln;
END.

Problema 7. Scrieţi un program Pascal pentru realizarea unei histograme a


producţiei de oţel pe n≤10 ani.

82
Reprezentarea vizuală a datelor

Se presupune vizorul maxim. Dacă h este înălţimea în pixeli admisibilă


pentru bara care corespunde producţiei maxime, atunci coeficientul întreg de scală,
k=h/Pmax, permite determinarea înălţimii unei bare oarecare ca Round(P(i)∗k), unde
P(i) este producţia anului i. Dacă barele se desenează pe linia orizontală Baza, cu
lăţimea Lat, grosimea Gros şi la distanţa Dist, exprimate în pixeli, atunci
coorodnatele feţei exterioare a unei bare se poate determina recursiv prin relaţiile:
x1:=x2+Dist
y1:=Baza-Round(P(i)∗k);
x2:=x1+Lat;
y2:=Baza;
unde: x2:=PStart, pentru început.
Barele se haşurează şi colorează diferit. Deasupra fiecărei bare, la distanţa
Peste de aceasta, se scrie centrat mărimea producţiei pe care o reprezintă. Punctul în
care se face centrarea numărului este (x1+Lat Div 2, y1-Peste+1). Sub fiecare bară,
la distanţa Sub de linia bazelor, se scrie centrat, în punctul (x1+Lat Div 2,
y2+Sub+1), anul corespunzător. Linia bazelor se trasează, ca linie triplă, între
punctele (PStart,y2) şi ((N+1)∗(Lat+Dist),y2).

Program Histobar;
Uses Graph;
Const
H=100; Baza=250; Lat=30; Dist=30; Gros=10;
Peste=40; Sub=5; Pstart=-5;
Pattern:Integer=1; Color:Integer=1;
Font:Integer=3; CharSize:Integer=3;
Titlx=10; Titly=10;
Type
Vector=Array [1..10] of Word;
Var
An, Driver, Mode, Err, X1, Y1, X2, Y2:Integer;
Pmax:Word;
P:Vector;
K:Real;
PStr:String[8];
AnStr:String[4];
N,I:Byte;
Function MaxP(Prod:Vector;N:Byte):Word;
Var
I:Byte; M:Word;
Begin
M:=Prod[1];
For I:=2 to N do
If M < Prod[I] then
M:=Prod[I];
MaxP:=M;
End;
Begin
Write ('Numar de ani (<=10):');
Readln(N);
Write ('Primul an al seriei:');
Readln(An);
Writeln ('Productiile pe ani:');
For I:=1 to N do

83
Programarea calculatoarelor. Aplicaţii

Readln (P[I]);
Pmax:=MaxP(P,N);
K:=H/Pmax;
Driver:=Detect;
InitGraph(Driver,Mode,'C:\Tp\Bgi');
Err:=GraphResult;
If Err < > GrOk then
Begin
Writeln ('Eroare:', GraphErrorMsg(Err));
Halt;
End;
Y2:=Baza; X2:=Pstart;
ClearDevice;
SetTextStyle(Font,HorizDir,CharSize);
SetTextJustify(LeftText,TopText);
OutTextXY(Titlx,Titly,'Histograma productiei de otel (Mii
tone)');
CharSize:=1;
SetTextJustify(CenterText,TopText);
SetTextStyle(Font,HorizDir,CharSize);
For I:=1 to N do
Begin
X1:=X2+Dist;Y1:=Baza-Round(P[I]∗K);
X2:=X1+Lat;
Pattern:=Pattern+1;
SetFillStyle(Pattern,Color);
Color:=Color+1;
Bar3D(X1,Y1,X2,Y2,Gros,TopOn);
Str(P[I]:8,PStr);
OutTextXY(X1+Lat div 2, Y1-Peste+1, PStr);
Str(An:4,AnStr);
OutTextXY(x1+Lat div 2,y2+Sub+1, AnStr);
An:=An+1
End;
SetLineStyle(0, 0, 3);
Line(PStart,Y2,(N+1)∗(Lat+Dist),Y2);
ReadLn;
End.

Rezultatul execuţiei programului este prezentat în figura 6.2.

Fig. 6.2. - Histogramă prin bare.

84
Reprezentarea vizuală a datelor

Problema 8. Să se realizeze animarea unui cerc, pe tot ecranul, cu mişcarea


lui în direcţie orizontală sau verticală, dată de apăsarea tastelor săgeţi, atâta timp cât
ele sunt apăsate.
Iniţial cercul se găseşte în centrul ecranului şi poate fi deplasat în orice
direcţie, eventual, cu ieşire şi revenire în ecran. La fiecare apăsare pe o tastă săgeată
se face o deplasare cu 8 pixeli.

Program AnimCerc;
Uses Graph,CRT;
Var
Ch1,Ch2:Char;
Sz:Word;
Oprire:Boolean;
Driver,Mode,I,Xp,Yp,Xc,Yc,Err:Integer;
P:Pointer;
Begin
Driver:=Detect;
InitGraph(driver,Mode,'C:\TP\Bgi');
Err:=GraphResult;
If Err <> GrOk then
Begin
Writeln('Eroare:',GraphErrorMsg(Err));
Halt;
End;
ClearDevice;
Xp:=GetMaxX div 2; Yp:=GetmaxY div 2;
Circle(Xp,Yp,50);
Xp:=Xp-50; Yp:=Yp-50;
Sz:=ImageSize(Xp,Yp,Xp+100,Yp+100);
GetMem(P,Sz);
GetImage(Xp,Yp,Xp+100,Yp+100,P^);
Ch1:=ReadKey;
Oprire:=False;
While Not Oprire do
Begin
If Ch1=#13 then { Enter }
Oprire:=True
else
Begin
If Ch1=#0 then
Begin
Ch2:=ReadKey;
Case Ch2 of
#72: Yc:=Yp-8;
#75: Xc:=Xp-8;
#77: Xc:=Xp+8;
#80: Yc:=Yp+8;
End;
PutImage(Xp,Yp,P^,XORPut);
PutImage(Xc,Yc,P^,COPYPut);
Xp:=Xc; Yp:=Yc;
End;
Ch1:=ReadKey;
End;
End;
Readln;
End.

85
Programarea calculatoarelor. Aplicaţii

Exerciţii

1. Scrieţi un program pentru realizarea unui meniu cu trei opţiuni: execuţia


primelor două opţiuni determină afişarea a două mesaje şi ultima opţiune determină
părăsirea programului.
2. Scrieţi un program pentru realizarea unui meniu cu 4 opţiuni: prin
intermediul primelor sunt apelate proceduri de desenare a câte unei figuri geometrice,
ultima opţiune fiind părăsirea programului de către utilizator.
3. Scrieţi un program pentru trasarea graficului unei funcţii.
4. Scrieţi un program pentru desenarea curbelor Hilbert H3.
5. Scrieţi un program pentru desenarea curbelor Sierpinski S3.
6. Scrieţi un program pentru desenarea unei histograme a mediilor obţinute
la bacalaureat pentru n promoţii de absolvenţi, n≤15.
7. Scrieţi programul pentru animarea unei figuri geometrice predefinite, cu
mişcarea lui în direcţie orizontală sau verticală, dată de apăsarea tastelor săgeţi.

86
7. OBIECTE ÎN PASCAL

Problema 1. Scrieţi un unit-ul corespunzător clasei Ccomplexe (vezi


capitolul 10 din cartea Programarea calculatoarelor. Tehnica programării în
limbajul Pascal). Atributele clasei sunt private, ele putând fi accesate exclusiv prin
intermediul funcţiilor de tip accesoriu get_x şi get_y.

unit complex;

interface
type
ccomplexe=object
function get_r:real;
function get_im:real;
procedure init(r,i:real);
procedure conjugat(var b:ccomplexe);
function modul:real;
procedure suma(b:ccomplexe;var c:ccomplexe);
procedure dif(b:ccomplexe;var c:ccomplexe);
procedure produs(b:ccomplexe;var c:ccomplexe);
procedure raport(b:ccomplexe;var c:ccomplexe;
var p:boolean);
private
p_reala,p_imaginara:real;
procedure minus(var b:ccomplexe);
function zero:boolean;
end;
implementation
procedure ccomplexe.conjugat(var b:ccomplexe);
begin
b.p_reala:=p_reala;
b.p_imaginara:=-p_imaginara;
end;
function ccomplexe.get_r:real;
begin
get_r:=p_reala;
end;
function ccomplexe.get_im:real;
begin
get_im:=p_imaginara;

87
Programarea calculatoarelor. Aplicaţii

end;

procedure ccomplexe.init(r,i:real);
begin
p_reala:=r;
p_imaginara:=i;
end;
function ccomplexe.modul:real;
begin
modul:=sqrt(p_reala*p_reala+p_imaginara*p_imaginara);
end;
procedure ccomplexe.suma(b:ccomplexe;var c:ccomplexe);
begin
c.p_reala:=b.p_reala+p_reala;
c.p_imaginara:=b.p_imaginara+p_imaginara;
end;
procedure ccomplexe.minus(var b:ccomplexe);
begin
b.p_reala:=-p_reala;
b.p_imaginara:=-p_imaginara;
end;

procedure ccomplexe.dif(b:ccomplexe;var c:ccomplexe);


var
d:ccomplexe;
begin
b.minus(d);
suma(d,c);
end;

procedure ccomplexe.produs(b:ccomplexe;var c:ccomplexe);


begin
c.p_reala:=b.p_reala*p_reala-b.p_imaginara*p_imaginara;
c.p_imaginara:=b.p_reala*p_imaginara+b.p_imaginara*p_reala;
end;
function ccomplexe.zero:boolean;
begin
zero:=(p_reala=0)and(p_imaginara=0);
end;
procedure ccomplexe.raport(b:ccomplexe;var c:ccomplexe;
var p:boolean);
var
d:ccomplexe;
r:real;
begin
if not b.zero then
begin
r:=b.modul;
b.conjugat(d);
produs(d,c);
c.p_reala:=c.p_reala/sqr(r);
c.p_imaginara:=c.p_imaginara/sqr(r);
p:=true
end
else p:=false;
end;
end.

88
Obiecte în Pascal

Problema 2. Utilizând unitatea descrisă în problema 1, să se construiască o


clasă vectc, cu atributele:
1. referinţă la un vector de numere complexe cu maxim 50 componente;
2. dimensiunea vectorului a cărui adresă este memorată în primul atribut
şi metodele publice
1. constructor;
2. destructor;
3. o procedură de tip accesoriu;
4. o procedură pentru sortarea vectorului crescător după modulul fiecărui
element.

unit op_vect;
interface
uses complex;
type
vect_c=array[1..50]of ccomplexe;
vectc=object
constructor initv;
procedure sort_module;
destructor delv;
procedure getv;
private
pv:^vect_c;
dim:byte;
end;

implementation
constructor vectc.initv;
var
i:byte;r,im:real;
begin
writeln('Dimensiunea:');
readln(dim);
getmem(pv,dim*sizeof(ccomplexe));
for i:=1 to dim do
begin
write('RE(v[',i,'])=');
readln(r);
write('IM(v[',i,'])=');
readln(im);
pv^[i].init(r,im);
end;
end;
destructor vectc.delv;
begin
freemem(pv,dim*sizeof(ccomplexe));
end;
procedure vectc.getv;
var
i:byte;
begin
writeln('vectorul:');
for i:=1 to dim do
writeln(pv^[i].get_r:7:2,'+i* ',pv^[i].get_im:7:2);
end;

89
Programarea calculatoarelor. Aplicaţii

procedure vectc.sort_module;
var
i,j:byte;
a:ccomplexe;
begin
for i:=1 to dim-1 do
for j:=i+1 to dim do
if pv^[i].modul>pv^[j].modul then
begin
a:=pv^[i];
pv^[i]:=pv^[j];
pv^[j]:=a;
end;
end;
end.

Problema 3. Implementaţi o structură de stivă utilizând programarea


orientată obiect.
Vor fi utilizate clasele TipNod şi TipStiva, astfel:
Clasa TipNod defineşte structura unui obiect de tip nod şi funcţionalitatea
minimă a obiectelor. Atributele (private) sunt referinţe: una spre un alt nod, iar
cealaltă spre informaţia ataşată nodului.
Constructorul InitNod îşi preia informaţia de la consolă şi iniţializează
spaţiul pentru legătura nodului curent cu valoarea nil.
Procedura LegNod primeşte o referinţă la nodul precedent şi leagă de el
nodul curent.
Funcţia Det_leg este de tip accesoriu şi returnează câmpul de legătură al
nodului curent.
Procedura ScrieInf scrie la consolă informaţia din nodul curent.
Clasa TipStiva este un cod general, aplicabil pentru orice obiect TipNod. Este
suficient să se schimbe calsa TipNod pentru a obţine o structură nouă de tip coadă.
Procedura constructor InitStiva stabileşte valorea pointer-ului de început al
structurii pentru stiva vidă.
Procedura Pop înserează un nou obiect în stivă. la spatele cozii, utilizând
procedura LegNod, metodă a clasei TipNod. Procedura alocă spaţiu pentru nod şi îl
iniţializează. De remarcat, în acest sens, modul de utilizare a funcţiei New.
Procedura Push elimină primul nod al stivei. Din motive care ţin de
posibilitatea de a asigura testarea, înainte de a şterge nodul se afişează informaţia pe
care o conţine. Afişarea informaţiei este realizată prin intermediul funcţiei accesoriu
ScrieInf, membru al clasei TipNod.
Dacă, după executarea unor operaţii individuale de eliminare a nodurilor, se
doreşte eliberarea restului stivei, se poate utiliza destructorul DelStiva. Se observă că
un destructor poate avea conţinutul pe care îl doreşte programatorul.
Procedura ScrieStiva permite afişarea vectorului de informaţii asociat stivei.

1. Clasa TipNod

unit nod;

90
Obiecte în Pascal

interface
type
PtNod=^TipNod;
TipNod=object
Constructor InitNod;
Procedure LegNod(Urm:PtNod);
function Det_leg:PtNod;
Procedure ScrieInf;
private
info:real;
leg:PtNod;
end;
implementation
Constructor TipNod.InitNod;
begin
readln(info);
leg:=nil;
end;
Procedure TipNod.LegNod;
begin
leg:=Urm;
end;

Function TipNod.Det_leg;
begin
Det_leg:=leg;
end;
Procedure TipNod.ScrieInf;
begin
writeln(info);
end;
end.

2. Clasa TipStiva

unit stiva;
interface
uses nod;
type
PtStiva=^TipStiva;
TipStiva=object
Constructor InitStiva;
Procedure Pop;
Procedure Push;
Procedure ScrieStiva;
Destructor DelStiva;
private
Head:PtNod;
end;
implementation
Constructor TipStiva.InitStiva;
begin
Head:=nil;
end;
Procedure TipStiva.Pop;

91
Programarea calculatoarelor. Aplicaţii

var
Ptr:PtNod;
begin
Ptr:=new(PtNod,InitNod);
Ptr^.LegNod(Head);
Head:=Ptr;
end;
Procedure TipStiva.Push;
var
Ptr:PtNod;
begin
if Head<>nil then
begin
Head^.ScrieInf;
Ptr:=Head;
Head:=Head^.Det_leg;
Dispose(Ptr);
end;
end;
Procedure TipStiva.ScrieStiva;
var
Ptr:PtNod;
begin
Ptr:=Head;
if Head=nil then
writeln('Stiva vida!');
while Ptr<>nil do
begin
Ptr^.ScrieInf;
Ptr:=Ptr^.Det_leg;
end;
end;
Destructor TipStiva.DelStiva;
begin
while Head<>nil do
Push;
end;

end.

3. Exemplu de test

program test;
uses stiva;
var
s:PtStiva;
r:real;
i:byte;
begin
writeln('Construim stiva cu 3 elemente:');
s:=new(PtStiva,InitStiva);
for i:=1 to 3 do
begin
s^.Pop;
s^.ScrieStiva;
end;
writeln('Golim Stiva:');
for i:=1 to 3 do

92
Obiecte în Pascal

begin
write('Elementul extras: ');
s^.Push;
writeln('Stiva este:');
s^.ScrieStiva;
readln;
end;
dispose(s,DelStiva);
end.

Problema 4. Exemplu de ierarhie


Pe baza analizei efectuate în capitolul 10 din Programarea calculatoarelor I.
Tehnica programării în limbajul Pascal, se poate deduce o ierarhie care poate fi
reprezentată prin arborele din figura 10.11 (vezi capitolul 10 din cartea Programarea
calculatoarelor. Tehnica programării în limbajul Pascal ), în care metodele au fost
notate cu majuscule. Se pun în evidenţă trei clase abstracte şi patru clase concrete
(pentru care se pot face instanţieri).
Clasa Figura introduce caracteristicile comune şi generale pentru toate
tipurile de figuri considerate. Aici, (x,y) sunt coordonatele de identificare a figurilor
(început de linie, colţ stânga sus, centru), Culoare defineşte culoarea de desen, iar
câmpul boolean EsteVizibil arată dacă figura este desenată sau nu pe ecran.
Clasa Contur stabileşte caracteristicile liniei de contur al figurii, iar clasa
Suprafaţa se referă la modul de umplere pentru figurile închise. La acestea,
constructorul INITDEFAULT asigură obiectelor claselor derivate o iniţializare
corectă, cu valori implicite: linie continuă subţire şi umplere cu culoare de fond.
Clasele concrete sunt Punct, Linie, Dreptunghi şi Cerc. La acestea, constructorii
proprii se definesc cu apel la constructorul clasei părinte, metodele virtuale ale
strămoşilor sunt redefinite corespunzător, iar aria figurilor se exprimă, ca unitate de
masură, in pixeli pătraţi.
Având în vedere caracterul didactic al exemplului, pentru simplificarea
metodelor, se presupune că figurile sunt disjuncte pe spaţiul de desenare. Se evită
astfel complicaţiile de refacere a imaginilor suprapuse şi figurile pot fi afişate şi
ascunse în orice ordine. Pentru a permite desenarea conturului şi/sau umplerea
figurilor şi în cazul când linia utilizată nu este continuă, s-a aplicat tehnica de
redesenare, cu haşurare a interiorului. Ascunderea unei figuri se realizează fie prin
redesenare şi umplere cu culoarea de fond, fie prin încadrarea într-un vizor care se
şterge cu această culoare.
Intrarea în regimul grafic şi închiderea acestuia trebuie gestionate de unitatea
de program apelatoare, prin intermediul variabilei globale InGrafic. Variabila este
setată implicit la valoarea False, ceea ce va determina deschiderea regimului grafic în
unitatea UFigura, la prima solicitare de afişare a unei figuri. Dacă unitatea apelatoare
a deschis regimul grafic, atunci aceasta trebuie să atribuie variabilei InGrafic
valoarea True.
Programul de testare TFigura a unităţii de program PFigura utilizează
obiecte statice şi o referinţa la clasa originară. Se verifică, prin apel, funcţionarea
corectă a constructorilor, a procedurilor de schimbare de proprietăţi, de desenare şi

93
Programarea calculatoarelor. Aplicaţii

ascundere. În finalul programului, se testează funcţia de calcul al ariei pentru cerc şi


dreptunghi, utilizând legarea dinamică.
Modelul rezolvării (netestat ca program) este prezentat în continuare.

Program TFigura;
Uses Ufigura,CRT,Graph;
VAR
pf:PFigura;
lin:Linie;
drp:Dreptunghi;
crc:Cerc;
a,b:Integer;
ar:Real;
arstring:String[10];
Begin
{ Linie continua, de culoare implicita, care se
afiseaza, ascunde si se reafiseaza }
lin.INIT(80,10,150,10);
lin.AFISEAZA; Delay(2000);
lin.ASCUNDE; Delay(1000);
lin.AFISEAZA;
{ Cerc cu contur continuu, de culoare rosie }
a:=250; b:=250;
crc.INIT(a,b,100);
crc.SCHIMBACULOARE(Red);
crc.SCHIMBACONTUR(SolidLn,3);
crc.SCHIMBAUMPLERE(1,White);
crc.AFISEAZA;Delay(2000);
crc.ASCUNDE; Delay(3000);
crc.AFISEAZA;

{ Dreptunghi cu contur linie intrerupta, culoare rosie si


umplut cu albastru }
drp.INIT(80,20,70,80);
drp.SCHIMBACONTUR(DashedLn,3);
drp.SCHIMBAUMPLERE(1,Blue);
drp.AFISEAZA; Delay(2000);
drp.ASCUNDE; Delay(3000);
drp.AFISEAZA;
{ Polimorfism in determinarea ariei cercului si
dreptunghiului}
pf:=Addr(crc);
ar:=pf^.ARIE;
str(ar:10:2,arstring);
OutTextXY(a,b+120,'Arie cerc='+arstring);
pf:=Addr(drp);
ar:=pf^.ARIE;
str(ar:10:2,arstring);
OutTextXY(160,60,'Arie dreptunghi='+arstring);
readln;
CloseGraph;
End.

Unit Ufigura;
INTERFACE
Uses Graph;
CONST
InGrafic:Boolean=False;
TYPE

94
Obiecte în Pascal

{----------Clasa Figura-------------------------------}
PFigura=^Figura;
Figura=OBJECT
x,y:Integer;
EsteVizibil:Boolean;
Culoare:Word;
Constructor INIT(x0,y0:Integer);
Procedure AFISEAZA; VIRTUAL;
Procedure ASCUNDE; VIRTUAL;
Function ARIE:Real; VIRTUAL;
Procedure SCHIMBACULOARE(Cul:Word);
END;
{----------Clasa Punct-------------------------------}
PPunct=^Punct;
Punct=OBJECT(Figura)
Procedure AFISEAZA; VIRTUAL;
Procedure ASCUNDE; VIRTUAL;
END;
{----------Clasa Contur------------------------------}
PContur=^Contur;
Contur=OBJECT(Figura)
TipLinie:Word;
Grosime:Word;
Constructor INITDEFAULT(x0,y0:Integer);
Procedure SCHIMBACONTUR(TipL,GrosL:Word);
END;
{---------Clasa Linie--------------------------------}
PLinie=^Linie;
Linie=OBJECT(Contur)
XSfirsit,YSfirsit:Integer;
Constructor INIT(x0,y0,x1,y1:Integer);
Procedure AFISEAZA; VIRTUAL;
Procedure ASCUNDE; VIRTUAL;
END;
{---------Clasa Suprafata----------------------------}
PSuprafata=^Suprafata;
Suprafata=OBJECT(Contur)
TipHasura:Word;
CuloareUmplere:Word;
Constructor INITDEFAULT(x0,y0:Integer);
Procedure SCHIMBAUMPLERE(TipH,TipC:Word);
END;
{---------Clasa Dreptunghi---------------------------}
PDreptunghi=^Dreptunghi;
Dreptunghi=OBJECT(Suprafata)
Latime,Inaltime:Integer;
Constructor INIT(x0,y0,Lat,Inalt:Integer);
Procedure AFISEAZA; VIRTUAL;
Procedure ASCUNDE; VIRTUAL;
Function ARIE:Real; VIRTUAL;
END;

{------Clasa Cerc------------------------------------}
PCerc=^Cerc;
Cerc=OBJECT(Suprafata)
Raza:Word;
Constructor INIT(x0,y0,R:Integer);
Procedure AFISEAZA; VIRTUAL;
95
Programarea calculatoarelor. Aplicaţii

Procedure ASCUNDE; VIRTUAL;


Function ARIE:Real; VIRTUAL;
END;
IMPLEMENTATION
Procedure INTRAINGRAFIC;
VAR
err,mode,submode:Integer;
Begin
mode:=DETECT;
InitGraph(mode,submode,'c:\bpcopy\bp\bgi');
err:=GraphResult;
If (err=GrOk)then
InGrafic:=True
else begin
WriteLn('* Eroare * ',GraphErrorMsg(err));
Halt(1);
end;
End;
{------Implementare Clasa Figura---------------------}
Constructor Figura.INIT;
Begin
x:=x0;
y:=y0;
EsteVizibil:=False;
Culoare:=White;
End;
Procedure Figura.AFISEAZA;
Begin
End;

Procedure Figura.ASCUNDE;
Begin
End;
Function Figura.ARIE;
Begin
ARIE:=0;
End;

Procedure Figura.SCHIMBACULOARE;
Begin
Culoare:=Cul;
End;
{------Implementare Clasa Punct----------------------}
Procedure Punct.AFISEAZA;
Begin
If Not InGrafic then
INTRAINGRAFIC;
PutPixel(x,y,Culoare);
EsteVizibil:=True;
End;
Procedure Punct.ASCUNDE;
Begin
If EsteVizibil then
begin
PutPixel(x,y,GetBkColor);
EsteVizibil:=False;
end;
96
Obiecte în Pascal

End;

{------Implementare Clasa Contur---------------------}


Constructor Contur.INITDEFAULT;
Begin
Figura.INIT(x0,y0);
TipLinie:=SolidLn;
Grosime:=1;
End;

Procedure Contur.SCHIMBACONTUR;
Begin
TipLinie:=TipL;
Grosime:=GrosL;
End;
{------Implementare Clasa Linie----------------------}
Constructor Linie.INIT;
Begin
Figura.INIT(x0,y0);
XSfirsit:=x1;
YSfirsit:=y1;
End;
Procedure Linie.AFISEAZA;
Begin
If Not InGrafic then
INTRAINGRAFIC;
SetLineStyle(TipLinie,0,Grosime);
SetColor(Culoare);
Line(x,y,XSfirsit,YSfirsit);
EsteVizibil:=True;
End;

Procedure Linie.ASCUNDE;
Begin
If EsteVizibil then
begin
SetLineStyle(TipLinie,0,Grosime);
SetColor(GetBkColor);
Line(x,y,XSfirsit,YSfirsit);
EsteVizibil:=False;
end;
End;
{------Implementare Clasa Suprafata------------------}
Constructor Suprafata.INITDEFAULT;
Begin
Contur.INITDEFAULT(x0,y0);
TipHasura:=EmptyFill;
CuloareUmplere:=Black;
End;
Procedure Suprafata.SCHIMBAUMPLERE;
Begin
TipHasura:=TipH;
CuloareUmplere:=TipC;
End;
{------Implementare Clasa Dreptunghi-----------------}
Constructor Dreptunghi.INIT;
Begin
Suprafata.INITDEFAULT(x0,y0);
97
Programarea calculatoarelor. Aplicaţii

Latime:=Lat;
Inaltime:=Inalt;
End;
Procedure Dreptunghi.AFISEAZA;
Begin
If Not InGrafic then
INTRAINGRAFIC;
SetFillStyle(TipHasura,CuloareUmplere);
SetLineStyle(TipLinie,0,Grosime);
SetColor(Culoare);
Bar(x,y,x+Latime,y+Inaltime);
Rectangle(x,y,x+Latime,y+Inaltime);
EsteVizibil:=True;
End;
Procedure Dreptunghi.ASCUNDE;
Begin
If EsteVizibil then
begin
SetViewport(x-1,y-1,x+Latime+1,y+Inaltime+1,ClipOn);
ClearViewport;
SetViewport(0,0,GetMaxX,GetMaxY,ClipOn);
EsteVizibil:=True;
end;
End;
Function Dreptunghi.ARIE;
Begin
ARIE:=Latime*Inaltime;
End;
{------Implementare Clasa Cerc-----------------------}
Constructor Cerc.INIT;
Begin
Suprafata.INITDEFAULT(x0,y0);
Raza:=R;
End;
Procedure Cerc.ASCUNDE;
Begin
If EsteVizibil then
begin
SetLineStyle(TipLinie,0,Grosime);
SetColor(GetBkColor);
SetFillStyle(SolidFill,GetBkColor);
PieSlice(x,y,0,360,Raza+1);
EsteVizibil:=False;
end;
End;
Procedure Cerc.AFISEAZA;
Begin
If Not InGrafic then INTRAINGRAFIC;
SetLineStyle(TipLinie,0,Grosime);
SetColor(Culoare);
SetFillStyle(TipHasura,CuloareUmplere);
PieSlice(x,y,0,360,Raza);
Circle(x,y,Raza);
EsteVizibil:=True;
End;
Function Cerc.ARIE;
Begin
98
Obiecte în Pascal

ARIE:=PI*Raza*Raza;
End;
END.

Exerciţii

1. Scrieţi un unit Pascal pentru implementarea unei clase vector, în care să fie
cuprinse operaţiile uzuale asupra vectorilor de numere reale (sortare, căutare,
interclasare).
2. Scrieţi un unit Pascal pentru implementarea unei clase matrice, în care să
fie cuprinse operaţiile uzuale asupra matricelor de numere reale (calculul transpusei
unei matrice, suma şi produsul a două matrice, calculul determinantului şi inversei
unei matrice, verificarea faptului că matricea este pătratică, verificarea proprietăţii de
simetrie a unei matrice).
3. Scrieţi un unit Pascal pentru lucrul cu obiecte dinamice în cazul clasei
vector.
4. Scrieţi un unit Pascal pentru lucrul cu obiecte dinamice în cazul clasei
matrice.
5. Utilizând clasa Ccomplexe, scrieţi un unit Pascal pentru implementarea
unei clase matrice de numere complexe, cu operaţiile de adunare, înmulţire şi ridicare
la putere a unei matrice. Atributul de caracterizare a matricei este dinamic.
6. Scrieţi un unit pentru implementarea orientată obiect a structurii de coadă.
7. Scrieţi un unit Pascal pentru implementarea orientată obiect a structurii de
listă. Operaţiile elementare sunt: parcurgerea, căutarea unei element, inserarea şi
extragerea unui element în/din poziţia p.

99
BIBLIOGRAFIE

1. Apostol C., Roşca I. Gh., Ghilic-Micu B., Roşca V., Introducere în


programare. Teorie şi practică Pascal, Casa de editură şi presă Viaţa
Românească, Bucureşti, 1993
2. Apostol C., Roşca I. Gh., Ghilic-Micu B., Roşca V., Prelucrarea fişierelor
în Pascal, Editura Tehnică, Bucureşti, 1994
3. Ionescu A., Cocianu C., Fundamentele programării. Probleme rezolvate şi
propuse, Editura ASE, Bucureşti 2000
4. Findlay W., Watt D., Pascal. An Introduction to Methodical
Programming, Pitman Publishing, 1987
5. Knuth D., The Art of Computer Programming, Vol. 2, Seminumerical
Algorithms, Addison-Wesley, 1981
6. Knuth D., The Art of Computer Programming, Vol. 3, Sortind and
Searching, Addison-Wesley, 1981
7. Roşca I. Gh., Apostol C., Ghilic-Micu B., Roşca V., Programare
sistematică în Pascal, Editura Didactică şi Pedagogică, Bucureşti, 1998
8. Roşca I. Gh., Apostol C., Ghilic-Micu B., Stoica M., Cocianu C., Uscatu
C., Bazele elaborării programelor. Exerciţii rezolvate şi propuse, Editura
ASE, Bucureşti 1999

100