Sunteți pe pagina 1din 133

VALERIU LUPU

ALGORITMI. TEHNICI I
LIMBAJE DE PROGRAMARE

EDITURA UNIVERSITII TEFAN cel MARE SUCEAVA


2007

Prefa
Cartea isi propune in primul rand sa fie un curs si nu o "enciclopedie" de algoritmi. Pornind de la structurile de date
cele mai uzuale si de la analiza eficientei algoritmilor, cartea se concentreaza pe principiile fundamentale de elaborare a
algoritmilor: greedy, divide et impera, programare dinamica, backtracking. Majoritatea algoritmilor selectati au o conotatie
estetica. Efortul necesar pentru intelegerea elementelor mai subtile este uneori considerabil. Ce este insa un algoritm "estetic"?
Putem raspunde foarte simplu: un algoritm este estetic daca exprima mult in cuvinte putine. Un algoritm estetic este oare in
mod necesar si eficient? Cartea raspunde si acestor intrebari.
In al doilea rand, cartea prezinta mecanismele interne esentiale ale limbajului Visual Basic si trateaza implementarea
algoritmilor in mod iterative cat si recursiv. Totusi, aceasta carte nu este un curs complet de Visual Basic. Algoritmii nu sunt
pur si simplu "transcrisi" din pseudo-cod in limbajul Visual Basic, ci sunt reganditi din punct de vedere al programarii orientate
pe obiect. Speram ca, dupa citirea cartii, veti dezvolta aplicatii de programare in mod iterative cat si recursiv si veti elabora
implementari ale altor structuri de date. Programele pot fi scrise si in limbajul C#. Acest limbaj se caracterizeaza, in principal,
prin introducerea claselor parametrice si a unui mecanism de tratare a exceptiilor foarte avansat, facilitati deosebit de
importante pentru dezvoltarea de biblioteci C#.
Fara a face concesii rigorii matematice, prezentarea este intuitiva, cu numeroase exemple. Am evitat, pe cat posibil,
situatia in care o carte de informatica incepe - spre disperarea ne-matematicienilor - cu celebrul "Fie ... ", sau cu o definitie. Am
incercat, pe de alta parte, sa evitam situatia cand totul "este evident", sau "se poate demonstra". Fiecare capitol este conceput
fluid, ca o mica poveste, cu putine referinte si note. Multe rezultate mai tehnice sunt obtinute ca exercitii. Algoritmii sunt
prezentati intr-un limbaj pseudo-cod compact, fara detalii inutile.
Presupunem ca cititorul nu are la baza cel putin un curs introductiv in programare, fiindu-i straini termeni precum
algoritm, recursivitate, functie, procedura si pseudo-cod. Exista mai multe modalitati de parcurgere a cartii. In functie de
interesul si pregatirea cititorului, acesta poate alege oricare din partile referitoare la elaborarea, analiza, sau implementarea
algoritmilor. Cu exceptia partilor de analiza a eficientei algoritmilor (unde sunt necesare elemente de matematici superioare),
cartea poate fi parcursa si de catre un elev de liceu. Pentru parcurgerea sectiunilor de implementare, este recomandabila
cunoasterea limbajului Visual Basic.
S-a dovedit utila si experienta autorului de peste douzeci de ani in dezvoltarea produselor software. Le multumesc
pentru aprecieri pro/contra asupra lucrrii membrilor catedrei de informatic de la Facultatea de tiine Economice i
Administraie Public.
Autorul,
Conf. univ. dr. Lupu Valeriu
Universitatea tefan cel Mare Suceava
Facultatea de tiine Economice i Administraie Public
Catedra de Informatic

Cuprins

Capitolul I

Descrierea algoritmilor .................................................................................................6

Capitolul II

Subprograme ................................................................................................. .............16

Capitolul III

Metode de proiectare a algoritmilor ...........................................................................23

Capitolul IV

Analiza algoritmilor ...................................................................................... .............27

Capitolul V

Clase de algoritmi ........................................................................................................34

Capitolul VI

Evoluia limbajelor de programare .............................................................................41

Capitolul VII

Limbajul Visual Basic ................................................................................................55

Capitolul VIII

Reguli privind alegerea unui limbaj de programare ...................................................69

Capitolul IX

Metoda backtracking ..................................................................................................73

Capitolul X

Metoda Divide et impera ............................................................................................91

Capitolul XI

Metoda Greedy ...........................................................................................................95

Capitolul XII

Studii de caz Aplicaii ................................................................................ ...........109

Bibliografie

....................................................................................................................................135

CAPITOLUL I
DESCRIEREA ALGORITMILOR
1.1 Algoritm, program, programare
Apariia primelor calculatoare electronice a constituit un salt uria n direcia automatizrii
activitii umane. Nu exist astzi domeniu de activitate n care calculatorul s nu i arate utilitatea[18].
Calculatoarele pot fi folosite pentru a rezolva probleme, numai dac pentru rezolvarea acestora se
concep programe corespunztoare de rezolvare. Termenul de program (programare) a suferit schimbri n
scurta istorie a informaticii. Prin anii '60 problemele rezolvate cu ajutorul calculatorului erau simple i se
gseau algoritmi nu prea complicai pentru rezolvarea lor. Prin program se nelegea rezultatul scrierii
unui algoritm ntr-un limbaj de programare. Din cauza creterii complexitii problemelor, astzi pentru
rezolvarea unei probleme adesea vom concepe un sistem de mai multe programe.
Dar ce este un algoritm? O definiie matematic, riguroas, este greu de dat, chiar imposibil fr
a introduce i alte noiuni. Vom ncerca n continuare o descriere a ceea ce se nelege prin algoritm.
Ne vom familiariza cu aceast noiune prezentnd mai multe exemple de algoritmi i observnd ce
au ei n comun. Cel mai vechi exemplu este algoritmul lui Euclid, algoritm care determin cel mai mare
divizor comun a dou numere naturale. Evident, vom prezenta mai muli algoritmi, cei mai muli fiind
legai de probleme accesibile absolvenilor de liceu.
Vom constata c un algoritm este un text finit, o secven finit de propoziii ale unui limbaj. Din
cauz c este inventat special n acest scop, un astfel de limbaj este numit limbaj de descriere a
algoritmilor. Fiecare propoziie a limbajului precizeaz o anumit regul de calcul, aa cum se va
observa atunci cnd vom prezenta limbajul Pseudocod.
Oprindu-ne la semnificaia algoritmului, la efectul execuiei lui, vom observa c fiecare algoritm
definete o funcie matematic. De asemenea, din toate seciunile urmtoare va reiei foarte clar c un
algoritm este scris pentru rezolvarea unei probleme. Din mai multe exemple se va observa ns c, pentru
rezolvarea aceleai probleme, exist mai muli algoritmi.
Pentru fiecare problem P exist date presupuse cunoscute (date iniiale pentru algoritmul
corespunztor, A) i rezultate care se cer a fi gsite (date finale). Evident, problema s-ar putea s nu aib
sens pentru orice date iniiale. Vom spune c datele pentru care problema P are sens fac parte din
domeniul D al algoritmului A. Rezultatele obinute fac parte dintr-un domeniu R, astfel c executnd
algoritmul A cu datele de intrare xD vom obine rezultatele rR. Vom spune c A(x)=r i astfel
algoritmul A definete o funcie
A : D ---> R .
Algoritmii au urmtoarele caracteristici: generalitate, finitudine i unicitate.
Prin generalitate se nelege faptul c un algoritm este aplicabil pentru orice date iniiale xD.
Deci un algoritm A nu rezolv problema P cu nite date de intrare, ci o rezolv n general, oricare ar fi
aceste date. Astfel, algoritmul de rezolvare a unui sistem liniar de n ecuaii cu n necunoscute prin metoda
lui Gauss, rezolv orice sistem liniar i nu un singur sistem concret.
Prin finitudine se nelege c textul algoritmului este finit, compus dintr-un numr finit de
propoziii. Mai mult, numrul transformrilor ce trebuie aplicate unei informaii admisibile xD pentru a
obine rezultatul final corespunztor este finit.
Prin unicitate se nelege c toate transformrile prin care trece informaia iniial pentru a obine
rezultatul rR sunt bine determinate de regulile algoritmului. Aceasta nseamn c fiecare pas din
execuia algoritmului d rezultate bine determinate i precizeaz n mod unic pasul urmtor. Altfel spus,
ori de cte ori am executa algoritmul, pornind de la aceeai informaie admisibil xD, transformrile
prin care se trece i rezultatele obinute sunt aceleai.
n descrierea algoritmilor se folosesc mai multe limbaje de descriere, dintre care cele mai des
folosite sunt:
- limbajul schemelor logice;
6

- limbajul Pseudocod.
n continuare vom folosi pentru descrierea algoritmilor limbajul Pseudocod care va fi definit n
cele ce urmeaz. n ultima vreme schemele logice sunt tot mai puin folosite n descrierea algoritmilor i
nu sunt deloc potrivite n cazul problemelor complexe. Prezentm ns i schemele logice, care se mai
folosesc n manualele de liceu, ntruct cu ajutorul lor vom preciza n continuare semantica propoziiilor
Pseudocod.
1.2 Scheme logice
Schema logic este un mijloc de descriere a algoritmilor prin reprezentare grafic. Regulile de
calcul ale algoritmului sunt descrise prin blocuri (figuri geometrice) reprezentnd operaiile (paii)
algoritmului, iar ordinea lor de aplicare (succesiunea operaiilor) este indicat prin sgei. Fiecrui tip de
operaie i este consacrat o figur geometric (un bloc tip) n interiorul creia se va nscrie operaia din
pasul respectiv.
Prin execuia unui algoritm descris printr-o schem logic se nelege efectuarea tuturor
operaiilor precizate prin blocurile schemei logice, n ordinea indicat de sgei.
n descrierea unui algoritm, deci i ntr-o schem logic, intervin variabile care marcheaz att
datele cunoscute iniial, ct i rezultatele dorite, precum i alte rezultate intermediare necesare n
rezolvarea problemei. ntruct variabila joac un rol central n programare este bine s definim acest
concept. Variabila definete o mrime care i poate schimba valoarea n timp. Ea are un nume i,
eventual, o valoare. Este posibil ca variabila nc s nu fi primit valoare, situaie n care vom spune c ea
este neiniializat. Valorile pe care le poate lua variabila aparin unei mulimi D pe care o vom numi
domeniul variabilei. n concluzie vom nelege prin variabil tripletul
(nume, domeniul D, valoare)
unde valoare aparine mulimii D {nedefinit}.
Blocurile delimitatoare Start i Stop (Fig.1.2.1. a i 1.2.1. b) vor marca nceputul respectiv
sfritul unui algoritm dat printr-o schem logic. Descrierea unui algoritm prin schem logic va ncepe
cu un singur bloc Start i se va termina cu cel puin un bloc Stop.
Blocurile de intrare/ieire Citete i Tiprete (Fig. 1.2.1. c i d) indic introducerea unor Date
de intrare respectiv extragerea unor Rezultate finale. Ele permit precizarea datelor iniiale cunoscute n
problem i tiprirea rezultatelor cerute de problem. Blocul Citete iniializeaz variabilele din lista de
intrare cu valori corespunztoare, iar blocul Tiprete va preciza rezultatele obinute (la execuia pe
calculator cere afiarea pe ecran a valorilor expresiilor din lista de ieire).
Blocurile de atribuire (calcul) se utilizeaz n descrierea operaiilor de atribuire (:=). Printr-o
astfel de operaie, unei variabile var i se atribuie valoarea calculat a unei expresii expr (Fig.1.2.1. e).

Fig.1.2.1. Blocurile schemelor logice


7

Blocurile de decizie marcheaz punctele de ramificaie ale algoritmului n etapa de decizie. Ramificarea
poate fi dubl (blocul logic, Fig.1.2.1.f) sau tripl (blocul aritmetic, Fig. 1.2.1.g). Blocul de decizie logic
indic ramura pe care se va continua execuia algoritmului n funcie de ndeplinirea (ramura Da) sau
nendeplinirea (ramura Nu) unei condiii. Condiia care se va nscrie n blocul de decizie logic va fi o
expresie logic a crei valoare poate fi una dintre valorile "adevrat" sau "fals". Blocul de decizie
aritmetic va hotr ramura de continuare a algoritmului n funcie de semnul valorii expresiei aritmetice
nscrise n acest bloc, care poate fi negativ, nul sau pozitiv.
Blocurile de conectare marcheaz ntreruperile sgeilor de legtur dintre blocuri, dac din
diverse motive s-au efectuat astfel de ntreruperi (Fig.1.2.1.h).
Pentru exemplificare vom da n continuare dou scheme logice, corespunztoare unor algoritmi
pentru rezolvarea problemelor P1.2.1 i P1.2.2.
P1.2.1. S se rezolve ecuaia de grad doi aX2+bX+c=0 (a,b,cR _i a0).
Metoda de rezolvare a ecuaiei de gradul doi este cunoscut. Ecuaia poate avea rdcini reale, respectiv
complexe, situaie recunoscut dup semnul discriminantului d = b2 - 4ac.

Fig.1.2.2. Algoritm pentru rezolvarea ecuaiei de gradul doi

Fig.1.2.3. Algoritm pentru calculul


unei sume.

Algoritmul de rezolvare a problemei va citi mai nti datele problemei, marcate prin variabilele a,
b i c. Va calcula apoi discriminantul d i va continua n funcie de valoarea lui d, aa cum se poate vedea
n fig.1.2.2.
P1.2.2. S se calculeze suma elementelor pozitive ale unui ir de numere reale dat.
Schema logic (dat n Fig.1.2.3) va conine imediat dup blocul START un bloc de citire, care
precizeaz datele cunoscute n problem, apoi o parte care calculeaz suma cerut i un bloc de tiprire a
sumei gsite, naintea blocului STOP. Partea care calculeaz suma S cerut are un bloc pentru iniializarea
8

cu 0 a acestei sume, apoi blocuri pentru parcurgerea numerelor: x 1, x2xn i adunarea celor pozitive la
suma S. Pentru aceast parcurgere se folosete o variabil contor i, care este iniializat cu 1 i crete
mereu cu 1 pentru a atinge valoarea n, indicele ultimului numr dat.
Schemele logice dau o reprezentare grafic a algoritmilor cu ajutorul unor blocuri de calcul.
Execuia urmeaz sensul indicat de sgeat, putnd avea loc reveniri n orice punct din schema logic.
Din acest motiv se poate obine o schem logic nclcit, greu de urmrit. Rezult importana compunerii
unor scheme logice structurate (D-scheme, dup Djikstra), care s conin numai anumite structuri
standard de calcul i n care drumurile de la START la STOP s fie uor de urmrit.
1.3. Limbajul PSEUDOCOD
Limbajul Pseudocod este un limbaj inventat n scopul proiectrii algoritmilor i este format din
propoziii asemntoare propoziiilor limbii romne, care corespund structurilor de calcul folosite n
construirea algoritmilor. Acesta va fi limbajul folosit de noi n proiectarea algoritmilor i va fi definit n
cele ce urmeaz. innd seama c obinerea unui algoritm pentru rezolvarea unei probleme nu este
ntotdeauna o sarcin simpl, c n acest scop sunt folosite anumite metode pe care le vom descrie n
capitolele urmtoare, n etapele intermediare din obinerea algoritmului vom folosi propoziii curente din
limba romn. Acestea sunt considerate elemente nefinisate din algoritm, asupra crora trebuie s se
revin i le vom numi propoziii nestandard. Deci limbajul Pseudocod are dou tipuri de propoziii:
propoziii standard, care vor fi prezentate fiecare cu sintaxa i semnificaia (semantica) ei i propoziii
nestandard. Aa cum se va arta mai trziu, propoziiile nestandard sunt texte care descriu pri ale
algoritmului nc incomplet elaborate, nefinisate, asupra crora urmeaz s se revin.
Pe lng aceste propoziii standard i nestandard, n textul algoritmului vom mai introduce
propoziii explicative, numite comentarii. Pentru a le distinge de celelalte propoziii, comentariile vor fi
nchise ntre acolade. Rolul lor va fi explicat puin mai trziu.
Propoziiile standard ale limbajului Pseudocod folosite n aceast lucrare, corespund structurilor
de calcul prezentate n figura 1.3.1 i vor fi prezentate n continuare. Fiecare propoziie standard ncepe cu
un cuvnt cheie, aa cum se va vedea n cele ce urmeaz. Pentru a deosebi aceste cuvinte de celelalte
denumiri, construite de programator, n acest capitol vom scrie cuvintele cheie cu litere mari. Menionm
c i propoziiile simple se termin cu caracterul ';' n timp ce propoziiile compuse, deci cele n interiorul
crora se afl alte propoziii, au un marcaj de sfrit propriu. De asemenea, menionm c propoziiile
limbajului Pseudocod vor fi luate n seam n ordinea ntlnirii lor n text, asemenea oricrui text al limbii
romne.
Prin execuia unui algoritm descris n Pseudocod se nelege efectuarea operaiilor precizate de
propoziiile algoritmului, n ordinea citirii lor.
n figura 1.3.1, prin A, B s-au notat subscheme logice, adic secvene de oricte structuri
construite conform celor trei reguli menionate n continuare.
Structura secvenial (fig.1.3.1.a) este redat prin concatenarea propoziiilor, simple sau
compuse, ale limbajului Pseudocod, care vor fi executate n ordinea ntlnirii lor n text.

a) structura
secvenial

b) structura
c) structura
alternativ
repetitiv
Figura 1.3.1. Structurile elementare de calcul
9

Propoziiile simple din limbajul Pseudocod sunt CITETE, TIPARETE, FIE i apelul de
subprogram. Propoziiile compuse corespund structurilor alternative i repetitive.
Structura alternativ (fig.1.3.1.b) este redat n Pseudocod prin propoziia DAC, prezentat n
seciunea 1.3.2, iar structura repetitiv din fig.1.3.1.c este redat n Pseudocod prin propoziia CT
TIMP, prezentat n seciunea 1.3.3.
Bohm i Jacopini au demonstrat c orice algoritm poate fi descris folosind numai aceste trei
structuri de calcul.
Propoziiile DATE i REZULTATE sunt folosite n faza de specificare a problemelor, adic
enunarea riguroas a acestora. Propoziia DATE se folosete pentru precizarea datelor iniiale, deci a
datelor considerate cunoscute n problem (numite i date de intrare) i are sintaxa:
DATE list;
unde list conine toate numele variabilelor a cror valoare iniial este cunoscut. n general, prin list se
nelege o succesiune de elemente de acelai fel desprite prin virgul. Deci n propoziia DATE, n
dreapta acestui cuvnt se vor scrie acele variabile care marcheaz mrimile cunoscute n problem.
Pentru precizarea rezultatelor dorite se folosete propoziia standard
REZULTATE list;
n construcia "list" ce urmeaz dup cuvntul REZULTATE fiind trecute numele variabilelor care
marcheaz (conin) rezultatele cerute n problem.
Acum putem preciza mai exact ce nelegem prin cunoaterea complet a problemei de rezolvat.
Evident, o problem este cunoscut atunci cnd se tie care sunt datele cunoscute n problem i ce
rezultate trebuiesc obinute. Deci pentru cunoaterea unei probleme este necesar precizarea variabilelor
care marcheaz date considerate cunoscute n problem, care va fi reflectat printr-o propoziie DATE i
cunoaterea exact a cerinelor problemei, care se va reflecta prin propoziii REZULTATE. Variabilele
prezente n aceste propoziii au anumite semnificaii, presupuse cunoscute. Cunoaterea acestora, scrierea
lor explicit, formeaz ceea ce vom numi n continuare specificarea problemei. Specificarea unei
probleme este o activitate foarte important dar nu i simpl.
De exemplu, pentru rezolvarea ecuaiei de gradul al doilea, specificarea problemei, scris de un
nceptor, poate fi:
DATE a,b,c;
{ Coeficienii ecuaiei }
REZULTATE x1,x2;
{ Rdcinile ecuaiei }
Aceast specificaie este ns incomplet dac ecuaia nu are rdcini reale. n cazul n care rdcinile
sunt complexe putem nota prin x1, x2 partea real respectiv partea imaginar a rdcinilor. Sau pur i
simplu, nu ne intereseaz valoarea rdcinilor n acest caz, ci doar faptul c ecuaia nu are rdcini reale.
Cu alte cuvinte avem nevoie de un mesaj care s ne indice aceast situaie (vezi schema logic 1.2.2), sau
de un indicator, fie el ind. Acest indicator va lua valoarea 1 dac rdcinile sunt reale i valoarea 0 n caz
contrar. Deci specificaia corect a problemei va fi
DATE a,b,c;
{ Coeficienii ecuaiei }
REZULTATE ind,
{Un indicator: 1=rdcini reale, 0=complexe}
x1,x2;
{ Rdcinile ecuaiei, n cazul ind=1,}
{respectiv partea real i cea }
{imaginar n cazul ind=0}
Evident c specificarea problemei este o etap important pentru gsirea unei metode de rezolvare
i apoi n proiectarea algoritmului corespunztor. Nu se poate rezolva o problem dac aceasta nu este
bine cunoscut, adic nu avem scris specificarea problemei. Cunoate complet problema este prima
regul ce trebuie respectat pentru a obine ct mai repede un algoritm corect pentru rezolvarea ei.
1.3.1 Algoritmi liniari
Propoziiile CITETE i TIPRETE sunt folosite pentru iniializarea variabilelor de intrare cu
datele cunoscute n problem, respectiv pentru tiprirea (aflarea) rezultatelor obinute. n etapa de
10

programare propriu-zis acestor propoziii le corespund ntr-un limbaj de programare instruciuni de


intrare-ieire.
Propoziia CITETE se folosete pentru precizarea datelor iniiale, deci a datelor considerate
cunoscute n problem (numite i date de intrare) i are sintaxa:
CITETE list ;
unde list conine toate numele variabilelor a cror valoare iniial este cunoscut.
Deci n propoziia CITETE, n dreapta acestui cuvnt se vor scrie acele variabile care apar n
propoziia DATE n specificarea problemei. Se subnelege c aceste variabile sunt iniializate cu valorile
cunoscute corespunztoare.
Pentru aflarea rezultatelor dorite, pe care calculatorul o va face prin tiprirea lor pe hrtie sau
afiarea pe ecran, se folosete propoziia standard
TIPRETE list ;
n construcia list ce urmeaz dup cuvntul TIPRETE fiind trecute numele variabilelor a cror
valori dorim s le aflm. Ele sunt de obicei rezultatele cerute n problem, specificate i n propoziia
REZULTATE.
Blocului de atribuire dintr-o schem logic i corespunde n Pseudocod propoziia standard
[FIE] var := expresie ;
Aceast propoziie este folosit pentru a indica un calcul algebric, al expresiei care urmeaz dup
simbolul de atribuire ":=" i de atribuire a rezultatului obinut variabilei var. Expresia din dreapta
semnului de atribuire poate fi orice expresie algebric simpl, cunoscut din manualele de matematic din
liceu i construit cu cele patru operaii: adunare, scdere, nmulire i mprire (notate prin caracterele +,
-, *, respectiv /).
Prin scrierea cuvntului FIE ntre paranteze drepte se indic posibilitatea omiterii acestui cuvnt
din propoziie. El s-a folosit cu gndul ca fiecare propoziie s nceap cu un cuvnt al limbii romne care
s reprezinte numele propoziiei. De cele mai multe ori vom omite acest cuvnt. Atunci cnd vom scrie
succesiv mai multe propoziii de atribuire vom folosi cuvntul FIE numai n prima propoziie, omindu-l
n celelalte.
Din cele scrise mai sus rezult c o variabil poate fi iniializat att prin atribuire (deci dac este
variabila din stnga semnului de atribuire :=) ct i prin citire (cnd face parte din lista propoziiei
CITETE). O greeal frecvent pe care o fac nceptorii este folosirea variabilelor neiniializate.
Evident c o expresie n care apar variabile care nu au valori nu poate fi calculat, ea nu este definit.
Deci nu folosii variabile neiniializate.
Pentru a marca nceputul descrierii unui algoritm vom folosi propoziia:
ALGORITMUL nume ESTE:
fr a avea o alt semnificaie. De asemenea, prin cuvntul SFALGORITM vom marca sfritul unui
algoritm.
Algoritmii care pot fi descrii folosind numai propoziiile prezentate mai sus se numesc algoritmi
liniari.
Ca exemplu de algoritm liniar prezentm un algoritm ce determin viteza v cu care a mers un
autovehicul ce a parcurs distana D n timpul T.
ALGORITMUL VITEZA ESTE:
{ A1: Calculeaz viteza }
{ D = Distana (spaiul) }
{ T = Timpul; V = Viteza }
CITETE D,T;
{ v:= spaiu/timp }
FIE V:=D/T;
TIPRETE V
SFALGORITM

11

1.3.2 Algoritmi cu ramificaii


Foarte muli algoritmi execut anumite calcule n funcie de satisfacerea unor condiii. Aceste
calcule sunt redate de structura alternativ prezentat n figura 1.3.1.b, creia i corespunde propoziia
Pseudocod
DAC cond ATUNCI A ALTFEL B SFDAC
sau varianta redus a ei,
DAC cond ATUNCI A SFDAC
folosit n cazul n care grupul de propoziii B este vid.
Aceste propoziii redau n Pseudocod structura alternativ de calcul. Ele cer mai nti verificarea
condiiei scrise dup cuvntul DAC. n caz c aceast condiie este adevrat se va executa grupul de
propoziii A. n cazul n care aceast condiie este fals se va executa grupul de propoziii B, dac este
prezent ramura ALTFEL. Indiferent care dintre secvenele A sau B a fost executat, se va continua cu
propoziia urmtoare propoziiei DAC.
O generalizare a structurii alternative realizat de propoziia DAC este structura selectiv:
SELECTEAZ i DINTRE
v1: A1;
v2: A2;
...
vn: An
SFSELECTEAZ
structur echivalent cu urmtorul text Pseudocod:
DAC i=v1 ATUNCI A1 ALTFEL
DAC i=v2 ATUNCI A2 ALTFEL
. . .
DAC i=vn ATUNCI An SFDAC
. . .
SFDAC
SFDAC
Cu propoziiile prezentate pn aici putem deja descrie destui algoritmi. Acetia se numesc
algoritmi cu ramificaii.
Ca exemplu vom scrie un algoritm pentru rezolvarea ecuaiei de gradul al doilea. Am scris mai sus
specificaia acestei probleme i am precizat semnificaia variabilelor respective. Pe lng aceste variabile,
pentru rezolvarea problemei mai avem nevoie de dou variabile auxiliare:
delta - pentru a reine discriminantul ecuaiei;
r - pentru a reine valoarea radicalului folosit n exprimarea rdcinilor.
Ajungem uor la algoritmul dat n continuare.
ALGORITMUL ECGRDOI ESTE:

{ Algoritmul 2: Rezolvarea }
{ ecuaiei de gradul doi }
{ a,b,c = Coeficienii ecuaiei }

CITETE a,b,c;
FIE delta:=b*b- 4*a*c;
DAC delta<0 ATUNCI ind:=0;
r:=radical din (- delta);
x1:=- b/(a+a);
x2:=r/(a+a);
ALTFEL ind:=1;
r:=radical din delta;
x1:=(-b- r)/(a+a);
x2:=(-b+r)/(a+a);
SFDAC
TIPRETE ind, x1,x2;
SFALGORITM

{ rdcini complexe }

{ rdcini reale }

12

1.3.3 Algoritmi ciclici


n rezolvarea multor probleme trebuie s efectum aceleai calcule de mai multe ori, sau s
repetm calcule asemntoare. De exemplu, pentru a calcula suma a dou matrice va trebui s adunm un
element al primei matrice cu elementul de pe aceeai poziie din a doua matrice, aceast adunare
repetndu-se pentru fiecare poziie. Alte calcule trebuiesc repetate n funcie de satisfacerea unor condiii.
n acest scop n limbajul Pseudocod exist trei propoziii standard: CTTIMP, REPET i PENTRU.
Propoziia CTTIMP are sintaxa
CTTIMP cond EXECUT A SFCT
i cere execuia repetat a grupului de propoziii A, n funcie de condiia "cond". Mai exact, se evalueaz
condiia "cond"; dac aceasta este adevrat se execut grupul A i se revine la evaluarea condiiei. Dac
ea este fals execuia propoziiei se termin i se continu cu propoziia care urmeaz dup SFCT. Dac
de prima dat condiia este fals grupul A nu se va executa niciodat, altfel se va repeta execuia grupului
de propoziii A pn cnd condiia va deveni fals. Din cauz c nainte de execuia grupului A are loc
verificarea condiiei, aceast structur se mai numete structur repetitiv condiionat anterior. Ea
reprezint structura repetitiv prezentat n figura 1.3.1.c.
Ca exemplu de algoritm n care se folosete aceast propoziie dm algoritmul lui Euclid pentru
calculul celui mai mare divizor comun a dou numere.
ALGORITMUL Euclid ESTE:
{A3: Cel mai mare divizor comun}
CITETE n1,n2;
{Cele dou numere a cror divizor se cere}
FIE d:=n1; i:=n2;
CTTIMP i0 EXECUT
r:=d modulo i; d:=i; i:=r
SFCT
TIPRETE d;
{ d= cel mai mare divizor comun al }
SFALGORITM
{ numerelor n1 i n2 }
n descrierea multor algoritmi se ntlnete structura repetitiv condiionat posterior:
REPET A PN CND cond SFREP
structur echivalent cu:
CTTIMP not(cond) EXECUT A SFCT
Deci ea cere execuia necondiionat a lui A i apoi verificarea condiiei "cond". Va avea loc
repetarea execuiei lui A pn cnd condiia devine adevrat. Deoarece condiia se verific dup prima
execuie a grupului A aceast structur este numit structura repetitiv condiionat posterior, prima
execuie a blocului A fiind necondiionat.
O alt propoziie care cere execuia repetat a unei secvene A este propoziia
PENTRU c:=li ;lf [;p] EXECUT A SFPENTRU
Ea definete structura repetitiv predefinit, cu un numr determinat de execuii ale grupului de
propoziii A i este echivalent cu secvena
c:=li ; final:=lf ;
REPET
A
c:=c+p
PNCND (c>final i p>0) sau (c<final i p<0) SFREP
Se observ c, n sintaxa propoziiei PENTRU, pasul p este nchis ntre paranteze drepte. Prin
aceasta indicm faptul c el este opional, putnd s lipseasc. n cazul n care nu este prezent, valoarea
lui implicit este 1.
Semnificaia propoziiei PENTRU este clar. Ea cere repetarea grupului de propoziii A pentru
toate valorile contorului c cuprinse ntre valorile expresiilor li i lf (calculate o singur dat nainte de
nceperea ciclului), cu pasul p. Se subnelege c nu trebuie s modificm valorile contorului n nici o
propoziie din grupul A. De multe ori aceste expresii sunt variabile simple, iar unii programatori modific
n A valorile acestor variabile, nclcnd semnificaia propoziiei PENTRU. Deci, nu recalcula limitele
i nu modifica variabila de ciclare (contorul) n interiorul unei structuri repetitive PENTRU).
13

S observm, de asemenea, c prima execuie a grupului A este obligatorie, abia dup modificarea
contorului verificndu-se condiia de continuare a execuiei lui A.
Ca exemplu, s descriem un algoritm care gsete minimul i maximul componentelor unui vector
de numere reale. Vom nota prin X acest vector, deci X = (x1, x2, ... , xn) .
Specificaia problemei este urmtoarea:
DATE n,(xi ,i=1,n);
REZULTATE valmin,valmax;
iar semnificaia acestor variabile se nelege din cele scrise mai sus. Pentru rezolvarea problemei vom
examina pe rnd cele n componente. Pentru a parcurge cele n componente avem nevoie de un contor care
s precizeze poziia la care am ajuns. Fie i acest contor. Uor se ajunge la urmtorul algoritm:
ALGORITMUL MAXMIN ESTE
{ Algoritmul 5: Calculul }
{ valorii minime i maxime }
CITETE n,(xi,i=1,n);
FIE valmin:=x1; valmax:=x1;
PENTRU i:=2,n EXECUT
DAC xi<valmin ATUNCI valmin:=xi SFDAC
DAC xi>valmax ATUNCI valmax:=xi SFDAC
SFPENTRU
TIPRETE valmin,valmax;
SFALGORITM
Un rol important n claritatea textului unui algoritm l au denumirile alese pentru variabile. Ele
trebuie s reflecte semnificaia variabilelor respective. Deci alege denumiri sugestive pentru variabile,
care s reflecte semnificaia lor.
n exemplul de mai sus denumirile valmin i valmax spun cititorului ce s-a notat prin aceste
variabile.
1.4 Calculul efectuat de un algoritm
Fie X1, X2, ..., Xn, variabilele ce apar n algoritmul A. n orice moment al execuiei algoritmului,
fiecare variabil are o anumit valoare, sau este nc neiniializat.
Vom numi stare a algoritmului A cu variabilele menionate vectorul
s = ( s1,s2,...,sn )
format din valorile curente ale celor n variabile ale algoritmului.
Este posibil ca variabila Xj s fie nc neiniializat, deci s nu aib valoare curent, caz n care sj
este nedefinit, lucru notat n continuare prin semnul ntrebrii '?'.
Prin executarea unei anumite instruciuni unele variabile i schimb valoarea, deci algoritmul i
schimb starea.
Se numete calcul efectuat de algoritmul A o secven de stri
s0, s1, s2, ..., sm
unde s0 este starea iniial cu toate variabilele neiniializate, iar sm este starea n care se ajunge dup
execuia ultimei propoziii din algoritm.
1.5 Rafinare n pai succesivi
Adeseori algoritmul de rezolvare a unei probleme este rezultatul unui proces complex, n care se
iau mai multe decizii i se precizeaz tot ceea ce iniial era neclar. Observaia este adevrat mai ales n
cazul problemelor complicate, dar i pentru probleme mai simple n procesul de nvmnt. Este vorba
de un proces de detaliere pas cu pas a specificaiei problemei, proces denumit i proiectare descendent,
sau rafinare n pai succesivi. Algoritmul apare n mai multe versiuni succesive, fiecare versiune fiind o
detaliere a versiunii precedente. n versiunile iniiale apar propoziii nestandard, clare pentru cititor, dar
14

neprecizate prin propoziii standard. Urmeaz ca n versiunile urmtoare s se revin asupra lor.
Algoritmul apare astfel n versiuni succesive, tot mai complet de la o versiune la alta.
Apare aici o alt regul important n proiectarea algoritmului: amn pe mai trziu detaliile
nesemnificative; concentreaz-i atenia la deciziile importante ale momentului.

15

CAPITOLUL II
SUBPROGRAME
Conceptul de SUBPROGRAM
Orice problem poate apare ca o subproblem S a unei probleme mai complexe C. Algoritmul de
rezolvare a problemei S devine n acest caz un SUBPROGRAM pentru algoritmul de rezolvare a
problemei C.
Pentru a defini un SUBPROGRAM vom folosi propoziia standard
SUBPROGRAMUL nume (lpf) ESTE:
unde nume este numele SUBPROGRAMului definit, iar lpf este lista parametrilor formali. Acetia sunt
formai din variabilele care marcheaz datele de intrare (cele presupuse cunoscute) i variabilele care
marcheaz datele de ieire (rezultatele obinute de SUBPROGRAM).
Aceast propoziie este urmat de textul efectiv al SUBPROGRAMului, text care precizeaz
calculele necesare rezolvrii subproblemei corespunztoare. Descrierea se va ncheia cu cuvntul
SFSUBPROGRAM sau SF-nume.
Dm ca exemplu un SUBPROGRAM cu numele MAXIM, care gsete maximul dintre
componentele vectorului X = (x1,x2, ..., xn).
Datele cunoscute pentru acest SUBPROGRAM sunt vectorul X i numrul n al componentelor
vectorului X. Ca rezultat vom obine maximul cerut, pe care-l vom nota cu max. Deci lista parametrilor
formali conine trei variabile, n, X i max. SUBPROGRAMul este dat n continuare.
SUBPROGRAMUL maxim(n,X,max) ESTE:
FIE max:=x1;
PENTRU i:=2;n EXECUT
DAC xi>max ATUNCI max:=xi SFDAC
SFPENTRU
SF-maxim
n cadrul multor algoritmi este necesar calculul valorilor unei funcii n diferite puncte. Este
necesar s definim funcia printr-un SUBPROGRAM de tip funcie.
Pentru definirea unui SUBPROGRAM de tip funcie se folosete un antet care precizeaz
numele funciei i variabilele de care depinde ea. SUBPROGRAMul are forma:
FUNCIA nume(lpf) ESTE:
{Antetul funciei}
text
{corpul funciei}
SF-nume
{marca de sfrit}
n corpul funciei trebuie s existe cel puin o atribuire n care numele funciei apare n partea
stng, deci prin care funcia primete o valoare.
Dm ca exemplu o funcie numar : R --> {2,3,4,5}, definit matematic astfel:
n Pseudocod descrierea este urmtoarea:
FUNCIA numar(x) ESTE:
DAC x<0.2 ATUNCI numar:=2 ALTFEL
DAC x<0.5 ATUNCI numar:=3 ALTFEL
DAC x<0.9 ATUNCI numar:=4
ALTFEL numar:=5
SFDAC
SFDAC
SFDAC
SF-numar

16

Am vzut c definiia unei funcii const dintr-un antet i dintr-un bloc care va defini aciunile
prin care se calculeaz valoarea funciei. n antet se precizeaz numele funciei i lista parametrilor
formali.
n concluzie, exist dou categorii de SUBPROGRAMi: de tip funcie i SUBPROGRAMi
propriu-zii, crora li se mai spune i proceduri. Importana lor va fi subliniat prin toate exemplele care
urmeaz n acest curs. n ncheiere menionm c subprogramele de tip funcie se folosesc n scopul
definirii funciilor, aa cum sunt cunoscute ele din matematic, n timp ce SUBPROGRAMii de tip
procedur se refer la rezolvarea unor probleme ce apar ca subprobleme, fiind algoritmi de sine stttori.
Apelul unui SUBPROGRAM
Am vzut c un SUBPROGRAM este dedicat rezolvrii unei subprobleme S a unei probleme mai
complexe C. Algoritmul corespunztor problemei C va folosi toate operaiile necesare rezolvrii
problemei S, deci va folosi ca parte ntregul SUBPROGRAM conceput pentru rezolvarea subproblemei S.
Spunem c el va apela acest SUBPROGRAM.
n Pseudocod apelul unei funcii se face scriind ntr-o expresie numele funciei urmat de lista
parametrilor actuali. Trebuie s existe o coresponden biunivoc ntre parametrii actuali i cei formali
folosii n definiia funciei. Dei denumirile variabilelor din cele dou liste pot s difere, rolul variabilelor
care se corespund este acelai. Mai exact, parametrul formal i parametrul actual corespunztor trebuie s
se refere la aceeai entitate, trebuie s aib aceeai semnificaie, s reprezinte aceeai structur de date.
Putem considera c n timpul execuiei algoritmului cei doi parametri devin identici.
Folosirea unui SUBPROGRAM n cadrul unui algoritm se face apelnd acest SUBPROGRAM
prin propoziia standard CHEAM nume (lpa);
unde nume este numele SUBPROGRAMului apelat iar lpa este lista parametrilor actuali. Aceast list
conine toate datele de intrare (cele cunoscute n subproblema corespunztoare) i toate rezultatele
obinute n SUBPROGRAM. i n acest caz ntre lista parametrilor formali din definiia
SUBPROGRAMului i lista parametrilor actuali din propoziia de apel trebuie s existe o coresponden
biunivoc, ca i n cazul funciilor. Ca o prim verificare a respectrii acestei corespondene, subliniem c
numrul parametrilor actuali trebuie s coincid cu numrul parametrilor formali.
Ca exemplu de apelare a funciilor, dm n continuare un program pentru a calcula a cta zi din
anul curent este ziua curent (zi,luna,an). El folosete un subprogram de tip funcie pentru a obine
numrul zilelor lunii cu numrul de ordine i i un altul pentru a verifica dac un an este bisect sau nu.
Aceste dou funcii sunt:
- NRZILE(i) furnizeaz numrul zilelor existente n luna i a unui an nebisect;
- BISECT(an) adevrat dac anul dintre paranteze este bisect.
Algoritmul este urmtorul:
ALGORITMUL NUMRZILE ESTE:
CITETE zi, luna, an;
FIE nr:=zi;
DAC luna>1 ATUNCI
PENTRU i:=1, Luna-1 EXECUT nr:=nr+NRZILE(i) SFPENTRU
SFDAC
DAC luna>2 ATUNCI
DAC BISECT(an) ATUNCI nr:=nr+1 SFDAC
SFDAC
TIPRETE nr;
SFALGORITM
S observm c n proiectarea acestui algoritm nu este necesar s cunoatem textul
SUBPROGRAMilor folosii, ci doar specificarea acestor SUBPROGRAMi, numele lor i lista
parametrilor formali. La acest nivel accentul trebuie s cad pe proiectarea algoritmului care apeleaz,
17

urmnd s se revin ulterior la proiectarea SUBPROGRAMilor apelai, conform specificaiei acestora. n


cazul de fa este necesar descrierea funciilor NRZILE(i) i BISECT(an). Lsm aceast descriere ca
tem pentru cititor.
Ca exemplu de apelare a unei proceduri vom scrie mai jos o procedur care efectueaz suma a
dou polinoame.
Un polinom P(X) este dat prin gradul su, m, i prin vectorul coeficienilor P = (p0, p1, ..., pm) (prin pi s-a
notat coeficientul lui Xi).
Procedura SUMAPOL(m,P,n,Q,r,S) trebuie s efectueze suma
S(X) = P(X)+Q(X),
unde P este un polinom de gradul m, iar Q este un polinom de gradul n, date. Suma lor, S, va fi un
polinom de gradul r calculat n SUBPROGRAM. Pentru efectuarea ei este util o alt procedur care
adun la suma S(X) un alt polinom, T(X), de grad mai mic sau egal dect gradul polinomului S(X). O
astfel de procedur se d n continuare.
SUBPROGRAMUL SUMAPOL1(n,T,r,S) ESTE:
{n r}
{S(X):=S(X)+T(X)}
PENTRU i:=0;n EXECUT
si := si+ti
SFPENTRU
SF-SUMAPOL1
SUBPROGRAMul SUMAPOL apeleaz acest SUBPROGRAM, aa cum se poate vedea n
continuare.
SUBPROGRAMUL SUMAPOL(m,P,n,Q,r,S) ESTE: {S(X):=P(X)+Q(X)}
DAC m<n
ATUNCI r:=n; S:=Q;
CHEAM SUMAPOL1(m,P,r,S)
ALTFEL r:=m; S:=P;
CHEAM SUMAPOL1(n,Q,r,S)
SFDAC
SF-SUMAPOL
S observm c n textul acestui SUBPROGRAM am extins semnificaia propoziiei de atribuire,
permind atribuirea S:=Q. Acest lucru este normal ntruct S noteaz un polinom, iar Q este un polinom
cunoscut; prin atribuire S primete o valoare iniial, cea dat de polinomul Q.
Subliniem c atribuirea
v := u
va fi corect n cazul n care variabilele u i v reprezint aceleai obiecte matematice, deci au aceeai
semnificaie.
Alte exemple
Ca un al doilea exemplu de definire i folosire a SUBPROGRAMilor, s considerm urmtoarea
problem:
Se dau trei mulimi de numere:
A = { a1, a2, ... , am }
B = { b1, b2, ... , bn }
C = { c1, c2, ... , cp }
Se cere s se tipreasc n ordine cresctoare elementele fiecrei mulimi, precum i a mulimilor
A U B, B U C, C U A.
n rezolvarea acestei probleme se ntlnesc urmtoarele subprobleme:
S1: S se citeasc elementele unei mulimi;
S2: S se efectueze reuniunea a dou mulimi;
S3: S se tipreasc elementele unei mulimi;
S4: S se ordoneze cresctor elementele unei mulimi.
Presupunnd c pentru rezolvarea acestor subprobleme am conceput SUBPROGRAMii:
18

CITMUL(m,A);
REUNIUNE(m,A,n,B,k,R);
TIPMUL(m,A);
ORDON(m,A);
care sunt specificai mai jos (la locul definirii lor) prin comentarii, algoritmul de rezolvare a problemei de
mai sus este dat n continuare. ntruct operaiile respective se folosesc de mai multe ori (de 3 ori), am
definit un SUBPROGRAM TIPORDON(m,A) care ordoneaz mai nti elementele mulimii A i apoi le
tiprete.
ALGORITMUL OPER-MULTIMI ESTE:
{ A6: SUBPROGRAMi }
CHEAM CITMUL(m,A);
CHEAM CITMUL(n,B);
CHEAM CITMUL(p,C);
CHEAM TIPORDON(m,A);
CHEAM TIPORDON(n,B);
CHEAM TIPORDON(p,C);
CHEAM REUNIUNE(m,A,n,B,k,R);
CHEAM TIPORDON(k,R);
CHEAM REUNIUNE(n,B,p,C,k,R);
CHEAM TIPORDON(k,R);
CHEAM REUNIUNE(p,C,m,A,k,R);
CHEAM TIPORDON(k,R);
SFALGORITM
SUBPROGRAMii apelai mai sus sunt definii n continuare.
SUBPROGRAMUL CITMUL(n,M) ESTE:
{Citete n i M}
CITETE n;
{n=nr. elementelor mulimii}
CITETE (mi,i=1,n);
{M=mulimea cu elementele m1,m2,...,mn}
SF-CITMUL
SUBPROGRAMUL ORDON(n,M) ESTE:
REPET
FIE ind:=0;
PENTRU i:=1;n- 1 EXECUT
DAC mi>mi+1 ATUNCI
FIE t := mi;
mi:=mi+1; mi+1:=t;
ind:=1;
SFDAC
SFPENTRU
PNCND ind=0 SFREP
SF-ORDON

{Ordoneaz cresctor cele n}


{elemente ale mulimii M}
{Cazul M este ordonat}
{schimb ordinea celor}
{dou elemente}
{Cazul M nu era ordonat}

SUBPROGRAMUL REUNIUNE(m,A,n,B,k,R) ESTE:


{ R := A U B }
{ k = numrul elementelor mulimii R }
FIE k:=m; R := A;
PENTRU j:=1,n EXECUT
FIE ind:=0;
{Ipoteza bj nu e in A}
PENTRU i:=1;m EXECUT
DAC bj=ai ATUNCI ind:=1 {bj este in A} SFDAC
SFPENTRU
19

DAC ind=0 ATUNCI k:=k+1; rk:=bj SFDAC


SFPENTRU
SF-REUNIUNE
SUBPROGRAMUL TIPMUL(n,M) ESTE:
PENTRU i:=1;n EXECUT
TIPRETE mi
SFPENTRU
SF-TIPMUL
SUBPROGRAMUL TIPORDON(n,M) ESTE:
CHEAM ORDON(n,M);
CHEAM TIPMUL(n,M);
SF-TIPORDON

{ Tiprete cele n elemente }


{ ale mulimii M }

{ Ordoneaz i tiprete }
{ elementele mulimii M }

Tot ca exemplu de folosire a SUBPROGRAMilor, vom scrie un algoritm pentru rezolvarea


urmtoarei probleme:
dirigintele unei clase de elevi dorete s obin un clasament al elevilor n funcie de media general. n
plus, pentru fiecare disciplin n parte dorete lista primilor ase elevi.
n rezolvarea acestei probleme este necesar gsirea ordinii n care trebuiesc tiprii elevii n
funcie de un anumit rezultat: nota la disciplina "j", sau media general. Am identificat prin urmare dou
subprobleme independente, referitoare la:
(1) aflarea ordinii n care trebuie tiprite n numere pentru a le obine ordonate;
(2) tiprirea elevilor clasei ntr-o anumit ordine.
Prima subproblem se poate specifica astfel:
Dndu- se numerele x1, x2, ... , xn, gsii ordinea o1, o2, ..., on, n care aceste numere devin ordonate
descresctor, adic
x[o1] x[o2] ... x[on] .
Pentru rezolvarea ei vom da un SUBPROGRAM ORDINE n care intervin trei parametri formali:
- n, numrul valorilor existente;
- X, vectorul acestor valori;
- O, vectorul indicilor care dau ordinea dorit.
Primii doi parametri marcheaz datele presupuse cunoscute, iar al treilea, rezultatele calculate de
SUBPROGRAM.
SUBPROGRAMUL ORDINE(n,X,O) ESTE:
{n, numrul valorilor existente}
{X, vectorul acestor valori}
{O, vectorul indicilor care dau ordinea dorit}
PENTRU i:=1; n EXECUT oi :=i SFPENTRU
REPET ind:=0;
PENTRU i:=1;n- 1 EXECUT
DAC x[oi] < x[oi+1] ATUNCI
FIE ind:=1; t:=oi+1 ;
oi+1 :=oi; oi :=t;
SFDAC
SFPENTRU
PANCND ind=0 SFREP
SF-ORDINE
A doua subproblem se poate specifica astfel:
20

Dndu- se ordinea o1,o2, ..., on, a elevilor clasei, numele i mediile acestora, s se tipreasc
numele i mediile primilor k elevi n ordinea specificat.
SUBPROGRAMul TIPAR, dat n continuare, rezolv aceast problem.
SUBPROGRAMUL TIPAR(k, NUME, O) ESTE:
PENTRU i:=1;k EXECUT
Tiprete datele elevului de rang oi.
SFPENTRU
SF-TIPAR
Variabilele folosite pentru problema dat sunt urmtoarele:
- n reprezint numrul elevilor clasei;
- m este numrul disciplinelor la care elevii primesc note;
- NUME este vectorul care reine numele elevilor: NUMEi este numele elevului cu numrul
de ordine i;
- NOTE este matricea notelor elevilor, avnd n linii i m coloane;
NOTEi,j este nota elevului cu numele NUMEi la disciplina cu numrul de ordine j;
NOTE.j este coloana a j-a a matricei NOTE i reprezint notele elevilor la disciplina
j;
- MEDII este vectorul mediilor generale.
Algoritmul se d n continuare:
ALGORITMUL CLASAMENT ESTE:
{ Algoritmul 7: Ordonare}
CITETE m,
{numrul disciplinelor i}
n,
{al elevilor}
NUMEi, i=1,n,
{numele elevilor}
NOTEi,j, j=1,m, i=1,n;
{notele elevilor}
PENTRU i:=1;n EXECUT
{ calculeaz media general}
FIE S:=0;
{a elevului i}
PENTRU j:=1;m EXECUT S:=S+NOTEi,j SFPENTRU
FIE MEDIIi:=S/m
SFPENTRU
CHEAM ORDINE(n,MEDII,O);
CHEAM TIPAR(n,NUME,O);
PENTRU j:=1;m EXECUT
CHEAM ORDINE(n,NOTE.j,O);
CHEAM TIPAR(6,NUME,O);
SFPENTRU
SF-ALGORITM
Apel recursiv
n exemplele date se observ c apelul unui subprogram se face dup ce el a fost definit. Este ns
posibil ca un SUBPROGRAM s se apeleze pe el nsui. ntr-un astfel de caz spunem c apelul este
recursiv, iar SUBPROGRAMul respectiv este definit recursiv.
Ca exemplu, definim n continuare o funcie care calculeaz recursiv valoarea n!. Se va folosi
formula n! = n.(n- 1)! n cazul n>0 i faptul c 0!=1. Recursivitatea const n faptul c n definiia funciei
Factorial de n se folosete aceeai funcie Factorial dar de argument n-1. Deci funcia Factorial se
apeleaz pe ea nsi. Este important ca numrul apelurilor s fie finit, deci ca procedeul de calcul descris
s se termine.
FUNCTIA Factorial(n) ESTE:
DAC n=0 ATUNCI Factorial:=1
ALTFEL Factorial:= n*Factorial(n- 1)
21

SFDAC
SF-Factorial;
Tot ca exemplu de apel recursiv putem descrie o funcie ce calculeaz maximul a n numere
x1,x2,...,xn. Ea se bazeaz pe funcia MAXIM2 care calculeaz maximul a dou numere, descris n
continuare.
FUNCIA MAXIM2(a,b) ESTE:
DAC a<b ATUNCI MAXIM2:=b
ALTFEL MAXIM2:=a
SFDAC
SF-MAXIM2
Funcia MAXIM, care calculeaz maximul celor n numere este urmtoarea:
FUNCIA MAXIM(n,X) ESTE:
{Calculeaz maximul a n numere}
{X=vectorul cu numerele date}
DAC n=1
ATUNCI MAXIM:=x1
ALTFEL MAXIM:=MAXIM2( MAXIM(n-1,X), xn)
SFDAC
SF-MAXIM

22

CAPITOLUL III
METODE DE PROIECTARE A ALGORITMILOR
3.1 Elaborarea algoritmilor
Prin elaborarea (proiectarea) unui algoritm nelegem ntreaga activitate depus de la enunarea
problemei pn la realizarea algoritmului corespunztor rezolvrii acestei probleme.
n elaborarea unui algoritm deosebim urmtoarele activiti importante:
specificarea problemei;
descrierea metodei alese pentru rezolvarea problemei;
proiectarea propriu-zis. Ea const n descompunerea problemei n subprobleme,
obinerea algoritmului principal i a tuturor SUBPROGRAMilor apelai, conform
metodelor prezentate n seciunile urmtoare. Ea se termin cu descrierea algoritmului
principal i a SUBPROGRAMilor menionai, dar i cu precizarea denumirilor i
semnificaiilor variabilelor folosite;
verificarea algoritmului obinut.
3.2 Proiectarea ascendent i proiectarea descendent
Exist dou metode generale de proiectare a algoritmilor, a cror denumire provine din modul de
abordare a rezolvrii problemelor: metoda descendent i metoda ascendent. Proiectarea descendent
(top-down) pornete de la problema de rezolvat, pe care o descompune n pri rezolvabile separat. De
obicei aceste pri sunt subprobleme independente, care la rndul lor pot fi descompuse n subprobleme.
La prima descompunere accentul trebuie pus pe algoritmul (modulul) principal nu asupra subproblemelor.
La acest nivel nu ne intereseaz amnunte legate de rezolvarea subproblemelor, presupunem c le tim
rezolva, eventual c avem deja scrii SUBPROGRAMi pentru rezolvarea lor. Urmeaz s considerm pe
rnd fiecare subproblem n parte i s proiectm (n acelai mod) un SUBPROGRAM pentru rezolvarea
ei. n final, se va descrie SUBPROGRAMul de rezolvare al fiecrei subprobleme, dar i interaciunile
dintre aceti SUBPROGRAMi i ordinea n care ei sunt folosii.
Noiunea de modul va fi definit n seciunea urmtoare. Deocamdat nelegem prin modul orice
SUBPROGRAM sau algoritmul principal. Legtura dintre module se prezint cel mai bine sub forma unei
diagrame numit arbore de programare. Fiecrui modul i corespunde n arborele de programare un nod,
ai crui descendeni sunt toate modulele apelate direct. Nodul corespunztor algoritmului principal este
chiar nodul rdcin.
n multe cri metoda top-down este ntlnit i sub denumirea stepwise-refinement, adic
rafinare n pai succesivi. Este vorba de un proces de detaliere pas cu pas a specificaiei, denumit
proiectare descendent. Algoritmul apare n diferite versiuni succesive, fiecare fiind o detaliere a versiunii
precedente.
Scopul urmrit este acelai: concentrarea ateniei asupra prilor importante ale momentului i amnarea
detaliilor pentru mai trziu. Dac ar fi necesar s le deosebim am spune c metoda top-down se refer la
nivelul macro iar metoda rafinrii succesive la nivel micro. La nivel macro se dorete descompunerea
unei probleme complexe n subprobleme. La nivel micro se dorete obinerea unui modul n versiune
final. ntr-o versiune intermediar pot fi prezente numai prile importante ale acestuia, urmnd s se
revin asupra detaliilor n versiunile urmtoare (aa cum s-a artat n seciunea 1.5), dup ce aspectele
importante au fost rezolvate.
Avantajele proiectrii top-down (cunoscut i sub denumirea "Divide et impera") sunt multiple.
Avantajul principal const n faptul c ea permite programatorului s reduc complexitatea problemei,
subproblemele n care a fost descompus fiind mai simple, i s amne detaliile pentru mai trziu. n
momentul n care descompunem problema n subprobleme nu ne gndim cum se vor rezolva
subproblemele ci care sunt ele i conexiunile dintre ele.
23

Proiectarea descendent permite lucrul n echipe mari. Prin descompunerea problemei n mai
multe subprobleme, fiecare subproblem poate fi dat spre rezolvare unei subechipe. Fiecare subechip
nu cunoate dect subproblema pe care trebuie s o rezolve.
Metoda "Divide et Impera" poate fi folosit nu numai la mprirea problemei n subprobleme ci
i la mprirea datelor n grupe mai mici de date. Un astfel de procedeu este folosit de SUBPROGRAMul
Quicksort.
Metoda ascendent (bottom-up) pornete de la propoziiile limbajului i de la SUBPROGRAMi
existeni, pe care i asambleaz n ali SUBPROGRAMi pentru a ajunge n final la algoritmul dorit. Cu
alte cuvinte, n cazul metodei ascendente va fi scris mai nti SUBPROGRAMul apelat i apoi cel care
apeleaz. Ca rezultat al proiectrii ascendente se ajunge la o mulime de SUBPROGRAMi care se
apeleaz ntre ei. Este important s se cunoasc care SUBPROGRAM apeleaz pe care, lucru redat printro diagram de structur, ca i n cazul programrii descendente.
Aceast metod are marele dezavantaj c erorile de integrare vor fi detectate trziu, abia n faza de
integrare. Se poate ajunge abia acum la concluzia c unii SUBPROGRAMi, dei coreci, nu sunt utili.
De cele mai multe ori nu se practic o proiectare ascendent sau descendent pur ci o combinare
a lor, o proiectare mixt.
3.3 Proiectarea modular
Prin proiectare (programare) modular nelegem metoda de proiectare (programare) a unui
algoritm pentru rezolvarea unei probleme prin folosirea modulelor.
Dar ce este un modul? Modulul este considerat o unitate structural de sine stttoare, fie
program, fie subprogram, fie o unitate de program. Un modul poate conine sau poate fi coninut ntr-alt
modul. Un modul poate fi format din mai multe submodule. Astfel, n Pseudocod fiecare
SUBPROGRAM i algoritmul principal sunt considerate module. n limbajele de programare cu structur
de bloc UNIT-urile pot fi considerate module. La compilarea separat un grup de subprograme compilate
deodat constituie un modul, dar acest modul poate fi considerat ca o mulime de submodule din care este
compus.
Este ns important ca fiecare modul s-i aib rolul su bine precizat, s realizeze o funcie n
cadrul ntregului program. El apare n mod natural n descompunerea top-down.
Indiferent c privim modulul ca un singur SUBPROGRAM, un grup de SUBPROGRAMi, sau un
algoritm de sine stttor ce apeleaz ali SUBPROGRAMi, considerm modulele relativ independente,
dar cu posibiliti de comunicare ntre ele. Astfel, un modul nu trebuie s fie influenat de maniera n care
se lucreaz n interiorul altui modul. Orice modificare ulterioar n structura unui program, dac funcia
pe care o realizeaz un modul M nc este necesar, acest modul trebuie s fie util i folosit n continuare
fr modificri.
Rezult c programarea modular se bazeaz pe descompunerea problemei n subprobleme i
proiectarea i programarea separat a SUBPROGRAMilor corespunztori. De altfel, considerm c ntr-o
programare serioas nu se poate ajunge la implementare fr a avea n prealabil algoritmii descrii ntr-un
limbaj de descriere (la noi Pseudocod). Deci programarea modular se refer n primul rnd la proiectarea
modular a algoritmilor i apoi la traducerea lor n limbajul de programare ales, innd seama de
specificul acestui limbaj. Programarea modular este strns legat de programarea ascendent i de
programarea descendent, ambele presupunnd folosirea SUBPROGRAMilor pentru toate subproblemele
ntlnite.
Avantajele programrii modulare sunt multiple. Menionm n cele ce urmeaz cteva dintre ele.
Descompunerea unei probleme complexe n subprobleme este un mijloc convenabil i eficient de a reduce
complexitatea (Principiul Divide et impera acioneaz i n programare). Este evident c
probabilitatea apariiei erorilor n conceperea unui program crete cu mrimea programului, lucru
confirmat i de experiena practic. De asemenea, rezolvnd o problem mai simpl, testarea unui modul
se poate face mult mai uor dect testarea ntregului algoritm.
24

Apoi, faptul c trebuiesc proiectate mai multe subprograme pentru subproblemele ntlnite,
permite munca mai multor programatori. S-a ajuns astfel la munca n echip, modalitate prin care se
ajunge la scurtarea termenului de realizare a produsului program.
Modulele se pot refolosi ori de cte ori avem nevoie de ele. Astfel, s-a ajuns la compilarea
separat a subprogramelor i la pstrarea subprogramelor obinute n biblioteci de subprograme, de unde
ele se pot refolosi la nevoie. Sunt cunoscute astzi multe astfel de biblioteci de subprograme.
Reutilizabilitatea acestor subprograme este o proprietate foarte important n activitatea de programare.
Ea duce la mrirea productivitii n programare, dar i la creterea siguranei n realizarea unui produs
corect.
Uneori, n timpul proiectrii algoritmului sau a implementrii lui, se ajunge la concluzia c
proiectarea a fost incomplet sau c unele module sunt ineficiente. i n aceast situaie programarea
modular este avantajoas, ea permind nlocuirea modulului n cauz cu altul mai performant.
Una din activitile importante n realizarea unui program este verificarea corectitudinii acestuia.
Experiena a artat c modulele se pot verifica cu att mai uor cu ct sunt mai mici. Abilitatea omului de
a nelege i analiza corectitudinea unui SUBPROGRAM este mult mai mare pentru texte scurte. n unele
cri chiar se recomand a nu se folosi SUBPROGRAMi mai mari dect 50 de propoziii. Sigur c o astfel
de limit nu exist, dar se recomand descompunerea unui SUBPROGRAM n ali SUBPROGRAMi
oricnd acest lucru este posibil n mod natural, deci aceti noi SUBPROGRAMi rezolv subprobleme de
sine stttoare, sau realizeaz funcii bine definite.
3.4 Programarea structurat
Programarea structurat este un stil de programare aprut n urma experienei primilor ani de
activitate. Ea cere respectarea unei discipline de programare i folosirea riguroas a ctorva structuri de
calcul. Ca rezultat se va ajunge la un algoritm uor de urmrit, clar i corect.
Termenul programare, folosit n titlul acestei seciuni i consacrat n literatura de specialitate, este
folosit aici n sens larg i nu este identic cu cel de programare propriu-zis. Este vorba de ntreaga
activitate depus pentru obinerea unui program, deci att proiectarea algoritmului ct i traducerea
acestuia n limbajul de programare ales.
Bohm i Jacopini au demonstrat c orice algoritm poate fi compus din numai trei structuri de
calcul:
structura secvenial;
structura alternativ;
structura repetitiv.
Fiecare din aceste structuri, ca parte dintr-o schem logic, are o singur intrare i o singur ieire
i sunt prezentate n figura 1.3.1.
Knuth consider programarea structurat ca fiind un mijloc de a face produsele program mai uor
de citit. De asemenea, programarea structurat este definit ca fiind programarea n care abordarea este
top-down, organizarea muncii este fcut pe principiul echipei programatorului ef, iar n proiectarea
algoritmilor se folosesc cele trei structuri de calcul definite de Bohm-Jacopini.
Ali autori consider programarea structurat nu ca o simpl metod de programare ci ansamblul
tuturor metodelor de programare cunoscute. Dar programarea modular, programarea top-down, sau
bottom-up (ascendent sau descendent) au aprut naintea programrii structurate. Important este faptul
c programarea structurat presupune o disciplin n activitatea de programare.
Considerm c programarea structurat se poate ntlni:
la nivel micro, privind elaborarea unui SUBPROGRAM;
la nivel macro, privind dezvoltarea ntregului produs informatic (algoritm).
La nivel micro programarea structurat este cea n care autorul este atent la structura fiecrui
modul n parte, cernd claritate i ordine n scriere i respectarea structurilor de calcul definite mai sus.

25

La nivel macro programarea structurat presupune practicarea proiectrii top-down, a programrii


modulare i a celorlalte metode de programare, cernd ordine n ntreaga activitate i existena unei
structuri clare a ntregii aplicaii, precizat prin diagrama de structur a aplicaiei.
n acest scop am definit limbajul Pseudocod, care are structurile de calcul menionate. Schemele
logice obinute dintr-o descriere n Pseudocod a unui algoritm, conform semanticii propoziiilor
Pseudocod, se numesc D-scheme (de la Dijkstra) sau scheme logice structurate.

26

CAPITOLUL IV
ANALIZA ALGORITMILOR
O anumit problem poate fi rezolvat cu ajutorul calculatorului numai dac se gsete un
algoritm pentru rezolvarea ei, care este dat calculatorului sub forma unui program. ntruct toate
problemele practice pe care le ntlnim se pot rezolva cu ajutorul calculatorului, s-ar putea crede c orice
problem este rezolvabil. Aceast afirmaie este ns fals. Se tie c nu exist un program care s
rezolve "problema terminrii programelor":
"Scriei un program care s decid dac un algoritm oarecare, dat, intr sau nu ntr-un ciclu infinit".
Chiar i problemele pentru care exist algoritmi corespunztori nu sunt neaprat rezolvabile cu
calculatorul. Este posibil ca timpul necesar execuiei acestor algoritmi, sau cantitatea de memorie
necesar, s nu permit folosirea lor n practic.
Evident, dac spaiul de memorie necesar programului este mai mare dect cantitatea de memorie
disponibil, programul nu poate fi executat. De asemenea, dac numrul calculelor ce trebuie efectuat este
foarte mare, programul poate fi inutil. Iar asta se poate ntmpla destul de uor n cazul problemelor ce
trebuiesc rezolvate n timp real (adic soluia trebuie obinut naintea unui timp critic).
Iat cteva motive pentru care este necesar s analizm algoritmii pe care-i concepem pentru
rezolvarea unei probleme.
Ne intereseaz s analizm un program din mai multe puncte de vedere:
1) Corectitudine;
2) Eficien;
3) Posibilitate de mbuntire;
4) Alte caliti pe care le are.
4.1 Corectitudinea programelor
Un program este corect dac el satisface specificaiile problemei. Nu ne intereseaz ct memorie
folosete acest program, din cte instruciuni este compus, sau ct timp de execuie necesit. Cu alte
cuvinte, un program este corect dac pentru acele date de intrare care satisfac specificaiile problemei
rezultatele obinute n urma execuiei sunt corecte.
Pentru orice program P deosebim trei tipuri de variabile, pe care le vom grupa n trei vectori X, Y
i Z. Componentele vectorului X desemneaz variabilele de intrare, deci datele presupuse cunoscute n
problema rezolvat prin programul P. Componentele vectorului Z sunt variabilele care reprezint
rezultatele cerute de problem. n sfrit, componentele vectorului Y sunt variabilele de lucru, care
noteaz diferitele rezultate intermediare necesare n program.
O problem nu are sens pentru orice date de intrare. Vom folosi predicatul R(X) pentru a preciza
datele pentru care problema are sens. R(X) se numete predicat de intrare sau precondiie. Pentru acele
valori ale lui X pentru care predicatul este adevrat problema are sens, pentru celelalte nu are sens s
executm programul P.
ntre rezultatele Z ale problemei i datele iniiale X (cunoscute n problem) exist anumite relaii.
Vom reda aceste relaii prin predicatul de ieire R(X,Z), numit i postcondiie. Acesta este corect pentru
acele valori a i b ale vectorilor X i Z pentru care rezultatele problemei sunt b n cazul cnd datele iniiale
sunt a i este fals n caz contrar. Deci, dac executnd programul cu datele iniiale a obinem rezultatele b'
i R(a,b') este fals, acest fapt este un indiciu c rezultatele obinute n program nu sunt corecte. Apare o
alt regul: fiecare variabil s aib semnificaia ei i s nu fie folosit n scopuri diferite.

27

4.2 Testarea i depanarea programelor


Testarea programelor este activitatea prin care programatorul observ comportarea programului
n urma execuiei lui cu date de test. Evident, primul lucru urmrit este corectitudinea rezultatelor obinute
n urma execuiei programului cu datele de test folosite. Dar se va urmri i dac programul are alte
caracteristici ca: utilitate, siguran n funcionare, robustee, performan. Este beneficiarul mulumit de
rezultatele care se obin i de forma sub care sunt prezentate? Sunt ele obinute n timp util?
Datele de test sunt date de intrare alese pentru variabilele de intrare pentru care se cunosc
rezultatele, sau avem unele informaii despre rezultate. Executnd programul cu aceste date ar trebui s
ajungem la rezultatele cunoscute.
Corectitudinea rezultatelor n aceste execuii nu demonstreaz corectitudinea programului n
general. Testarea ns pune adeseori n eviden erori fcute n diferite faze ale programrii. n privina
aceasta dm un citat din Dijkstra: Testarea programelor poate fi un mijloc eficient de a indica prezena
erorilor, dar din pcate, nu i un mijloc de a demonstra absena lor.
Cu toate c ea nu demonstreaz corectitudinea programului, testarea mrete certitudinea
corectitudinii lui i este deocamdat singura metod practic de certificare a programului. Ar fi de dorit
demonstrarea apriori a corectitudinii programului, dar rezultatele cunoscute n prezent n aceast direcie
nu sunt aplicabile programelor complexe.
Scopul testrii programelor este depistarea i eliminarea erorilor. Acest lucru este fcut prin
execuia programului cu date de test pentru care se cunosc dinainte rezultatele (sau cel puin se tie ceva
despre ele) i se observ rezultatele obinute n urma execuiei. n cazul n care rezultatele obinute n
urma execuiei nu sunt cele ateptate se vor cuta i elimina erorile. Activitatea care urmrete
descoperirea cauzelor erorilor i nlturarea lor se numete depanare.
Se pune problema alegerii datelor de test i a numrului de execuii ce trebuie fcute pentru a
putea considera c programul nu are erori. Numrul tuturor seturilor de date de intrare posibile este
teoretic infinit chiar i pentru probleme simple. Deci nu poate fi vorba de o testare exhaustiv. Stabilirea
datelor de test se poate face cel puin pe dou ci:
innd seama de specificaia problemei;
innd seama de textul programului.
Aa cum va rezulta din cele ce urmeaz, cea mai bun cale este una mixt, n care sunt combinate
aceste dou posibiliti.
La testarea dup specificaia problemei, stabilirea datelor de test se face analiznd specificaia
problemei. Se recomand stabilirea datelor de test innd seama de specificaia asupra datelor de intrare i
de specificaia asupra datelor de ieire. Aceast metod de testare este adecvat problemelor simple. n
cazul unei probleme complexe aplicarea ei este imposibil datorit numrului foarte mare de cazuri
posibile, care ar trebui testate. ns problema noastr a fost descompus n subprobleme mai mici,
invizibile n specificaie i a cror testare este mai simpl. Privind programul ca o cutie neagr nu vom
mai ine seama de aceste subprobleme. Totui, testarea dup specificaia problemei rmne o metod util
n testarea modulelor.
Testarea dup textul programului ine seama, pentru a stabili datele de test, de instruciunile
care trebuiesc executate. Considernd c algoritmul este descris printr-o schem logic, o execuie a
programului nseamn parcurgerea unui drum de la START la STOP n aceast schem. Dac la aceast
execuie rezultatele obinute sunt corecte probabil c textul algoritmului pe acest drum este corect. Ar
trebui s verificm toate blocurile schemei logice i mai ales toate drumurile de la START la STOP
posibile. Cu observaia c n cazul a dou drumuri ce difer doar prin faptul c o anumit bucl se execut
de n1, respectiv n2 ori le vom considera echivalente ntre ele. Dintre toate drumurile echivalente ntre ele
vom testa un singur drum, altfel am avea o infinitate de drumuri de testat.
n concluzie vom alege pentru fiecare drum un set de date de test, numrul execuiilor fiind egal
cu numrul acestor drumuri. Dac toate execuiile au dat rezultate corecte programul se consider testat.
Dac ns la o singur execuie am depistat erori, corectarea lor a modificat textul algoritmului i testarea
trebuie reluat pe toate drumurile afectate de aceast schimbare.
28

Pentru un program complex, deci pentru o schem logic cu un numr foarte mare de drumuri
START-STOP, testarea ar fi o activitate complex, constnd dintr-un numr foarte mare de execuii. nc
un motiv pentru a practica programarea modular, caz n care testarea se face asupra unor module mai
mici i asupra interfeei dintre ele, aa cum se va meniona mai jos.
Stabilirea datelor de test dup textul programului are i unele dezavantaje. n primul rnd,
programul poate fi incomplet i s nu corespund specificaiilor. Pe drumurile existente el este corect, dar
lipsesc drumuri care, conform specificaiilor, ar trebui s existe. Lipsa acestor drumuri este o greeal
grav care nu va fi descoperit de datele de test care ne duc doar pe drumurile existente. Din aceast
cauz se recomand o testare mixt.
n textul unui program exist i drumuri moarte, pe care nu se poate merge oricare ar fi datele de
intrare, deci nu putem gsi date de test corespunztoare acestor drumuri. Adeseori aceste drumuri scot n
eviden erori prin simpla analiz a textului. Astfel, n succesiunea de propoziii Pseudocod
DAC n<2 ATUNCI
. . .
DAC n>3 ATUNCI A SFDAC
. . .
SFDAC
grupul A este inaccesibil oricare ar fi valoarea lui n. Este ns foarte frecvent eroarea de omisiune a unui
caracter; n cazul nostru tastarea numrului 2 n loc de 20, ceea ce schimb complet sensul textului
Pseudocod de mai sus.
Adesea este imposibil s se execute programul cu toate datele de test stabilite. n acest caz apare
problema alegerii acelei submulimi din aceste date care s aib ansa maxim de a depista erorile
prezente n program. Testarea minim care trebuie fcut const ntr-un numr de execuii a programului
care s ne asigure c fiecare instruciune din program a fost executat cel puin odat. Ea nseamn mult
mai puine execuii dect toate drumurile START-STOP.
Exist date de test care ne duc pe un anumit drum fr a depista erori existente n instruciunile
ntlnite i alte date de test care depisteaz aceste erori. nc un motiv pentru care se recomand o testare
mixt.
Ca ordine de folosire a datelor de test n timpul testrii, se recomand mai nti testarea dup
specificaii i apoi testarea dup textul programului.
Este necesar i testarea robusteei programului, care nseamn buna lui comportare la date de
intrare intenionat greite, pentru care problema nu are sens. Unele programe intr n aceste condiii n
ciclu infinit, altele se termin cu erori de execuie. Un program robust nu trebuie s fie afectat de datele de
intrare eronate. Comportarea cea mai normal n astfel de situaii ar fi semnalarea unor mesaje de eroare
corespunztoare.
La un produs program complex testarea este o activitate mult mai complicat. Este necesar o
testare separat a fiecrui modul n parte, o testare a interfeei dintre module i o testare a produsului n
ansamblu (testarea de integrare).
Testarea de integrare se refer la funcionarea programului realizat n ansamblu. Dup ce fiecare
modul n parte a fost testat i corectat, deci n ipoteza c fiecare modul n parte este corect, e necesar s se
verifice comportarea global a programului. n aceast etap gsirea erorilor, nlturarea cauzelor care lea generat i corectarea lor, poate fi
foarte dificil, mai ales atunci cnd ele provin dintr-o proiectare greit.
Execuia unui program se poate termina anormal datorit apariiei unor erori ca:
mpriri la zero;
alte erori ce provoac depiri;
neconcordana ntre parametri actuali i formali;
depirea dimensiunii tablourilor.
Dar chiar i la execuia normal a programului putem avea erori, unele foarte grave, obinnd
rezultate greite. n ambele situaii urmeaz depanarea programului, adic descoperirea cauzei erorilor
i nlturarea lor.
29

O metod util n depanarea programelor, n special pentru nceptori, este inserarea n program a
unor tipriri auxiliare. Mai ales n locurile vecine cu instruciunile care au provocat eroarea i pentru
variabilele implicate n producerea ei. Observarea valorilor unei variabile, a schimbrilor fcute n timpul
execuiei, pot dezvlui programatorului cauza erorii. Cu siguran i va arta c o anumit variabil ia alte
valori dect cele la care se ateapt el. De altfel, pe timpul testrii unui program, sunt utile semnalrile
oricror semne de eroare. Recomandm verificarea valorilor variabilelor imediat dup obinerea
acestora.
4.3 Complexitatea algoritmilor
n aceast seciune ne va interesa eficiena unui algoritm. Mai exact, ne intereseaz s comparm
ntre ei mai muli algoritmi care rezolv aceeai problem. Care dintre ei este mai bun? Evident, vom
compara numai algoritmi despre care tim c sunt coreci.
Putem compara doi algoritmi n raport cu:
cantitatea de memorie necesar;
viteza de lucru, deci timpul necesar rezolvrii problemei.
Dac n urm cu dou decenii volumul de memorie necesar rezolvrii unei probleme era un factor
important din cauza memoriei reduse existente la calculatoarele din acel timp, astzi acest factor a devenit
mai puin important. Calculatoarele actuale au memorie suficient de mare pentru marea majoritate a
algoritmilor ntlnii.
Timpul necesar execuiei unui program depinde de numrul operaiilor ce trebuiesc executate. Iar
numrul operaiilor efectuate depinde de datele de intrare, deci se schimb de la o execuie la alta.
Exist ns un cel mai ru caz, pentru acele date de intrare pentru care numrul operaiilor
efectuate este maxim. n acest caz vorbim de complexitate n cel mai ru caz.
De asemenea, putem vorbi de numrul mediu de operaii efectuate ntr-o execuie. Dac numrul
execuiilor posibile este finit atunci acest numr mediu este egal cu numrul operaiilor efectuate n toate
execuiile, mprit la numrul execuiilor. Sunt ns foarte puine programe cu aceast proprietate. Pentru
aproape toate programele, cel puin teoretic, numrul execuiilor posibile este infinit.
4.4 Documentarea programelor
n paralel cu elaborarea programului trebuie elaborat i o documentaie. Aceasta va conine toate
deciziile luate n crearea programului. Documentarea este activitatea de prezentare a programului celor
care vor fi interesai s obin informaii despre el. Acetia sunt n primul rnd persoanele care au realizat
programul, apoi persoanele care-l vor folosi i persoanele solicitate s fac ntreinerea acestuia.
Adeseori se ntlnesc programe fr nici o alt documentaie n afara textului propriu-zis al
programului. n graba de a termina ct mai repede, programul nu este nsoit de nici o documentaie i
frecvent nu sunt folosite nici comentarii n textul programului.
Sigur c nsi textul programului constituie o autodocumentare. Iar comentariile prezente n
program dau explicaii suplimentare despre program. Este ns necesar o documentaie complet, scris,
care va conine:
enunul iniial al problemei;
specificaia (vezi seciunea 4.1);
documentaia de proiectare (metoda de rezolvare aleas i proiectarea algoritmilor
folosii. Pentru fiecare algoritm va fi prezentat subproblema corespunztoare, cu
specificaia ei i rolul fiecrei variabile);
documentaia de programare, care va include textul programului;
datele de test folosite;
documentaie privind exploatarea programului;
modificri fcute n timpul ntreinerii programului.
30

Menionm c cele mai recente produse realizate de firmele consacrate au, pe lng documentaia
scris, i o autodocumentaie (funcii HELP).
Referitor la autodocumentare, folosirea comentariilor, alegerea cu grij a denumirii
variabilelor, ct i claritatea textului, obinut prin indentare i grij asupra structurii
programului, este util nu numai pe timpul elaborrii programului, dar mai ales pe timpul ntreinerii i
modificrilor ulterioare.
Denumirea variabilei s fie astfel aleas nct s redea ct mai bine semnificaia ei.
Cei care au dorit s refoloseasc programe scrise cu cteva luni n urm neleg foarte bine
diferena dintre un program nsoit de comentarii explicative i un program fr nici o explicaie. Uitarea
acioneaz asupra oricrei persoane i, chiar dac este posibil, descifrarea unui program cere timp i nu
este o sarcin prea uoar. Comentariile sunt recomandate, fiind un mijloc de autodocumentare a
programului surs.
Sigur c prima documentaie a oricrui program este textul surs propriu-zis. Este bine ca acest
text s poat fi citit ct mai uor, iar programarea structurat duce la un program mai uor de citit dect
unul lipsit de orice structur.
Este ns nevoie i de o documentaie nsoitoare scris, care constituie documentarea propriu-zis
a programului. Aceasta trebuie s redea toate deciziile fcute n timpul proiectrii, s prezinte diagrama de
structur a ntregului produs i fiecare parte separat. Pentru fiecare modul documentaia va conine:
numele acestuia;
datele de intrare;
datele de ieire;
funcia realizat de modulul respectiv;
variabilele folosite i semnificaia lor;
algoritmul propriu-zis.
Este necesar ca aceste informaii s se afle i sub forma unor comentarii n textul programului. De
asemenea, documentaia va conine i textul final al programului.
Este necesar i o documentaie de folosire a produsului realizat. Beneficiarul nu este interesat de
modul n care a fost realizat programul ci de modul n care l poate folosi.
O documentare complet a unui program poate fi util nu numai pentru folosirea i ntreinerea
programului. Componente ale unui produs existent pot fi utile i n realizarea altor produse. Este ns
necesar s se neleag ct mai uor ce funcii realizeaz aceste componente i cu ce performane.
Folosirea acestor componente existente, testate i documentate, duce evident la creterea productivitii n
realizarea noului produs.
4.5 Stil n programare
Fiecare programator are stilul s propriu de concepere i redactare a unui program. Este bine ca el
s respecte anumite reguli generale de programare, astfel nct programele elaborate s aib anumite
caliti.
Calitile pe care le poate avea un program sunt urmtoarele:
Corectitudine = proprietatea programului de a respecta specificaiile i a da rezultate corecte;
Extensibilitate = posibilitatea adaptrii programului la unele schimbri n specificaie;
Robustee = abilitatea de a recunoate situaiile n care problema ce se rezolv nu are sens i de a se
comporta n consecin (de exemplu, prin mesaje de eroare corespunztoare);
Reutilizabilitate = posibilitatea reutilizrii ntregului program sau a unor pri din el n alte aplicaii;
Compatibilitate = uurina de combinare cu alte produse program;
Portabilitate = posibilitatea de folosire a produsului program pe alte sisteme de calcul, diferite de cel pe
care a fost conceput;
Eficien = msura n care sunt bine folosite resursele sistemului de calcul;
Claritate = uurina citirii i nelegerii textului programului, a structurilor din care este compus i a
rolului denumirilor i prilor sale.
31

Un produs program este considerat de calitate dac are calitile de mai sus, dac lansat n
execuie d rezultate corecte, dac textul lui se poate citi i nelege, dac poate fi uor ntreinut i dac
este terminat la data fixat.
Stilul unui programator este dat de msura n care programul su are aceste caliti i de
vizibilitatea lor. Evident, pe lng aceste caliti, vizibile i n text, stilul de programare este dat i de
corectitudinea i robusteea produselor realizate. Programul trebuie s funcioneze i la introducerea unor
date greite (pentru care problema nu are sens), recunoscnd aceast situaie i semnalnd-o. n acelai
timp rezultatele obinute pentru date pentru care problema are sens trebuie s fie corecte. Iar
corectitudinea sau incorectitudinea programului este o consecin a modului n care programatorul a
respectat regulile de programare (vezi capitolul 8) i a experienei obinute n activitatea de programare.
Privind claritatea algoritmului trebuie s observm c indentarea (paragrafarea) este un alt mijloc
de a mri claritatea scrierii. Textul unui algoritm poate fi scris cuvnt dup cuvnt, completnd tot rndul
asemeni textului unui roman. Claritatea lui este mic, dup cum urmeaz:
PROGRAMUL CLASAMENT ESTE:
DATE m,n,NUMEi, i=1,n, NOTEi,j, j=1,m, i=1,n;
PENTRU i:=1,n EXECUT {calculeaz media general a elevului i}
FIE S:=0;
PENTRU j:=1,m EXECUT S:=S+NOTEi,j SFPENTRU
FIE MEDIIi:=S/M
SFPENTRU
PENTRU j:=1,m EXECUT
CHEAM ORDINE(n,NOTEj,O);
CHEAM TIPAR(n, NUME, O)
SFPENTRU
CHEAM ORDINE(n,MEDII,O);
CHEAM TIPAR(n,NUME,O)
SFALGORITM
Considerm c fiecare programator trebuie s respecte anumite reguli de scriere a programelor, cu
gndul la claritatea textului. n unele cri sunt date mai multe reguli de indentare. Astfel, Gries sugereaz
urmtoarele reguli:
- instruciunile unei secvene se vor scrie aliniate, ncepnd toate n aceeai coloan;
- instruciunile unei structuri de calcul (instruciuni compuse) se vor scrie ncepnd toate
din aceeai coloan, aflat cu 2-4 caractere la dreapta fa de nceputul instruciunii
compuse;
- pe o linie pot fi scrise mai multe instruciuni, cu condiia ca ele s aib ceva comun.
Astfel, 2-4 instruciuni scurte de atribuire pot fi scrise pe acelai rnd. Acest lucru se
recomand n vederea unei scrieri compacte a programului. E bine ca un program ce se
poate scrie pe o pagin, cu respectarea structurii lui, s nu fie ntins pe dou pagini !
Considerm c nu exist reguli de scriere obligatorii pentru toat lumea! Dar fiecare programator
trebuie s aib propriile lui reguli de scriere.
Tot privind claritatea scrierii programului, se recomand ca denumirile variabilelor s fie astfel
alese nct s reflecte semnificaia acestor variabile.
Un alt mijloc de a mri claritatea textului unui program const n inserarea comentariilor n text.
Comentariile sunt texte explicative nchise ntre acolade. Ele au rolul de a explica cititorului anumite
pri din program. Am spus deja c n proiectarea algoritmilor folosim i propoziii nestandard care vor fi
pe parcurs nlocuite cu propoziii standard. E bine ca aceste propoziii s rmn n text sub form de
comentarii.
Comentariile vor fi prezente:
n capul programului, pentru a prezenta titlul i scopul programului, perioada realizrii
lui i numele programatorului;
32

n definiii, pentru a descrie semnificaia notaiilor folosite (a variabilelor, constantelor,


SUBPROGRAMilor etc);
n dreapta unor instruciuni, pentru a descrie rolul acestora, sau cazul n care se atinge
acea instruciune;
ntre prile unui modul mai lung, pentru a explica rolul fiecrei pri.
Sperm c prin exemplele date n acest material am prezentat un stil propriu de programare i am
convins cititorul de necesitatea formrii propriului su stil.

33

CAPITOLUL V
CLASE DE ALGORITMI
Cutarea i Sortarea sunt dou dintre cele mai des ntlnite subprobleme n programare. Ele
constituie o parte esenial din numeroasele procese de prelucrare a datelor. Operaiile de cutare i
sortare sunt executate frecvent de ctre oameni n viaa de zi cu zi, ca de exemplu cutarea unui cuvnt n
dicionar sau cutarea unui numr n cartea de telefon.
Cutarea este mult simplificat dac datele n care efectum aceast operaie sunt sortate
(ordonate, aranjate) ntr-o anumit ordine (cuvintele n ordine alfabetic, numerele n ordine cresctoare
sau descresctoare).
Sortarea datelor const n rearanjarea coleciei de date astfel nct un cmp al elementelor
coleciei s respecte o anumit ordine. De exemplu n cartea de telefon fiecare element (abonat) are un
cmp de nume, unul de adres i unul pentru numrul de telefon. Colecia aceasta respect ordinea
alfabetic dup cmpul de nume.
Dac datele pe care dorim s le ordonm, adic s le sortm, sunt n memoria intern, atunci
procesul de rearanjare a coleciei l vom numi sortare intern, iar dac datele se afl ntr-un fiier
(colecie de date de acelai fel aflate pe suport extern), atunci procesul l vom numi sortare extern.
Fiecare element al coleciei de date se numete articol iar acesta la rndul su este compus din
unul sau mai multe componente. O cheie C este asociat fiecrui articol i este de obicei unul dintre
componente. Spunem c o colecie de n articole este ordonat cresctor dup cheia C dac C(i) C(j)
pentru 1i<jn, iar dac C(i) C(j) atunci irul este ordonat descresctor.
5.1 Algoritmi de cutare
n acest subcapitol vom studia cteva tehnici elementare de cutare i vom presupune c datele se
afl n memoria intern, ntr-un ir de articole. Vom cuta un articol dup un cmp al acestuia pe care l
vom considera cheie de cutare. n urma procesului de cutare va rezulta poziia elementului cutat (dac
acesta exist).
Notnd cu k1, k2, ...., kn cheile corespunztoare articolelor i cu a cheia pe care o cutm, problema
revine la a gsi (dac exist) poziia p cu proprietatea a = kp.
De obicei articolele sunt pstrate n ordinea cresctoare a cheilor, deci vom presupune c
k1 < k2 < .... < kn .
Uneori este util s aflm nu numai dac exist un articol cu cheia dorit ci i s gsim n caz contrar locul
n care ar trebui inserat un nou articol avnd cheia specificat, astfel nct s se pstreze ordinea existent.
Deci problema cutrii are urmtoarea specificare:
Date a,n,(ki, i=1,n);
Precondiia: nN, n1 i k1 < k2 < .... < kn ;
Rezultate p;
Postcondiia: (p=1 i a k1) sau (p=n+1 i a > kn) sau (1<pn) i (kp-1 < a kp).
Pentru rezolvarea acestei probleme vom descrie mai muli SUBPROGRAMi.
O prim metod este cutarea secvenial, n care sunt examinate succesiv toate cheile.
{nN, n1 i}
{k1 < k2 < .... < kn}
{Se caut p astfel ca:}
{(p=1 i a k1) sau (p=n+1 i a>kn)}
{sau (1<pn) i (kp-1 < a kp)}
{Cazul "nc negasit"}

SUBPROGRAMul CautSecv(a,n,K,p) este:

Fie p:=0;

34

Dac ak1 atunci p:=1 altfel


Dac a>kn atunci p:=n+1 altfel
Pentru i:=2; n execut
Dac (p=0) i (aki) atunci p:=i sfdac
sfpentru
sfdac
sfdac
sf-CautSecv
Se observ c prin aceast metod se vor executa n cel mai nefavorabil caz n-1 comparri,
ntruct contorul i va lua toate valorile de la 2 la n. Cele n chei mpart axa real n n+1 intervale. Tot
attea comparri se vor efectua n n-1 din cele n+1 intervale n care se poate afla cheia cutat, deci
complexitatea medie are acelai ordin de mrime ca i complexitatea n cel mai ru caz.
Evident c n multe situaii acest algoritm face calcule inutile. Atunci cnd a fost deja gsit cheia
dorit este inutil a parcurge ciclul pentru celelalte valori ale lui i. Cu alte cuvinte este posibil s nlocuim
ciclul PENTRU cu un ciclu CTTIMP. Ajungem la un al doilea algoritm, dat n continuare.
SUBPROGRAMul CautSucc(a,n,K,p) este:
{nN, n1 i}
{k1 < k2 < .... < kn}
{Se caut p astfel ca:}
{(p=1 i a k1) sau (p=n+1 i a>kn)}
{sau (1<pn) i (kp-1 < a kp).
Fie p:=1;
Dac a>k1 atunci
Cttimp pn i a>kp execut p:=p+1 sfct
sfdac
sf-CautSecv
O alt metod, numit cutare binar, care este mult mai eficient, utilizeaz tehnica "divide et
impera" privitor la date. Se determin n ce relaie se afl cheia articolului aflat n mijlocul coleciei cu
cheia de cutare. n urma acestei verificri cutarea se continu doar ntr-o jumtate a coleciei. n acest
mod, prin njumtiri succesive se micoreaz volumul coleciei rmase pentru cutare. Cutarea binar
se poate realiza practic prin apelul funciei BinarySearch(a,n,K,1,n), descris mai jos, folosit n
SUBPROGRAMul dat n continuare.
SUBPROGRAMul CautBin(a,n,K,p) este: {nN, n1 i k1 < k2 < .... < kn}
{Se caut p astfel ca: (p=1 i a k1) sau}
{(p=n+1 i a>kn) sau (1<pn) i (kp-1 < a kp)}
Dac ak1 atunci p:=1 altfel
Dac a>kn atunci p:=n+1 altfel
p:=BinarySearch(a,n,K,1,n)
sfdac
sfdac
sf-CautBin
Funcia BinarySearch (a,n,K,St,Dr) este:
Dac StDr-1
atunci BinarySearch:=Dr
altfel m:=(St+Dr) Div 2;
Dac aK[m]
atunci BinarySearch:=BinarySearch(a,n,K,St,m)
altfel BinarySearch:=BinarySearch(a,n,K,m,Dr)
sfdac
35

sfdac
sf-BinarySearch
n funcia BinarySearch descris mai sus, variabilele St i Dr reprezint capetele intervalului de
cutare, iar m reprezint mijlocul acestui interval.
Se observ c funcia BinarySearch se apeleaz recursiv. Se poate nltura uor recursivitatea, aa
cum se poate vedea n urmtoarea funcie:
Funcia BinSeaNerec (a,n,K,St,Dr) este:
Cttimp Dr-St>1 execut
m:=(St+Dr) Div 2;
Dac aK[m]
atunci Dr:=m
altfel St:=m
sfdac
sfct
BinSeaNerec:=Dr
sf-BinSeaNerec
5.2 Sortare intern
Prin sortare intern vom nelege o rearanjare a unei colecii aflate n memoria intern astfel
nct cheile articolelor s fie ordonate cresctor (eventual descresctor).
Din punct de vedere al complexitii algoritmilor problema revine la ordonarea cheilor. Deci
specificarea problemei de sortare intern este urmtoarea:
Date n,K;
{K=(k1,k2,...,kn)}
Precondiia: kiR, i=1,n
Rezultate K';
Postcondiia: K' este o permutare a lui K, dar ordonat cresctor.
Deci k1 k2 ... kn.
O prim tehnic numit "Selecie" se bazeaz pe urmtoarea idee: se determin poziia
elementului cu cheie de valoare minim (respectiv maxim), dup care acesta se va interschimba cu
primul element. Acest procedeu se repet pentru subcolecia rmas, pn cnd mai rmne doar
elementul maxim.
SUBPROGRAMul Selectie(n,K) este:
{Se face o permutare a celor}
{n componente ale vectorului K astfel}
{ca k1 k2 .... kn }
Pentru i:=1; n-1 execut
Fie ind:=i;
Pentru j:=i+1; n execut
Dac kj < kind atunci ind:=j sfdac
sfpentru
Dac i<ind atunci t:=ki; ki:=kind; kind:=t sfdac
sfpentru
sf-Selectie
Se observ c numrul de comparri este:
(n-1)+(n-2)+...+2+1=n(n-1)/2
indiferent de natura datelor.
A treia metod care va fi prezentat, numit "BubbleSort", compar dou cte dou elemente
consecutive iar n cazul n care acestea nu se afl n relaia dorit, ele vor fi interschimbate. Procesul de
comparare se va ncheia n momentul n care toate perechile de elemente consecutive sunt n relaia de
ordine dorit.
36

SUBPROGRAMul BubbleSort (n,K) este:


Repet
Fie kod:=0;
Pentru i:=2; n execut
Dac ki-1 > ki atunci
t := ki-1;
ki-1 := ki;
ki:=t;
kod:=1
sfdac
sfpentru
pncnd kod=0 sfrep
sf-BubbleSort

{Ipoteza "este ordine"}

{N-a fost ordine!}


{Ordonare}

O metod mai performant de ordonare, care va fi prezentat n continuare, se numete


"QuickSort" i se bazeaz pe tehnica "divide et impera" dup cum se poate observa n continuare. Metoda
este prezentat sub forma unei proceduri care realizeaz ordonarea unui subir precizat prin limita
inferioar i limita superioar a indicilor acestuia. Apelul procedurii pentru ordonarea ntregului ir este :
QuickSort(n,K,1,n), unde n reprezint numrul de articole ale coleciei date.
SUBPROGRAMul SortareRapid (n,K) este:
Cheam QuickSort(n,K,1,n)
sf-SortareRapid
Procedura QuickSort (n,K,St,Dr) va realiza ordonarea subirului kSt,kSt+1,..., kDr. Acest subir va fi
rearanjat astfel nct kSt s ocupe poziia lui final (cnd irul este ordonat). Dac i este aceast poziie,
irul va fi rearanjat astfel nct urmtoarea condiie s fie ndeplinit:
kj ki kl , pentru st j < i < l dr
(*)
Odat realizat acest lucru, n continuare va trebui doar s ordonm subirul kSt , kSt+1 , ... ,ki-1 prin
apelul recursiv al procedurii QuickSort(n,K,St,i-1) i apoi subirul ki+1,..., kDr prin apelul
QuickSort(i+1,Dr). Desigur ordonarea acestor dou subiruri (prin apelul recursiv al procedurii) mai este
necesar doar dac acestea conin cel puin dou elemente.
Procedura QuickSort este prezentat n continuare :
SUBPROGRAMul QuickSort (n,K,St,Dr) este:
Fie i:=St; j:=Dr; a:=ki;
Repet
Cttimp kj >= a i (i<j) execut j:=j-1 sfct
ki:= kj;
Cttimp ki a i (i<j) execut i:=i+1 sfct
kj:= ki ;
pncnd i=j sfrep
Fie ki := a;
Dac St < i- 1 atunci Cheam QuickSort(n,K,St,i-1) sfdac
Dac i+1 < Dr atunci Cheam QuickSort(n,K,i+1,Dr) sfdac
sf-QuickSort
Un ultim algoritm care va fi prezentat se numete "Merge Sort" (sortare prin interclasare) i se
bazeaz pe tehnica "divide et impera". irul ce urmeaz a fi ordonat se mparte n dou subiruri care se
ordoneaz, dup care acestea se vor interclasa obinndu-se ntregul ir ordonat. Fiecare subir se va
ordona tot prin desprirea lui n dou subiruri urmat de interclasare i aa mai departe pn cnd
37

ordonarea unui subir se poate rezolva elementar fr a mai fi necesar desprirea lui n alte dou
subiruri (lungimea subirului este cel mult 2).
Algoritmul corespunztor este prezentat n seciunea urmtoare sub forma unei proceduri
recursive care ordoneaz un subir preciznd limitele acestuia.
5.3 Interclasare
Fiind date dou colecii de date, ordonate cresctor (sau descresctor) dup o cheie, se cere s se
obin o colecie care s fie de asemenea ordonat cresctor (respectiv descresctor) dup aceeai cheie i
care s fie format din articolele coleciilor date. Acest lucru se poate obine direct (fr o sortare a
coleciei finale) prin parcurgerea secvenial a celor dou colecii, simultan cu generarea coleciei cerute.
Prin compararea a dou elemente din listele de intrare se va decide care element va fi adugat n lista de
ieire.
Deci ne intereseaz un algoritm de rezolvare a problemei ce are urmtoarea specificare:
Date m, (xi, i=1,m), n, (yi, i=1,n);
Precondiia: {x1 x2 ... xm} i {y1 y2 ... yn}
Rezultate k, (zi, i=1,k);
Postcondiia: {k=m+n} i {z1 z2 ... zk} i (z1,z2,..., zk) este o permutare a valorilor
(x1, ..., xm,y1,..., yn)
O soluie posibil ar fi depunerea componentelor vectorului X i a componentelor vectorului Y n
vectorul Z, realiznd astfel a doua parte din postcondiie. Ordonnd apoi componentele vectorului Z
obinem soluia dorit. Acest algoritm, dei corect, este ineficient i, n plus, nu este util n sortrile
externe (vezi seciunea 5.4). Este important ca la o singur trecere prin vectorii X i Y s se obin
vectorul Z. Acest lucru este realizat de urmtorul algoritm de interclasare:
SUBPROGRAMul Interclasare(m,X,n,Y,k,Z) este:
{X are cele m}
{componente ordonate nedescresctor}
{La fel Y cu n componente. Cele m+n valori}
{se depun n Z, tot ordonate nedescresctor}
Fie i:=1; j:=1; k:=0;
Cttimp (i<=m) i (j<=n) execut
{Exist componente}
Dac xiyj
atunci Cheam PUNE(i,xi,k,Z)
{i n X}
altfel Cheam PUNE(j,yj,k,Z)
{i n Y}
sfdac
sfct
Cttimp (i<=m) execut
{Exist componente}
Cheam PUNE(i,xi,k,Z)
{numai n X}
sfct
Cttimp (j<=n) execut
{Exist componente}
Cheam PUNE(j,yj,k,Z)
{numai n Y}
sfct
sf-Interclasare
Aici s-a folosit SUBPROGRAMul PUNE(ind,val,k,Z) care pune n vectorul Z valoarea val i
mrete indicele ind cu 1, subalgortim dat n continuare.
SUBPROGRAMul PUNE(ind,val,k,Z) este:
k:=k+1;
zk:=val;
ind:=ind+1
sf-PUNE
38

{Adaug val}
{n vectorul Z cu}
{k componente i}
{mrete ind cu 1}

Algoritmul MergeSort de sortare bazat pe interclasare se poate vedea n continuare.


Algoritmul MergeSort este:
{Sortare prin interclasare}
Citete n;
Pentru i:=1 ; n execut Citete Ki sfpentru
Cheam SortInter (n,K);
Pentru i:=1; n execut Tiprete Ki sfpentru
sf-MergeSort
SUBPROGRAMul SortInter(n, C) este:
Cheam Ordon (1,n,C);
sf-SortInter
SUBPROGRAMul Ordon (St,Dr,A) este:

{Sortare prin interclasare a}


{elementelor ASt,ASt+1,...,ADr}

Dac St < Dr atunci


Fie m:=(St+Dr) Div 2;
Cheam Ordon (St,m,A);
Cheam Ordon (m+1,Dr,A);
Cheam Inter (St,m, m+1,Dr);
sfdac
sf-Ordon
SUBPROGRAMul Inter (s1,d1, s2,d2) este:
{ Interclasare }
Fie A:=C; k:=s1- 1;
Cttimp (s1<=d1) i (s2<=d2) execut
Dac (C[s1]<C[s2])
atunci Cheam PUNE(s1,cs1 ,k,A)
altfel Cheam PUNE(s2,cs2 ,k,A)
sfdac
sfct
Cttimp (s1<=d1) execut Cheam PUNE(s1,cs1 ,k,A) sfct
Cttimp (s2<=d2) execut Cheam PUNE(s2,cs2 ,k,A) sfct
C:=A
sf-Inter
5.4 Sortare extern
O problem cu care ne confruntm adesea este sortarea unei colecii de date aflate pe un suport
extern, de volum relativ mare fa de memoria intern disponibil. n aceast seciune o astfel de colecie
de date o vom numi fiier. n acest caz nu este posibil transferul ntregii colecii n memoria intern
pentru a fi ordonat i apoi din nou transferul pe suport extern. Dac datele ce urmeaz a fi sortate ocup
un volum de n ori mai mare dect spaiul de memorie intern de care dispunem, atunci colecia se va
mpri n n subcolecii ce vor fi transferate succesiv n memoria intern, se vor sorta pe rnd i vor fi
stocate din nou pe suportul extern sortate. Din acest moment prin operaii de interclasare dou cte dou
se pot obine colecii de dimensiuni superioare pn se obine toat colecia ordonat.
La aceste interclasri, pentru a efectua un numr ct mai mic de operaii de transfer se recomand
interclasarea coleciilor de dimensiuni minime, apoi din datele obinute din nou vor fi alese dou colecii
de dimensiuni minime i aa mai departe pn se obine o singur colecie care va fi colecia cerut, adic
sortat.
Dup metodele de sortare extern folosite, se descriu trei procedee de sortare extern:
39

sortarea echilibrat;
sortarea polifazic;
sortarea n cascad.
Evident c sortarea depinde i de configuraia calculatorului folosit, dar i de suportul pe care se
afl fiierul de sortat i fiierele intermediare create.
Principial sortarea extern presupune parcurgerea a dou etape importante:
a) Divizarea fiierului de sortat F, n n fiiere H1, H2, ..., Hn, cu sortarea intern a acestora;
b) Interclasarea acestor fiiere sortate pentru a ajunge la fiierul dorit G.

40

CAPITOLUL VI
EVOLUIA LIMBAJELOR DE PROGRAMARE
Un limbaj de programare este un sistem de convenii adoptate pentru realizarea unei comunicri
ntre programator i calculator . Limbajele folosite pentru programarea unui calculator sunt extrem de
asemntoare limbajelor naturale . Ele sunt compuse din :
cuvinte (rezervate);
punctuaie;
propoziii i fraze;
reguli sintactice etc.
Aa cum pentru nsuirea unei limbi strine trebuie nvate cuvintele acesteia i regulile cu care
pot fi manevrate tot aa pentru nsuirea unui limbaj de programare trebuie studiate cuvintele i semnele
care l compun mpreun mpreun cu regulile de manevrare a lor.
De-a lungul timpului,oamenii au inventat masini pentru a calcula cat mai eficient.Inaintea
calculatoarelor performante din zilele noastre,au existat alte masini de calcul.
Momentul iniial al istoriei calculatoarelor este, de obicei legat de numele matematicianului
englez Charles Babbage. El a propus n anul 1830 o Main Analitic care a anticipat n mod fascinant
structura calculatoarelor actuale. Ideile sale au devansat cu peste 100 de ani posibilitiile tehnologice ale
vremii sale. naintea a mai fost ncercri n acest domeniu ale lui Leibnitz i Pascal (sec al XVII-lea) .
Urmtorul moment de referin este anul 1937, cnd Howard Aiken, de la Universitatea Harvard a propus
Calculatorul cu secven de Comand Automat, bazat pe o combinaie ntre ideile lui Babbage i
calculatoarele elertromecanice, produse de firma IBM. Construcia acestuia a nceput n anul 1939 i s-a
terminat n anul 1944, fiind denumit Mark I . El a fost n principal primul calculator electromecanic, fiind
alctuit din comutatoare i relee.
nlocuirea releelor cu tuburi electronice a constituit un important pas nainte. Rezultatul a fost
concretizat n calculatorul ENIAC ( Electronic Numerical Integrator And Computer ), primul calculator
electronic digital. El conine circa 18.000 de tuburi electronice i executa 5.000 de adunri pe secund,
avnd o memorie de 20 de numere reprezentate n zecimal. Programarea sa se realiza prin poziionarea a
circa 6.000 de comutatoare, cu mai multe poziii. O semnificaie aparte o are faptul c n arhitectura
calculatoarelor Mark I i ENIAC, intrau mai multe elemente de calcul, ce lucrau n paralel la o problem
comun, fiind dirijate de o singur unitate de comand . Aceast soluie a fost aleas datorit vitezei
reduse a fiecrei uniti de calcul, n parte. La versiunea urmtoare s-a renunat la aceast structur
paralel de calcul, deoarece s-a considerat c viteza unei uniti de calcul, realizat cu circuite
electronice, este suficient . Soluia prelucrrii paralele a fost reluat ulterior dup anii 80 pentru mrirea
performanelor unui sistem de calcul; astfel n 1996 Firma INTEL a realizat un supercalculator ce
folosete peste 7000 de procesoare PENTIUM utiliznd tehnica de calcul masiv (utilizat pentru
simularea testelor nucleare, n cercetri genetice, spaiale, meteorologice).
De remarcat c la realizarea primelor calculatoare, n calitate de consultant al echipei, a lucrat i
matematicianul John von Neumann, unul dintre matematicienii importani ai secolului XX. De altfel, la
realizarea calculatorului EDVAC ( primul calculator cu circuite electronice ) el a stabilit 5 caracteristii
principale ale calculatorului cu program memorat :
Trebuie s posede un mediu de intrare, prin intermediul cruia s se poat introduce un
numr nelimitat de operanzi i instruciuni .
Trebuie s posede o memorie, din care s se citeasc instruciunile i operanzii i n care
s se poat memora rezultatele.
Trebuie s posede o seciune de calcul, capabil s efectueze operaii aritmetice i
logice, asupra operanzilor din memorie.
Trebuie de asemenea s posede un mediu de ieire, prin intermediul cruia un numr
nelimitat de rezultate s poat fi obinute de ctre utilizator.
41

Trebuie s aib o unitate de comand , capabil s interpreteze instruciunile obinute


din memorie i capabil s selecteze diferite moduri de desfurare a activitii
calculatorului pe baza rezultatelor calculelor.
Primul calculator comercializat a fost UNIVAC (UNIversal Automatic Computer ) realizat pe
structura calculatorului EDVAC, n anul 1951. n anii 1960 a aprut un nou tip de calculatoare:
minicalculatoarele. Aceste maini erau mai ieftine, mai mici, nu avea nevoie de aer condiionat i erau
mult mai uor de folosit (cel puin dup standardele acelor timpuri) fa de mainframe-uri. n fa ereziei,
preoii mainframe-urilor s-au nfiorat. Deinerea unui mainframe era problema corporaiei, datorit
cheltuielilor necesare, dar un departament putea avea propriul minicalculator, pentru c acesta nu necesita
spaii speciale sau specialiti necesari unui mainframe. Pe scurt, minicalculatoarele erau ieftine.Aceast
dezvoltare a dus la apariia unui nou personaj pe scena calculatoarelor. Minicalculatoarele au adus la
nlocuirea programatorilor de mainframe, curai i bine mbrcai, cu o nou specie de programatori.
Minicalculatoarele au nceput s fie introduse n universiti i alte instituii de nvmnt, pentru
c erau ieftine. Ele erau accesibile i proiectate pentru a putea suporta modificri ulterioare, ceea ce a
atras un grup de entuziati cunoscui sub numele de hackeri. Aceti hackers nu sunt identici cu cei din
zilele noastre. Acei hacker-i erau plini de entuziasm fa de calculatoare, oameni care voiau s fac
programe mai bune, mai rapide i mai elegante.Din rndurile lor s-au ridicat o parte din oameni care au
fcut revoluia calculatoarelor personale. Piaa minicalculatoarelor a crescut repede. Imediat ce
departamentele puteau justifica nevoia minicalculatorului, acesta era instalat. Acesta a fost momentul
cnd DEC (Digital Equipment Corporation) a devenit a doua mare companie productoare de calculatoare
din lume.n privina mbuntirilor aduse programelor, gama funciilor care pot fi realizate a crescut. Un
minicalculator poate fi folosit simultan de mai muli utilizatori, cu ajutorul unui procedeu de mprire a
timpului de folosire a procesului numit time-sharing. Astfel, fiecare utilizator poate s prelucreze date, s
creeze programe sau s utilizeze, ca i cnd ar fi singurul utilizator. Acest sistem a fost introdus i n
tehnologia de realizare a mainframe-urilor. Sisteme sofisticate de time-sharing, cu componente disc mai
puternice i programe mai sofisticate, au fost dezvoltate n acelai timp pentru mainframe-uri.Aceasta era
piaa calculatoarelor n anii 70: mainframe-uri i minicalculatoare erau prezente n toate companiile i
principalele departamente. Pentru sacinile pe care le puteau rezolva n moduri n care le rezolvau, erau
bune. Au adus metode noi i eficiente n birouri i au fcut afacirele mai eficiente. Totui, au euat n
mrirea productivitii personale (n creterea eficienei personalului, nu a corporaiilor).
Apariia calculatoarelor personale
La mijlocul anilor 70 a aprut o nou tehnologie: miniprocesorul. Acesta folosea multe
tranzistoare conectate pe o pastil de siliciu pentru a realiza un dispozitiv de calcul.Primele
microprocesoare au fost, dup standardele actuale, destul de simple. Primul microprocesor, devine
cunoscut ca 4004, a fost proiectat pe patru bii de ctre inginerul Marcian E. Ted Hoff de la Intel, n
anul 1969. Clientul care i-a comandat lui Intel microprocesorul a fost o firm japonez, care a dat
faliment n 1970; dup aceasta Intel nu se putea hotr dac s lanseze sau nu circuitul pe pia. L-au
lansat, i n 1974 existau mai mult de 19 tipuri de microprocesoare pe pia, inclusiv Intel 8088, cel care
va deveni trambulina actualelor calculatoare personale.Microprocesoarele au fost iniial folosite drept
controler - dispozitive de control pentru maini de splat vesel i frigidere. Productorii i proiectanii
de calculatoare nu au pierdut ocazia dat de potenial acestor dispozitive de a fi folosite drept
calculatoare.
8080, Z80, CP/M
Primele succese ale pieei au fost microprocesorul Intel 8080 i noul sistem de operare numit
CP/M-80 scris pentru acest cercuit. CP/M-80 a fost creat n 1975 de Gary Kildall, fondatorul i
preedintele companiei Digital Research primul productor al unui sistem de operare pentru
microcalculatoare. Astzi, compania este o divizie a lui Novell Inc. cea mai mare companie n domeniul
sistemelor de operare n reea.CP/M este prescurtat de la Controlul Programului/Microcalculatorului cel
mai sugestiv nume de produs, dac mai existase unul, de pn atunci. Acest sistem de operare a fost, la
42

acea dat, extraordinar. Dac aveai un sistem 8080 sau Z80, cu sistem de operare CP/M, cu 64 kilobii de
RAM i o pereche de uniti de disc flexsibil de 8", aveai ultimul strigt al modei calculatoarelor i l
fceai verde de invidie pe orice pasionat. Un singur lucru le putea depi invidia i ctiga ura: s ai un
disc i o imprimat; ambele necesitau o cheltuial exorbitant.Discurile acelor timpuri merit puin
atenie. Primul tip larg rspndit mpreun cu microcalculatoarele aveau discuri de 14" (comparai-le cu
cele de 3,5" disponibile astzi) i un timp de acces suficient pentru o pauz de cafea.
Apple Computer, binecunoscut ca avndu-i nceputurile ntr-un garaj, a aprut n 1976. Apple a fost
fondat de legendarii Steve Jobs i Steve Wozniack, i este recunoscut drept compania care a pus bazele
industriei calculatoarelor personale. Dei povestea lui Visilac i a calculatorului Apple II este bine
cunoscut, merit s o spunem nc o dat, pentru c arat motivele care au generat revoluia
calculatoarelor personale.La mijlocul anilor `70, dac doreai s faci ncercri de genul i dac calculnd
pe mainframe, trebuia s scrii un program, s-l depanezi, s ncerci un set de date, s verifici rezultatele,
s ncerci un set de date mai complex s.a.m.d. Era un procedeu cel puin laborios i nu foarte practic, cu
excepia cazului n care priviziunele aveau importan pentru corporaie i aveai suficient timp la
dispoziie. Aceast situaie a motivat doi studeni de la Harvard Business School s fac primul program
de calcul tabelar: Visicalc.Apple II avea la baz un procesor Motorola 6502 (proiectat pe 8 bii), pn la
128 kilobii de RAM i utiliza un casetofon pentru a stoca date i programe. Apple a ncheiat o nelegere
cu realizatorii lui Visicalc pentru a obine exclusivitatea programului pe Apple II. Acestui program i se
acord meritul de a fi catapultat Apple de la un venit de 800.000 de dolari n 1977 la puin sub 48 de
milioane n 1979.Utilizatorii cumprau Apple II doar pentru a rula Visicalc, i o dat cu el un raft ntreg
de aplicaii, care ofereau utilizatorilor, pentru prima dat la un pre rezonabil, putere de calcul accesibil
i dedicata
IBM preia controlul
Calculatoarele despre care am vorbit, mainile CP/M i Apple, nu erau numite calculatoare
personale acesta nu a fost un termen recunoscut pn n august 1981, data de natere a calculatorului
IMB PC a fost creat de pia, datorit acelor sisteme de microcalculatoare care au fcut posibil existena
calculatorului IBM PC.Dei microprocesorul care a stat la baz calculatorului IBM PC a fost produs n
1974, calculatorul IBM PC a fost produs abia n 1981. Intel 8088 era un microprocesor pe 16 bii, care
putea lucra cu mai mult memorie i mai rapid dect predecesorii si. IBM a delegat o companie
necunoscut, numit Microsoft, pentru a realiza un sistem de operare. Restul este, aa cum o spun ei,
istorie. IBM PC a devenit un standard, n realitate o serie de standarde care au adus la vnzarea de
aproximativ 100 de milioane de calculatoare personale din 1981. puterea marketing-ului IBM a dus la
succesul lui IBM PC. IBM avea bani i poziia pe pia astfel nct s fac calculatorul IBM PC acceptat
n corporaii. Dei e uor s critici IBM pentru greelile, destul de multe, fcute n dezvoltarea pieei
calculatoarelor personale i lipsa de receptivitate fa de o pia care cretea mai rapid dect putea acoperi
IBM, fr amestecul lui IBM, aceast pia ar fi crescut mult mai ncet i mai fragmentat.
Calculatorul IBM PC a continuat tendina dat de Apple II, aducnd puterea de calcul la ndemna
utilizatorilor. Posibilitatea de a-i mbunti i mri productivitatea personal a fost o atracie att de
mare, nct oamenii au trecut peste orice pentru a-i cumpra un calculator personal. Ei au pclit
bugetele departamentale cumprndu-le ca maini de scris sau chiar pltind diferena din propriul
buzunar.
Multe companii au avut reineri n a urma tendina de introducere a calculatoarelor personale, dar
au descoperit ulterior c acestea erau folosite din plin de concurena. n aceste companii, de obicei,
Centrul de Calcul era uluit cnd descoperea invazia calculatoarelor personale. Fanaticii mainframe-urilor
erau probabil cei mai surprini cnd aflau ce se ntmplase.
Aparent peste noapte, Centrul de Calcul pierdea un procent destul de mare din prelucrrile de date
ale companiei. Teritoriul pe care credeau c l stpnesc era brusc invadat. Ceea ce era probabil cel mai
tulburtor pentru ei era c utilizatorii de calculatoare personale vorbeau despre informaii i nu doar
despre coloane de date.
43

Utilizatorii au descoperit c puteau combina i prelucra cum doresc datele. Puteau realiza rapoarte
despre ceea ce i interesa. Pe de alt parte, dac ai fi cerut la Centrul de Calcul un raport, i-ar fi dat doar
un raport standard aa cum le genera mainframe-ul. (Rapoartele standard consumau o mic pdure de
hrtie, cnd toi utilizatorii doreau doar o pagin ).
Astfel a aprut o nou tendin: aceea de a a-i realiza singur calculele. Atunci cnd utilizatorii
doreau s fac simulri financiare de tipul i dac, ei nu mai trebuiau s mearg, cu plria n mn
(metamorfic vorbind) la Centrul de Calcul. Puteau s-i porneasc calculatorul personal, s ruleze
programul de calcul tabelar i s realizeze o duzin de scenarii, n timpul n care Centrul de Calcul ar fi
luat n considerare cererea lor.Deja nu mai exista nici o posibilitate pentru Centrul de Calcul de a
schimba lucrurile. Corporaiile aveau toate motivele s susin noua tendin i n acelai timp destule
motive de ngrijorare pentru anarhia care se crea. Distribuirea datelor prin companii, cum vei vedea, avea
multe implicaii i exista marele risc de a scpa totul de sub control.
Revoluia calculatoarelor personale, mai mult dect orice, a forat Centrele de Calcul s-i
regndeasc rolul i tehnologia pe care o foloseau. Ele nu au avut cu adevrat de ales i au devenit
Servicii de gestiunea de informaie (Management Information Service) sau IT (Information Tehnology)
sau orice altceva care coninea cuvntul informaie. De asemenea, au trebuit s urmeze sau cel puin s se
obinuiasc cu valul tehnologiilor aduse de calculatoarelor personale.
nceputul conectrii
Pe timpul CP/M-ului, preul perifericilor de calitate era exorbitant. Un disc de 14" i 10MB, care
consuma 5 amperi i fcea zgomot ca un avion care decola, era tot att de scump ca i un calculator. O
imprimat matriceal, care nici nu se apropia de calitatea unei letter-quality, era o resurs preioas. n
momentul lansrii calculatorului IBM PC preurile sczuser, dar erau nc destul de mari. Pe scurt,
perifericele calculatoarelor personale erau ca aurul: rare i scumpe.
Nu era practic ca fiecare calculator s aib disc i imprimat, dei fr ele productivitatea calculatoarelor
personale era mai mic. O alt problem era folosirea n comun a datelor. Dac aveai nevoie de un
document creat de altcineva, trebuia s iei dischet, s-i pui pantofii de sport i s alergi la acel
microcalculator s-l iei. De aici, numele acestui tip de partajare a datelor: reea sportiv.
Reeaua sportiv
Acest tip de reea a ridicat multe probleme. Cum puteai s fii sigur c documentele cu care lucrai
erau la zi, dac diverse copii modificate de un numr oarecare de oamenii circulau pe diverse dischete?
Cum poi opri furtul documentelor? Cum poi opri furtul documentelor? i dac ultima versiune, i
singura, a unui document se afl pe o singur dischet folosit de cineva drept suport pentru ceac de
cafea? i dac...?
Existau sute de probleme cu aceast reea i toate evideniau o singur soluie: nevoia, absolut necesitate,
de a schimba documentele electrice ntre calculatoare. Combinai cu dorina de a schimba, de a folosi n
comun discuri i imprimate scumpe, i avei o problem la care s meditai. Nevoia de a folosi n comun
date i periferice a stimula crearea primei reele locale de calculatoare, dar aa cum vei vedea, problema
central a fost nevoia de a folosi n comunicatie.
Comutatoarele de date
O modalitate de a folosi n comun periferice a fost folosirea unui comutator de date: un dispozitiv
ce permite doar unui utilizator la un moment dat s foloseasc dispozitivul, ca exemplu o imprimat.
Dac o alt persoan folosea imprimata cnd doreai tu s o foloseti, trebuia s atepi pn termina. Un
comutator de date poate fi comparat cu o coad la banc. Orice persoan (datele ce vor vi imprimate) care
se aeaz prima coad (comutatorul) ajunge prima la casier (imprimanta). Restul trebuia s atepte pn
ce aceasta termin.
Comutatorul de date ofer utilizatorului o conexiune pe portul serial sau paralel, pe baz creia
primul utilizator care cere primete dreptul de folosi imprimanta. Calculatorul care nu mai are nevoie de
periferic trebuie s trimit o secven de caractere prin care spune de fapt Am terminat.
44

Aceste dispozitive, dei erau bune pentru imprimant i plotere (ele nc mai sunt folosite cteva
companii nc le mai ofer ), nu permiteau folosirea n comun a discurilor. De asemenea, necesitau o linie
dedicat ntre calculator i comutator. Aceasta devenea dificil de realizat cnd calculatoarele erau
rspndite pe o suprafa mare, i imposibil dac erau mai multe calculatoare.
Aici servesc discuri
Prima ncercare de a realiza ceea ce astzi numim reea local (LAN) a fost tehnologie, acum
nvechit, numim disc server. Un disc server era un calculator, prin care, printr-o tehnic de comunicaie
oarecare, era legat de un grup de calculatoare numit clieni. El rula un sistem de operare special care era
proiectat astfel nct s poat permit accesul mai multor clieni n acelai timp la disc i la imprimat:
acest sistem se numete sistem de operare pentru reea (Network Operating System sau NOS).
Funcionarea reelei
Aplicaia client/server
Primele aplicaii de reea erau n majoritate programe integrate. De exemplu, dac ofereau o baz
de date multiutilizator ele aveau i partea frontal (front-end) de interaciune cu utilizatorului i motorul
bazei de date (partea de program care lucra cu fiierele bazei de date) pe acelai PC. Singura parte care se
putea afla n reea, pe server, era baza de date.
n aceast configuraie, calculatorul client realiza toat prelucrarea datelor (citire, cutare a
nregistrrilor dorite ntre datele citite etc.). Aplicaiile acestea pot fi descrise ca avnd doar client.
Serverul era o simpl pomp de date: trimitea utilizatorului date din fiierele aflate pe disc sau le
primea i le stoca pe disc.
n ultimii ani au aprut un numr mare de sisteme de baz de date sofisticate care pun n reea
motorul de acces la baza de date care se afl n parte frontal (front-end) utilizatorul. Acestea se numesc
sisteme client/server.
O dat cu mbuntirea performanelor datorit eliminrii suprancrcrii reelei cu transferuri
mari de date, mai exist i avantajul faptului c serverul poate deservi mai muli clieni n acelai timp.
ntregul proces de sincronizare al accesului la baza de date, care trebuia realizat de clieni, este acum
realizat de server, ceea ce face aplicaiile mai simple i ntregul sistem mai eficient.
Bazele de date nu sunt singurele aplicaii care pot fi realizate n sistem client/server. Alte aplicaii
client/server includ servere de pot electronic, sisteme de vizualizare pe calculator a imaginilor i
urmrire serviciilor de reea.
Avantajele sistemelor client/server sunt urmtoarele:
securitate mai bun, deoarece accesul la datele din baza de date server este indirect.
Utilizatorii nu pot vedea fiierele de date dect dac li se d acest drept n mod explicit.
Performanele pot fi mbuntite uor, deoarece o mai bun proiectare a serverului
poate duce la o mai bun coordonare a utilizatorilor care doresc servicii n acelai timp i,
de aici, performane mai bune. n cazul severelor de baze de date prin reea pentru a gsi ce
i intereseaz; e suficient ca ele s trimit cereri ctre server, iar serverul le va trimite doar
rezultatele pe care le doresc.
Crete raportul calitate/pre. Clienii trebuie doar s aib suficient putere de calcul pentru a rula
partea frontal (front-end). (Cnd sunt necesare performane mai mari, serverul poate fi nlocuit cu un
calculator personal mai performant i, respectiv, mai scump).
Dezavantajele sistemelor client/server:
Complexitatea: nu este simplu, de obicei, s configurezi i s administrezi sisteme
client/server.
Necesiti: pentru a avea muli utilizatori, serverul din sistemele client/server are nevoie de un
calculator scump. Aplicaiile de pe server au tendina s devie mai mari i mai complexe i au nevoie de
mai mult memorie RAM.
Pre: performanele serverului scad o dat cu creterea numrului de utilizatori. Pentru a reface
performanele, serverul de baz de date trebuie s ruleze pe o main dedicat acelui server. Deci, acolo
45

unde cndva era un server dedicat general, care funciona i ca server de baz de date, acum avem un
server dedicat general i un server de baze de date dedicat, ceea ce duce cel puin la dublarea costului.
Tehnologii de grup
Tehnologiile de grup (groupware) sunt un set de tehnologii care au scopul de a mbunti
productivitatea a doi sau mai muli utilizatori care coopereaz n realitate unor obiective comune. Ideea
este ca o dat ce reeaua unete utilizatorii, munca i comunicrile cu privire la ea pot fi automatizate
pentru mbuntirea fluxului muncii i a oportunitilor. Teoretic, un grup de oameni care muncesc
mpreun ntr-o activitate comun sau pentru obiective comune poate fi mult mai eficient dect un grup
de oameni care muncesc independent. Deoarece calculatoarele mbuntesc dialogul ntre membrii
grupului i urmresc progresele lor, detaliile nu vor mai fi omise, iar desfurarea poate fi foarte uor de
urmrit.
Aceste idei au fost aplicate la procese cum sunt planificate i administrate proiectelor. Planificarea
n reea permite unui grup dintr-o reea s-i fac orare pe reea. Cnd vor s-i coordoneze activitile, de
exemplu s stabileasc o ntlnire, orarul grupului poate fi examinat i poate fi gsit momentul cnd toi
membrii sunt disponibili. Folosind pota electronic, acetea pot fi rugai s va edin (sau n
organizaiile mai autoritate li se ordon).
Alte caracteristici ale aplicaiei de grup:
Sisteme de informare (oferite n sisteme de pot electronic cum ar fi cc: Mail).
Baze de date folosite n comun.
Sisteme de conducere a proiectelor.
Servicii de bibliotec (pentru administrarea documentaiilor aparinnd unui grup).
Sisteme de control al versiunii (asemntoare cu serviciul de bibliotec, dar cu faciliti
de control al arhivrii i gsirii diverselor versiuni de fiier; aceste sisteme sunt de obicei
folosite pentru dezvoltarea programelor).
Una dintre cele mai ludate aplicaii ale tehnologiilor de grup, Lotus Notes, este un sistem de baze
de date cu pot electronic. Rolul lui Notes este de a rspndi informaiile deinute n bazele de date ale
organizaiilor, la un numr oarecare de utilizatori. Sistemul permite duplicarea i sincronizarea mai multor
copii de baze de date.
O alt direcie principal a aplicaiilor de grup este posibilitatea urmririi fluxului muncii. Ideea
este c grupurile de utilizatori care sunt ntr-o reea pot beneficia de automatizarea activitilor de rutin.
Mare parte a sistemelor care se ocup de fluxul muncii se bazeaz pe formulare. Ele primesc date de la o
persoan, pe care apoi le transmit, dac e posibil cu date suplimentarea din alte surse, celorlali membri.
Ele au mecanisme pentru contabilizarea i urmrirea tranzaciilor i raportarea stadiului muncii.
Obiectivele vor fi mai rar uitate sau amnate, deoarece calculatoarele sunt mai de ncredere dect
oamenii. Fluxul muncii este concept att de important n reele, nct multe dintre principalele companii
productoare de produse de reea au investit n companii care dezvolt tehnologii de baz pentru suportul
fluxului muncii.
Problema cu aplicaiile de grup este c e greu ca oamenii s se obinuiasc cu ea! (Poi s duci un
cal la ap, dar nu poi s-l faci s bea.).
NIVELE ALE LIMBAJELOR DE PROGRAMARE
Nivelul unui limbaj este apreciat prin poziia pe care o ocup pe scara constituit de limbajul
recunoscut de microprocesor (limbaj main) i limbajul natural al programatorului (limba romn, limba
englez ) .
Un limbaj de nivel sczut este foarte apropiat de main, el manipuleaz cu elemente de nivel
hardware, fizic, cum ar fi : registru, microprocesor, locaie de memorie, port de intrare / ieire etc.
Un limbaj de nivel nalt sau foarte nalt manipuleaz cu concepte apropiate de limbajul natural,
concepte de nivel logic, cum ar fi: colecie de date, nume de operaie (sort, writeln, open), variabile,
constante ( asemntoare ca neles cu cele din matematic).
46

Cu ajutorul unui limbaj de nivel nalt programatorul se face mult mai uor neles de ctre
calculator . Uneori o singur limie de program scris cu un astfel de limbaj poate echivala cu sute de linii
de program scrise n limbaj main. Deci din punct de vedere al reducerii timpului de realizare a unui
program i al siguranei n funcionare (absena erorilor de programare) este de preferat un limbaj de nivel
ct mai ridicat (nalt sau foarte nalt). n schimb, pe msur ce limbajul are un nivel mai ridicat execuia
programului conceput cu ajutorul su va fi mai lent, dect a unui program ce realizeaz aceleai operaii
dar este scris n limbaj de asamblare.
O alt diferen esenial ntre cele dou tipuri de limbaje o reprezint portabilitatea, adic
posibilitatea transferrii programelor pe un alt tip de main dect cea pe care au fost construite. Din acest
punct de vedere limbajul de asamblare este neportabil deoarece el este specific microprocesorului.
Programele realizate pe un tip de main trebuie rescrise integral pentru noul tip de main , folosind un
nou set de instruciuni care deobicei difer foarte mult. Lucrurile stau altfel cu programele concepute cu
ajutorul unui limbaj de nivel nalt, deoarece acestea sunt detaate de main. ntre un astfel de program i
calculator se interpune compilatorul (sau interpretorul) care rezolv corect transformarea fiierului-surs
n fiier - executabil.
Limbaje procedurale neprocedurale
Cele dou tipuri de limbaje, procedurale i neprocedurale, se difereniaz prin nivelul de
organizare (structurare) a unui program. Limbajele neprocedurale sunt concepute pentru a gndi un
program la nivel de instruciune, pe cnd cele procedurale, oblig programatorul s conceap programe la
nivel de bloc. ntr-un limbaj procedural (numit i limbaj structurat) programele sunt scrise instruciune cu
instruciune, dar ele sunt organizate logic n blocuri (grupuri de instruciuni) ce realizeaz o aciune bine
determinat. n general un bloc are un punct de intrare i un punct de ieire nu mai multe.
Un limbaj procedural ofer posibilitatea utilizrii unui nivel ridicat de concepere a unui program i
duce la realizarea de programe coerente i protejate la erori. Prin contrast, limbajele neprocedurale nu
favorizeaz programatorul n a se desprinde de nivelul instruciune i duc deseori la programe greu de
controlat mai ales n cazul programelor de dimensiuni mari.
Limbajele neprocedurale sunt nc preferate de unii utilizatori datorit timpului foarte scurt ct
decurge nvarea i utlizarea lor.
Limbaje orientate
Din punctul de vedere al aplicabilitii unui limbaj, limbajele pot fi orientate pe o anumit
problem sau concepute pentru soluionarea oricrui tip de problem limbaje de uz general sau altfel
spus, neorientate pe o problem.
Limbajele orientate prezint un grad nalt de specificitate pe cnd un limbaj neorientat reprezint
un cadru general ce permite introducerea de ctre utilizator a conceptelor i prelucrrilor dorite.
Deci, diferena esenial dintre cele dou tipuri de limbaje o constitue nivelul conceptual definit.
Cele specializate posed deja integral suportul necesar i permit programatorului s se concentreze la
ansamblul problemei, pe cnd cele nespecializate las n sarcina programatorului manevrarea nivelelor
inferioare ale problemei.
Limbaje concurente
Un limbaj concurent permite definirea de procese (prelucrri) paralele, execuia sa fiind ramificat
la un anumit moment de timp. Prin contrast limbajele neconcurente (majoritatea limbajelor) au o
desfurare liniar, fiind activ un singur proces la un moment dat. Procesele concurente presupun n mod
obligatoriu un sistem multi-tasking ce poate gestiona mai multe sarcini la un moment dat.
Limbaje de nivel sczut
Aceast categorie de limbaje are un reprezentant autoritar i anume: limbajul de asamblare.
Diferenierile care se pot face pentru limbajele de nivel sczut sunt urmtoarele:
47

dup tipul de main;


Regulile respectate de versiunile limbajului de asamblare sunt :
nou versiune o include complet pe cea anterioar,
versiunea nou ofer funcii suplimentare i le realizeaz pe cele vechi mai rapid.
dup mediul de programare oferit.
Aspectul unui limbaj poate fi schimbat radical de mediul de programare oferit . Pentru limbajul de
asamblare exist mai multe implementri disponibile, ncepnd cu pachete ce opereaz n mod linie i
culminnd cu medii integrate n care toate operaiile se pot declana de la un acelai pupitru de comand .
Nu sunt luate n considerare dect aceste medii integrate (denumite generic medii Turbo), dintre
care se detaeaz Turbo Asamblorul firmei Borland TASM.
Limbaje de nivel nalt neorientate
BASIC
A fost creat n 1964 la Darmooth College (S.U.A.). Denumirea sa provine de la iniialele
cuvintelor Beginners Allpurpose Symbolic Instruction Code (Cod de instruciuni simbolice, de uz
general, destinat nceptorilor).
Are urmtoarele caracteristici fundamentale :
simplu de nvat; instruciunile sale sunt cuvinte din limba englez sau prescurtri ale
acestora;
neorientat pe un anumit tip de problem; permite construirea de aplicaii;
este un limbaj nestructurat, ceea ce i permite s fie uor nvat.
Din cauz c a cunoscut o larg rspndire, au fost implementate noi versiuni de Basic: GWBASIC, QUICK BASIC, TURBO BASIC, VISUAL BASIC (Basic for Windows).
FORTRAN
Limbajul Fortran este decanul de vrst al limbajelor de larg folosin. A aprut n 1956 i i
datoreaz numele prescurtrii cuvintelor: FORmula TRANslation (Traducere de formule). Iniial
reprezenta un limbaj orientat pe calcule tiinifice avnd definite concepte precum: matrice, funcii
trigonometrice, numere reale n dubl precizie. Versiunile ulterioare care au cunoscut o mare popularitate
au extins posibilitile limbajului trasformndu-l ntr-un limbaj eficient, de uz general. n prezent exist
pentru IBM-PC dou implementri mai importante ale limbajului: Microsoft Fortran, Fortran for
Windows.
Dei nu poate fi considerat depit din punct de vedere conceptual (este un limbaj algoritmic
structurat) este neindicat folosirea lui datorit absenei unor medii de programare performante i pentru
c tendina actual i este defavorabil.
PASCAL
Conceptualizat n anul 1970 de ctre Niklaus Wirth, limbajul PASCAL poart numele
matematicianului i filosofului BLAISE PASCAL, n semn de recunoatere a meritelor sale n teoretizarea
mainilor de calcul.
Creat dup acumularea de cunotiine temeinice n tiina limbajelor formale, din confruntarea cu
probleme concrete ale programrii, limbajul PASCAL a constituit la vremea respectiv un limbaj modern,
meninndu-se ca atare i n prezent, datorit faptului c posed o solid baz conceptual.
Limbajul PASCAL a introdus n versiunea sa iniial noiunea de programare structurat i ulterior
noiunile de date (structuri) dinamice, date (structuri) definite de utilizator.
n prezent standardul implementrilor PASCAL cuprinde urmtoarele elemente:
programare structurat de tip algoritmic;
definirea de noi funcii sau proceduri;
tipuri de date definibile de ctre utilizator;
structuri de date dinamice;
48

adresri indirecte ale datelor;


recursivitate;
rutine complete de intrare / ieire;
funcii de conversie a datelor din ASCII n format intern i invers;
set complet de funcii matematice;
funcii elementare de grafic 2D;
posibilitatea inserrii direct n surs a instruciunilor n limbaj de asamblare;
posibilitatea definirii de overlay-uri pentru program.
Versiunile standard ale implementrilor PASCAL sunt cele oferite de Microsoft i Borland, cu
avantaj pentru cele din urm (TURBO PASCAL 5.0, TURBO PASCAL 5.5) datorit mediului de lucru
performant (de tip TURBO ). Combinaia PASCAL + TURBO a reprezentat un succes imens n rndul
programatorilor avnd ca singur rival cealalt combinaie: C+TURBO.
Limbajul C
Acest limbaj de programare , cu cel mai scurt nume , a fost creat n 1971 de ctre Dennis Ritchie
i Brian Kernigham pentru dezvoltarea sistemului de operare UNIX.
Principalele caracteristici ale limbajului sunt:
limbaj structurat de nivel nalt;
posed concepte de nivel sczut, ceea ce permite exploatarea portabil a caracteristicilor
intime unei maini;
rutine de conversie a datelor foarte evoluate;
tipuri de date definibile de ctre utilizator;
gestionarea elaborat a datelor de tip dinamic;
definirea de noi funcii;
adresri indirecte ale datelor , variabilelor ( pointer-i );
recursivitate;
set complet de funcii matematice;
funcii pentru realizarea de grafic elementar 2D;
funcii de apel servicii DOS;
posibilitatea definirii de overlay-uri pentru un program;
concizie deosebit a limbajului.
Pentru versiunile standard ale implementrilor limbajului C exist medii de programare
de tip TURBO ce aparin firmelor: Microsoft produsul QUICK C i firmei Borland
produsele TURBO C.
Limbajul ADA
A fost creat special pentru a gestiona totalitatea aplicaiilor dezvoltate i utilizate de N.A.S.A.
Noutatea limbajului (de tip structurat, algoritmic) o constitue concurena, deci posibilitatea lansrii de
procese paralele (sincronizate interactiv n finalul execuiei lor). Saltul calitativ este evident i deschide
un nou domeniu n programare dar nu pentru IBM-PC. Versiunile implementrilor limbajului ADA pe
IBM-PC nu posed tocmai acest parte de concuren, reducnd limbajul la un simplu limbaj structurat de
uz general. Deci, ADA este un limbaj ultramodern din punct de vedere teoretic dar ineficient din punct de
vedere practic pentru IBM-PC-uri.
Limbaje orientate pe gestiunea bazelor de date
Necesitile actuale n practica utilizrii calculatoarelor se ndreapt cu precdere spre gestionarea
bazelor de date de mari dimensiuni. O explicaie a acestei orientri e dat de faptul c o baz de date
reprezint o informaie, iar cel ce deine informaii complete i rapide ntr-o anumit problem este
49

indiscutabil cu un pas naintea celorlali. Concurena din domeniul economic poate fi numit pe bun
dreptate o btlie informaional.
Un sistem de gestionare a bazelor de date (S.G.B.D.) de tip clasic opereaz cu urmtorii termeni
fundamentali:
cmp o locaie n care se poate memora o informaie bine determinat;
nregistrare mai multe cmpuri alctuiesc mpreun o nregistrare;
baza de date colecie de nregistrri.
Deci, datele sunt gestionate prin intermediul unei structuri, organizat ierarhic, la un nivel de
organizare logic.
Tendina modern n exploatarea bazelor de date const n deplasarea interesului ctre bazele de
date relaionale. Diferena esenial const n definirea unui nivel logic suplimentar ntre datele
gestionate. Acestea nu mai sunt privite ca simple fie izolate ntre ele ci pot fi analizate pe baza legturilor
(relaiilor) ce exist ntre ele.
Noiunile cu care opereaz un S.G.B.D. relaional sunt urmtoarele:
tabel structur fundamental de depozitare a datelor;
linie n tabel echivalentul unei nregistrri clasice;
coloan n tabel echivalentul unui cmp de tip clasic;
baz de date o colecie de tabele, conectate prin valorile anumitor coloane.
Aceast nou concepie permite definirea de structuri 1:n. O nregistrare poate conine n valori
pentru un cmp anumit nu una singur ca n cazul clasic. Structurile de tip 1:n pot fi rezolvate i cu
ajutorul unui S.G.B.D. clasic, dar ntreaga gestiune a operaiilor revine programatorului pe cnd un mediu
relaional furnizeaz din start servicii speciale.
Spre deosebire de S.G.B.D.-urile clasice, un mediu relaional presupune ca cerin minimal
posibilitatea manipulrii datelor prin intermediul conexiunilor logice stabilite. Pentru aceasta exist
definit (i impus ca standard unanim recunoscut) limbajul de interogare SQL (Structured Query Language
limbaj de cereri structurate). Prin intermediul su sunt permise urmtoarele operaii:
regsire date (conexate logic) ce ndeplinesc o anumit condiie;
definire ordine de returnare a datelor;
redefinire conectri logice ale datelor;
exploatare;
programare.
Avantajele unui S.G.B.D. clasic sunt:
simplitate n manevrare; deci efort de studiu redus;
pot funciona pe un sistem de calcul ce nu implic resurse speciale, ci doar spaiu de
stocare extern suficient pentru problema dat;
pre de cost redus fa de cele relaionale.
Avantajele unui S.G.B.D. relaional sunt:
nivel logic superior (corelaii, structuri 1:n ),
prelucrri (regsiri) de date cu un nalt nivel de complexitate;
nivel superior de portabilitate a aplicaiilor, datelor.
S.G.B.D. -uri clasice
dBASE III
Cel mai rspndit sistem de gestiune a bazelor de date este dBASE, n diversele lui versiuni. El
poate fi considerat un BASIC al bazelor de date. La momentul apariiei a constituit o adevrat
revoluie n domeniul S.G.B.D.-urilor.
Meritele sale principale care l-au impus ateniei utilizatorilor i programatorilor sunt :
foarte simplu de utilizat;
limbaj de nivel foarte nalt , simplu de nvat;
50

interactivitate bun a sistemului;


poate funciona cu resurse extrem de restrnse;
Dezavantajele principale ale dBASE-ului sunt:
vitez de lucru extrem de sczut;
limbaj de programare cu lacune greu de surmontat (nu posed salturi, funcii
matematice reduse, erori de implementare);
aplicaiile create slab interactive;
imposibilitateta conectrii cu un alt limbaj.
Cele mai importante implementri ale sale sunt: dBASE III Plus i dBASE IV.
COBOL
A fost creat n 1950 i reprezenta singura posibilitate de gestionare a unei baze de date. Reprezint
n primul rnd un limbaj de programare special conceput pentru informatica de gestiune. Dac facem o
comparaie, sugestiv, COBOL este echivalentul FORTRAN-ului pentru sistemele de gestiune a bazelor
de date (din punct de vedere istoric i al performanelor).
Limbajul este considerat greoi i inflexibil, iar pentru crearea unui program foarte simplu e nevoie
de scrierea unui adevrat eseu.
Singurul avantaj real al COBOL-ului este portabilitatea sa ridicat.
FOXBASE
Sistemul dBASE a incintat firmele productoare de soft, datorit popularitii sale i pe de alt
parte a calitilor sczute ale implementrilor originale furnizate de firma Ashton-Tate. Au aprut noi
implementri ale limbajului care au ncercat s furnizeze unelte profesionale pe baza acestui suport
conceptual.
Versiunile FOXBASE 2.10 i FOXBASE PRO se constitue n medii performante att pentru
programatori ct i pentru utilizatori.
ISIS
Este distribuit gratis de ctre UNESCO, ceea ce l face cu adevrat interesant. Caracteristicile ce l
fac interesant sunt:
interactivitate bun;
posibilitate definire structuri 1:n;
suport de reea local;
un limbaj intern (o versiune de PASCAL) cu care se prelucreaz datele;
adaptabilitate foarte bun.
S.G.B.D. uri relaionale
ORACLE
Se poate afirma fr teama de a grei c ORACLE reprezint cel mai performant S.G.B.D.
disponibil la momentul actual. Pe lng faptul c posed avantajele unui mediu de tip relaional ORACLE
este gndit ca un sistem exhaustiv pentru rezolvarea problemelor de utilizare sau programare.
Limbajul intern folosit este SQL Plus i este permis conectarea cu alte limbaje externe evoluate
(orientate ctre C). Putem meniona:
vitez de lucru foarte bun;
exploatare interactiv la nivel SQL;
limitri de lucru greu sau imposibil de atins (maxim 65535 caractere ntr-un cmp,
numr nelimitat de cmpuri, de nregistrri);
exploatare eficient a spaiului pe disc (memorarea cmpurilor n format variabil).
Oracle este implementat pe majoritatea tipurilor de computere mari, ceea ce ofer portabilitatea
aplicaiilor, dar mai ales posibilitatea conectrii la calculatoare puternice.
PARADOX
51

Reprezint un S.G.B.D. cu adevrat profesional. El ndeplinete toate cerinele unui produs cu


adevrat modern i performant i anume:
interactivitate foarte bun;
vitez de lucru mare;
servicii i auxiliare;
limbaj de programare evoluat (PAL Paradox Application Language), dotat cu
compilator.
Limbaje orientate pe calcul tabelar
Aplicaiile mpreun cu limbajele implementate pentru rezolvarea problemelor descrise n
continuarea nu pot fi considerate medii de programare propriu-zise.
Aplicaiile de tip tabel de calcul au fost concepute n ajutorul funcionarilor, pentru a prelua o
parte imens din rutina de lucru inerent unor astfel de activiti.
Denumirea provine din limba englez i este o traducere pentru termenul spread-sheet (spreadntindere, desfurare, foaie, tabel; sheet-schem, diagram, a acoperi cu un strat). n traducere direct
aceasta ar nsemna pentru cazul de fa organizarea unei foi (a unui tabel).
Iat cum funcioneaz un program de tip spread-sheet:
elementul de lucru l reprezint un tabel;
un tabel este format din linii i coloane;
intersecia unei linii cu o coloan se cheam celul;
tabelul este vizualizat pe ecran prin intermediul unei ferestre;
n fiecare celul poate exista una din entitile urmtoare: text, numere, formule,
secvene de program, macroinstruciuni.
Pe lng aceste caracteristici specifice unui spread-sheet cerinele minimale ale unui pachet de
calcul tabelar includ:
posibilitatea cutrilor inverse (de la rezultatul unui calcul, la valorile care l-au
generat);
posibilitatea de lucru multi-tabel (mai multe tabelel simultan);
funcii de editare i formatare a textului (editor de texte obinuit);
funcii grafice (diagrame, prezentri);
sistem de gestiune a bazelor de date (pentru celulele unui tabel);
tiprire de calitate (posibilitatae de a lucra cu mai multe tipuri de imprimante,
exploatarea rezoluiei unei imprimante laser, set bogat de fonturi).
Spre deosebire de limbajele de programare propriu-zise, cele folosite de spread-sheet-uri sunt
special concepute pentru a fi folosite de nespecialiti (uor de nvat, uor de utilizat).
Un astfel de limbaj (de tip interpretor) se constituie ntr-un cadru general pentru rezolvarea
problemelor funcionarilor din diverse domenii de activitate.
O aplicaie realizat cu un spread-sheet poate fi modificat i adus la zi direct de ctre utilizator,
fr a mai fi necesar intervenia programatorului. Produsul obinut are flexibilitate maxim, iar efortul
necesar realizrii lui este minim.
Dezavantajele principale ale aplicaiilor realizate cu ajutorul unui spread-sheet le constitue
imposibilitatea depirii cadrului de programare oferit i dificultatea de a realiza prelucrri foarte
complexe . ns aceste dezavantaje sunt mai mult teoretice deoarece nu este cazul de a realiza aplicaii cu
astfel de cerine folosind un spread-sheet. Programele de calcul tabelar rezolv n mod strlucit o
problem punctual.
Cele mai cunoscute i rspndite produse de tip calcul tabelar sunt:
LOTUS 1-2-3
Lotus 1-2-3, produs al firmei Lotus Development este n mod sigur cel mai rspndit produs din
aceast categorie. Datorit popularitii sale el s-a constituit ntr-un adevrat standard (neoficial) pentru
52

spread-sheet-uri. La nivel de ansamblu, LOTUS se preuint ca o aplicaie cu bun interactivitate.


Reprourile ce i se pot aduce sunt: meniurile (uneori stufoase i nelogic ramificate) i help-ul care nu
totdeauna este la obiect.
QUATRO PRO 2.0
Spread-sheet-ul QUATRO, realizat de firma Borland este cel mai nou i puternic produs din
categoria sa. El combin ntr-un mod fericit tot ceea ce este pozitiv la rivalii si adugnd i multe
faciliti proprii.
EXCEL
Produsul firmei Microsoft, EXCEL este o aplicaie care funcioneaz sub Windows. De aici
rezult n mod direct unele din caracteristicile sale (utilizare mai comod, meniuri foarte clare i
standardizate, funcii grafice deosebit de puternice, vitez de lucru inferioar lui Quatro).
Cteva specificaii tehnice pentru EXCEL ar fi:
tabel cu dimensiunea maxim de 1638 x 256 celule;
limea maxim a unei coloane este de 255 caractere;
tabelele i grafica pot exista pe foi distincte;
funcioneau dup principiul WYSIWYG;
se pot folosi maxim 4 fonturi la un moment dat;
limbaj de programare puternic i flexibil;
posibilitatea definirii de macroinstruciuni;
nu posed funcie de salvare automat;
conine suport de funcionare n reea;
detecteaz prezena coprocesorului matematic i face uz de facilitile acestuia;
lucreaz cu memoria expandat.
Alte limbaje orientate
Limbaje orientate pe calcul matematic simbolic
Specialitii din domeniul cercetrii matematice au la dispoziie unelte de lucru extrem de utile
pentru eliminarea calculului matematic rutinier. n acest scop au fost create limbaje de programare care
pot recunoate i rezolva formule sau ecuaii matematice complexe. Expresiile manevrate pot conine
operaii algebrice elementare, operatori de derivare, de integrare, operatori difereniali care sunt
recunoscui de sistem ca atare. n plus sunt oferite instruciuni absolut necesare pentru a controla un
program.
Cele mai importante produse de acest gen sunt REDUCE, SYMNON, MATHCAD,
MATHEMATICA, MATHLAB.
Limbaje orientate pe programarea inteligenei artificiale
Acest tip de limbaje difer esenial de cele algoritmice. Modalitatea de programare este
descriptiv i are intenia declarat de simulare a raionamentului uman. Pentru rezolvarea unei probleme
sunt furnizate seturile de reguli i informaii necesare, iar apoi se descrie n ce const problema ca atare.
Limbajul este capabil s opereze deduciile (deciziile) necesare pentru a rezolva problema ntr-un caz
particular ce apare n practic.
Aadar, aceste limbaje descriu problema de rezolvat (n termenii deduciilor logice) pe cnd
limbajele de tip algoritmic descriu metoda de rezolvare a problemei. Domeniile de aplicabilitate pentru
limbajele de programare a inteligenei artificiale sunt cu predilecie: realizarea de sisteme expert
(programe ce nlocuiesc experii umani), computerizarea procesului de producie, robotic, tratarea
limbajelor naturale.
Cele mai importante limbaje de acest tip sunt:
PROLOG (PROgramming in LOGic) creat n 1973 i implementat pe PC-uri abia n
1986 de firma Borland sub forma Turbo-Prolog.
53

LISP (LISt Processing language) conceput n 1976 i implementat pe PC-uri de firma


Microsoft sub forma MuLISP.
GENERAII DE CALCULATOARE
Generaia I (1946-1956) caracterizat prin:
Hardware: relee, tuburi electronice;
Software: programe cablate, cod main, limbaj de asamblare;
Capacitate de memorie: 2 Koctei;
Vitez de operare: 10.000 de operaii/sec.;
Calulatoare: ENIAC, UNIVAC, IBM;
Generaia a IIa (1957-1963) marcat de apariia tranzistorului
Hardware: tranzistoare, memorii cu ferite, cablaj imprimat;
Software: limbaj de nivel nalt ( Algol, Fortan)
Memorie: 32 Koctei;
Viteza: 200.000 de instruciuni/sec
Calculatoare: IBM 7040, NCR501;
Generaia a IIIa (1964- 1981) caracterizat prin:
Hardware: circuite integrate (la nceput pe scar redus, apoi pe scar medie i larg;
scara de integrare se refer la numrul de componente electronice pe unitatea de suprafa),
cablaje imprimate multistrat, discuri magnetice, aparariia primelor microprocesoare;
Software: limbaje de nivel foarte nalt, programare orientat pe obiecte B.Pascal,
programare structurat LISP, primele programe pentru grafic i baze de date .
Memorie: 12 Moctei ;
Viteza: 5.000.000 de operaii/sec;
Calculatoare: IBM 370, FELIX
Comunicaii: Primele comunicaii prin satelit, transmisia de date prin fibr optic.
Generaia a IV-a (1982-1989) caracterizat prin:
Hardware: circuite integrate pe scar foarte mare (VLSI), sisteme distribuite de calcul,
apar microprocesoarele de 16/32 bii, primele elemente optice (discurile optice);
Software: Pachete de programe de larg utilizare, sisteme expert, sisteme de operare, se
perfecioneaza limbajele de programare orientate pe obiect, baze de date relaionale;
Memorie: 810 Moctei;
Viteza: 30 de milioane de instruciuni/sec;
Caculatoare: INDEPENDENT, CORAL, IBM (apar mai multe versiuni)
Generaia a V-a (1991-2002) n curs de dezvolatare
Hardware: circuite integrate pe scar ultralarg ULSI (proiectare circuite integrate 3D),
arhitecturi paralele, alte soluii arhitecturale noi (reele neurale etc.), proiectele galiu-arsen.
Software: limbaje concurente, programare funcional, prelucrare simbolic, baze de
cunotiine, sisteme expert evoluate, programe de realitate virtual, acum apar i sistemele
de operare windows. Aceast perioad este marcat de apariia internetului i extinderea
rapid a acestei reele mondiale.
Memorie: de la zeci, sute de Moctei pn la Goctei;
Viteza: 1G de instruciuni /sec 3 G de instruciuni/sec
Comunicaiile: au atins un nivel nemaintlnit, emisiile radio de ordinul GHz, reele
globale pe fibr optic, reele de comunicare prin satelit.
Calculatoare: o gam foarte larg de calculatoare.

54

CAPITOLUL VII
LIMBAJUL VISUAL BASIC
7.1 Programarea aplicaiilor Windows
Pentru realizarea unei aplicaii pot fi avute n vedere dou tehnologii de programare i anume:
programare procedural
programare orientat spre obiecte i dirijat de evenimente.
n programarea procedural, o aplicaie este constituit din unul sau mai multe programe care se
vor executa ntr-o anumit ordine, fiecare program fiind constituit dintr-o secven de instrucuni scrise
ntr-un limbaj de programare.
Acesta era modul clasic de realizare a aplicaiilor i sistemelor informatice i are o serie de
dezavantaje printre care: productivitate sczut n realizarea programelor, efort mare pentru realizarea
programelor i mai ales a interfeelor etc.
Apariia tehnologiei orientate obiect, a mediilor visuale de programare i a sistemului de operare
Windows a condus la apariia i dezvoltarea unei noi tehnologii de programare a aplicaiilor windows i
anume programarea orientat pe obiecte i dirijat de evenimente, tehnologie ce va fi prezentat n cele ce
urmeaz n cadrul limbajului Visual Basic.
O aplicaie Windows afieaz unul sau mai multe ecrane care conin obiecte cu care va
interaciona utilizatorul pentru a controla evoluia programului. ntr-un mediu de programare vizual,
obiectele principale sunt formele i controalele desenate n forme (form = o fereastr) Aceste obiecte pot
fi create prin selecie i depunere folosind barele de instrumente ale mediului respectiv.
Spre exemplu, bara cu instrumente Visual Basic permite crearea unei varieti de obiecte printre
care: forme, butoane, casete cu list, casete derulante combinate, casete de validare, butoane radio
(butoane de opiune), etc. Fiecare din aceste obiecte are un comportament predefinit. Spre exemplu cnd
se execut click pe un buton acesta trece n poziia apsat i apoi revine n poziia normal. Pentru a
schimba comportamentul obiectului acestuia trebuie s-i ataai cod de program (instruciuni)
corespunztor, cod ce se va executa atunci cnd are loc un anumit eveniment (spre exemplu n cazul
butonului evenimentul este click).
Evenimentele se produc ca urmare a unei aciuni a utilizatorului (ex. evenimentul click
corespunde apsrii butonului stng al mouse-ului pe obiectul respectiv), sau n urma execuiei codului
programului, sau pot fi declanate de ctre sistem.
Majoritatea obiectelor vor rspunde unui anumit numr de evenimente generate de ctre utilizator
printre care click-uri, dublu click-uri, apsri de taste sau trageri i eliberri ale obiectului. Limbajul
Visual Basic pune la dispoziia utilizatorului un mediu de dezvoltare care permite crearea de programe
orientate spre obiecte i conduse de evenimente. Pentru lucrul cu obiecte conduse de evenimente se
parcurg urmtoarele etape:
se creeaz o nou form creia i se d un nume;
se deseneaz i se denumesc obiectele ce urmeaz a fi afiate n forma respectiv;
se ataeaz fiecrui obiect codul ce va fi executat ca rspuns la evenimente generate de
utilizator sau de sistem.
Va rezulta o interfa grafic cu care interacioneaz utilizatorul pentru a controla evoluia
programului. Rezumnd putem spune c n programarea orientat spre obiecte i dirijat de evenimente,
obiectele au un comportament predefinit care poate fi modificat de utilizator prin ataare de cod
corespunztor i aceste obiecte rspund la evenimente declanate fie ca urmare a aciunii utilizatorului
asupra obiectelor, fie ca urmare a execuiei codului ataat, fie declanate de sistem.

55

7.2 Proprieti i metode


Un obiect este definit de un set de proprieti cum ar fi: dimensiune, culoare, poziie pe ecran,
comportament (ex. dac un buton radio este activ sau nu la un moment dat etc.). O metod este o
procedur (succesiune de instruciuni) asociat unei anumite aciuni a unui obiect. Spre exemplu n Visual
Basic exist o metod Move asociat majoritii obiectelor (permite mutarea obiectelor).
Deci proprietile descriu obiectele iar metodele definesc aciunile obiectelor, iar pe de alt parte
proprietile reprezint date iar metodele reprezint cod (instruciuni). Astfel n gramatica programrii
orientate spre obiecte :
obiectele sunt substantive;
proprietile sunt adjective;
metodele sunt verbe.
Utilizarea notaiei cu punct pentru referirea proprietilor i metodelor
Referirea unei proprieti se face astfel:
Obiect . Proprietate = Valoare
Exemplu - fie forma frmForma1 i variabila dColor n care memorm culoarea de fond a formei
dColor = frmForma1.BackColor (citete culoarea curent i o depune n dColor)
frmForma1.BackColor = QBColor (Blue) stabilete noua culoare de fond a formei la valoarea
Blue.
Referirea metodelor se face asemntor cu referirea proprietilor, ns n plus metodele pot
necesita precizarea unor informaii suplimentare.
Exemplu - pentru mutarea obiectului Buton1 n colul din stnga sus al formei curente se apeleaz
metoda Move i se precizeaz coordonatele colului din stnga sus:
Buton1.Move 0,0
Stabilire proprieti i executare metode
Proprietile unui obiect pot fi setate n faza de proiectare (atunci cnd se deseneaz sau se
modific formele) utiliznd fia Properties a formei sau obiectului din form (fia este automat vizualizat
la selecia obiectului respectiv: forma, buton, etc.). De asemenea fia Properties poate fi vizualizat prin
click dreapta i selecie Properties.
Proprietile pot fi modificate i prin program n momentul execuiei formei, dac codul de
program asociat conine instruciuni care refer i seteaz proprieti (ca n exemplul de mai sus n care
schimbm culoarea fondului formei).
Spre deosebire de proprieti, metodele pot fi executate numai n momentul execuiei programului
(eventual n momentul depanrii programului utiliznd facilitatea Debugger a programului Visual Basic).
Denumirea obiectelor
Orice obiect are proprietile:
Name - numele utilizat n scrierea codului
Capture - numele dat obiectului pentru a putea fi identificat de utilizator. Visal Basic d
nume implicite obiectelor. Este indicat ca utilizatorul s dea nume obiectelor (Name) utiliznd
urmtoarea convenie:
un prefix format din 3 litere mici (ex. frm pentru form, cmd pentru buton de comand,
etc.)
un ir de caractere care identific obiectul (ex. Forma1, Ecran1, Buton1, etc.).
n tabelul urmtor sunt prezentate conveniile de denumire a obiectelor din Visual Basic:
Obiect

Prefix

Exemplu

Form
Buton de comand
Caset de text

Frm
cmd, btn
Txt

frmForma1
cmdButon, btnOK
txtCaseta1

56

Obiect

Prefix

Bare de derulare
- orizontal
- vertical
Meniu
Caset de validare
Caset cu lista
Cadru
Imagine
Buton de opiune (radio)

hsb
vsb
Mnu
Chk
Lst
Fra
Img
Opt

Exemplu

mnuMeniuPrinc

optBO1

7.3 Instruciunile VBA


Generaliti
Exist trei categorii de instruciuni Visual Basic:
instruciuni de declarare (prezentate la declararea variabilelor) prin care se denumesc i
se declar tipul pentru variabile, constante i proceduri;
instruciuni de atribuire (prezentate n continuare) prin care se atribuie valori
variabilelor sau constantelor;
instruciuni executabile (prezentate n continuare) care iniiaz aciuni: execut metode
sau proceduri, controleaz fluxul execuiei codului.
n mediul de dezvoltare VBA, sintaxa instruciunilor este verificat automat dup ce se trece la
instruciunea urmtoare (prin Enter).
Continuarea instruciunilor
O instruciune poate s fie scris pe mai multe linii prin utilizarea caracterului de continuare a
liniei "_" precedat de un spaiu. De exemplu, crearea prin program a unui tabel ntr-un document Word:
ActiveDocument.Tables.Add Range:=Selection.Range, _
NumRows:=3, _
NumColumns:= 3
unde, pe lng continuarea liniilor se va remarca utilizarea argumentelor numite la apelul metodei
de adugare a unui nou tabel la colecia de tabele a documentului.
Dou instruciuni pot fi scrise pe o aceeai linie dac sunt separate cu caracterul ":".
Etichetarea liniilor
O linie poate fi identificat:
printr-o etichet: orice nume, care respect regulile generale, care ncepe n prima
coloan a liniei i se termin cu caracterul ":"
printr-un numr: orice combinaie de cifre, care ncepe n prima coloan a liniei i este
unic n modulul respectiv.
Identificatorii de linii pot fi utilizai n instruciuni de control, desi codul astfel construit nu
respect regulile programrii structurate.
Comentarii
Textele explicative (necesare documentrii codului) pot fi introduse pe linii separate sau n
continuarea liniei de cod.
O linie de comentariu ncepe cu un apostrof (') sau cu cuvntul Rem urmat de un spaiu.
Comentariul de pe aceeai linie cu o instruciune se introduce printr-un apostrof urmat de
comentariu.
57

Operatori
n formarea expresiilor de diverse tipuri, operatorii sunt cei utilizai aproape general n limbajele
de programare de nivel nalt. Pentru fixarea termenilor i notaiilor sunt totui prezentai, pe categorii,
nsoii, acolo unde este cazul de scurte explicaii.
Operatori aritmetici
Operator

Semnificaie

Observaii

Ridicarea la
putere

rezultatul este Double sau Variant(Double) cu excepia: dac


un operand este Null, rezultatul este tot Null

nmulirea

rezultatul este dat de cel "mai precis" factor, ordinea


cresctoare a "preciziei" fiind, pentru nmulire, Byte, Integer,
Long, Single, Currency, Double i Decimal. Dac o expresie
este Null, rezultatul este Null. O expresie Empty este
considerat ca 0. Pentru excepii se va studia Help
*(operator).

mprirea

rezultatul este, n general, Double sau Variant(Double). Dac


o expresie este Null, rezultatul este Null. O expresie Empty
este considerat ca 0. Pentru excepii se va studia Help /
(operator).

mprirea
ntreag

nainte de mprire, operanzii sunt rotunjii la Byte, Integer


sau Long. Rezultatul este Byte, Variant(Byte), Integer,
Variant (Integer), Long, sau Variant(Long). Dac o expresie
este Null, rezultatul este Null. O expresie Empty este
considerat ca 0.

Mod

Restul
mpririi

operanzii sunt rotunjii la ntregi i se obine restul mpririi.


Rezultatul este Byte, Variant(Byte), Integer, Variant (Integer),
Long, sau Variant(Long). Dac o expresie este Null, rezultatul
este Null. O expresie Empty este considerat ca 0.

Adunarea
numeric sau
concatenarea
irurilor

n general, operanzi numerici produc adunarea, iar operanzi


iruri produc concatenarea. n cazul numeric, rezultatul este
de tipul cel "mai precis" al operanzilor, ordinea de "precizie"
fiind pentru adunare i scdere: Byte, Integer, Long, Single,
Double, Currency i Decimal. Deoarece operanzii pot fi orice
expresie, pentru o informare complet (de exemplu operanzi
Variant) se va studia Help +(operator).

Scderea sau
inversarea
semnului

operanzii pot fi doar numerici. Rezultatul este de tipul cel


"mai precis" al operanzilor, ordinea de "precizie" fiind pentru
adunare i scdere: Byte, Integer, Long, Single, Double,
Currency i Decimal. Dac o expresie este Null, rezultatul
este Null. O expresie Empty este considerat ca 0. Pentru
excepii se va studia Help -(operator).

Operatori de comparare
58

Relaiile care exist ntre diferite tipuri de entiti se pot evidenia prin comparaii avnd una
dintre formele urmtoare:
result = expression1 comparisonoperator expression2
result = object1 Is object2
result = string Like pattern
unde
result este o variabil numeric
expression este o expresie oarecare
comparisonoperator este un operator relaional
object este un nume de obiect
string este o expresie ir oarecare
pattern este o expresie String sau un domeniu de caractere.
Operatorii de comparare sunt cei uzuali: < (mai mic), <= (mai mic sau egal), > (mai mare), >=
(mai mare sau egal), = (egal), <> (diferit, neegal).
Rezultatul este True (dac este adevrat relaia), False (dac relaia este neadevrat), Null (dac
cel puin un operand este Null).
Operatorul Is produce True dac variabilele se refer la acelai obiect i False n caz contrar.
Operatorul Like compar dou iruri cu observaia c al doilea tremen este un ablon. Prin urmare
rezultatul este True dac primul ir operand este format dup ablon, False n caz contrar. Atunci cnd un
operand este Null, rezultatul este tot Null.
Comportarea operatorului Like depinde de instruciunea Option Compare, care poate fi:
Option Compare Binary, ordinea este cea a reprezentrii interne binare, determinat n
Windows de codul de pagin.
Option Compare Text, compararea este insenzitiv la capitalizarea textului, ordinea este
determinat de setrile locale ale sistemului.
Construcia ablonului poate cuprinde caractere wildcard, liste de caractere, domenii de caractere:
un caracter oarecare
oricte caractere (chiar nici unul)
# o cifr oarecare (09).
[charlist] oricare dintre caracterele enumerate n list, un domeniu de litere poate fi dat
prin utilizarea cratimei.
[!charlist] orice caracter care nu este n list
Observaie. Pentru a utiliza n ablon caracterele speciale cu valoare de wildcard se vor utiliza construcii
de tip list: [[], [?] etc. Paranteza dreapta va fi indicat singur: ].
Pentru alte observaii utile se va studia Help Like operator.
Operatori de concatenare
Pentru combinarea irurilor de caractere se pot utiliza operatorii & i +.
n sintaxa
expression1 & expression2
unde operanzii sunt expresii oarecare, rezultatul este:
de tip String, dac ambii operanzi sunt String
de tip Variant(String) n celelalte cazuri
Null, dac ambii operanzi sunt Null.
nainte de concatenare, operanzii care nu sunt iruri se convertesc la Variant(String). Expresiile
Null sau Empty sunt tratate ca iruri de lungime zero ("").

59

Operatori logici
Pentru operaiile logice sunt utilizai urmtorii operatori, uzuali n programare.
Operator
Semnificaie
Observaii
And

conjuncia logic Null cu False d False, Null cu True sau cu Null d Null.
Operatorul And realizeaz i operaia de conjuncie bit cu
bit pentru expresii numerice.

Eqv

echivalena logic Dac o expresie este Null, rezultatul este Null. Eqv
realizeaz i compararea bit cu bit a dou expresii
numerice, poziionnd cifrele binare ale rezultatului dup
regulile de calcul ale echivalenei logice: 0 Eqv 0 este 1
etc.

Imp

implicaia logic True Imp Null este Null, False Imp * este True, Null Imp
True este True, Null Imp False (sau Null) este Null.
Operatorul Imp realizeaz i compararea bit cu bit a dou
expresii numerice, poziionnd cifrele binare ale
rezultatului dup regulile de calcul ale implicaiei logice: 1
Imp 0 este 0, n rest rezultatul este 1.

Not

Or

Xor

negaia logic

Not Null este Null. Prin operatorul Not se poate inversa bit
cu bit valorile unei variabile, poziionndu-se
corespunztor un rezultat numeric.

disjuncia logic Null Or True este True, Null cu False (sau Null) este Null.
Operatorul Or realizeaz i o comparaie bit cu bit a dou
expresii numerice poziionnd biii corespunztori ai
rezultatului dup regulile lui Or logic.
disjuncia
exclusiv

Dac un operand este Null, atunci rezultatul este Null. Se


poate efectua operaia de sau exclusiv i bit cu bit pentru
dou expresii numerice [b1+b2(mod 2)].

Instruciuni de atribuire
Atribuirea se poate efectua prin instruciunea Let (pentru valori atribuite variabilelor i
proprietilor), Set (pentru atribuirea de obiecte la o variabil de tip obiect), Lset i Rset (pentru atribuiri
speciale de iruri sau tipuri definite de utilizator).
Instruciunea Let
Atribuie valoarea unei expresii la o variabil sau proprietate.
[Let] varname = expression
unde varname este nume de variabil sau de proprietate.
Este de remarcat forma posibil (i de fapt general utilizat) fr cuvntul Let.
Observaii. Valoarea expresiei trebuie s fie compatibil ca tip cu variabila (sau proprietatea): valori
numerice nu pot fi atribuite variabilelor de tip String i nici reciproc.
Variabilele Variant pot primi valori numerice sau String, reciproc nu este valabil dect dac
valoarea expresiei Variant poate fi interpretat compatibil cu tipul variabilei: orice Variant poate fi
atribuit unei variabile de tip String (cu excepia Null), doar Variant care poate fi interpretat nuric poate fi
atribuit unei variabile de tip numeric.
La atribuirea valorilor numerice pot avea loc conversii la tipul numeric al variabilei.
Atribuirea valorilor de tip utilizator poate fi efectuat doar dac ambii termeni au acelai tip
definit. Pentru alte situaii se va utiliza instruciunea Lset.
Nu se poate utiliza Let (cu sau fr cuvntul Let) pentru legarea de obiecte la variabile obiect. Se
va utiliza n aceast situaie instruciunea Set.
60

Instruciunea LSet
Copie, cu aliniere la stnga, un ir de caractere (valoarea expresiei din dreapta) ntr-o variabila de
tip String. Deoarece copierea este binar, poate fi utilizat pentru atribuiri ntre tipuri utilizator diferite
(rezultatul este impredictibil deoarece nu se face nici o verificare de tipuri/componente ale valorilor de tip
record). Sintaxa este
LSet stringvar = string
LSet varname1 = varname2
unde
stringvar, string reprezint variabila de tip String i expresia de acelai tip implicate ntr-o
atribuire de iruri.
varname1, varname2 sunt denumiri de variabile, de tipuri definite de utilizator (vezi
instruciunea Type) diferite. Zona de memorie alocat celei de a doua variabile este copiat
(aliniat la stnga) n zona de memorie a primei variabile.
Caracterele care rmn neocupate se completeaz cu spaii, iar dac zona de unde se copie este
mai mare, caracterele din dreapta se pierd (sunt trunchiate).
Instruciunea LSet
Copie, cu aliniere la dreapta, un ir de caractere (valoarea expresiei din dreapta) ntr-o variabila de
tip String. Sintaxa este
RSet stringvar = string
Caracterele rmase neocupate n variabil sunt completate cu spaii. Instruciunea RSet nu se
poate utiliza (analog lui LSet) pentru tipuri definite de utilizator.
Instruciuni executabile
Execuia unui program are loc, n lipsa oricrui control, instruciune cu instruciune, de la stnga
la dreapta i de sus n jos. Acest sens poate fi modificat, ntr-o oarecare msur, prin ordinea de
preceden a operaiilor n evaluarea expresiilor. Este evident c o asemenea structur simpl nu poate
cuprinde toate aspectele programrii i din acest motiv necesitatea structurilor de control a fluxului
execuiei. Unele instruciuni au fost pstrate doar din motive de compatibilitate cu versiunile iniiale ale
limbajului, n locul lor fiind preferate structuri mai evoluate sau similare altor limbaje de programare.
Instruciuni de transfer (GoSubReturn, GoTo, OnError, OnGoSub, OnGoTo)
Aceast categorie cuprinde instruciunile prin care controlul execuiei este transferat la o alt
instruciune din procedur. n general, utilizarea acestor comenzi nu produce programe foarte structurate
(n sensul programrii structurate) i prin urmare, pentru o mai mare claritate a codului, pot fi nlocuite cu
alte structuri de programare.
GoSubReturn
n cadrul unei proceduri un grup de instruciuni poate fi organizat ca o subrutin (similar unei
proceduri on-line, nenumite) identificat prin linia de nceput. Transferul controlului la acest grup de
instruciuni i revenirea la locul apelului se poate efectua prin GoSubReturn cu sintaxa
GoSub line
...
line
...
Return
unde line este o etichet de linie sau un numr de linie din aceeai procedur.
Pot exista mai multe instruciuni Return, prima executat produce saltul la instruciunea care
urmeaz celei mai recente instruciuni GoSub executate.

61

GoTo
Realizeaz tranferul controlului execuiei la o linie din aceeai procedur.
GoTo line
unde line este o etichet de linie sau un numr de linie din aceeai procedur.
On Error
Permite controlul erorilor prin transferul controlului la rutine de tratare.
Observaie. Este prezentat n seciunea dedicat controlului erorilor.
OnGoSub, OnGoTo
Permit o ramificare multipl, dup valoarea unei expresii. Se recomand, pentru claritatea codului,
utilizarea structurii Select Case n locul acestor structuri.
On expression GoSub destinationlist
On expression GoTo destinationlist
unde
expression este o expresie numeric avnd valoare ntreag (dup o eventual rotunjire)
ntre 0 i 255 inclusiv.
destinationlist este o list de etichete de linii sau numere de linii, separate prin virgule
(elementele pot fi de ambele categorii), din aceeai procedur cu instruciunea.
Dac valoarea expresiei este negativ sau mai mare dect 255 se produce o eroare.
Dac valoarea expresiei, fie ea k, este n domeniul rangurilor listei, atunci se transfer controlul la
linia identificat de al k-lea element al listei.
Dac valoarea expresiei este 0 sau mai mare dect numrul de elemente din list, transferul se
efectueaz la linia care urmeaz instruciunea On...GoSub sau On...GoTo.
Instruciuni de terminare sau oprire a programului (DoEvents, End, Exit, Stop)
Terminarea execuiei programului sau oprirea temporar (pauza) se pot realiza prin instruciunile
enumerate aici.
DoEvents
Dei nu este o instruciune VBA ci este o funcie, includerea ei este natural prin aceea c permite
cedarea controlului ctre sistemul de operare, care poate astfel s funcioneze n regim de multitasking.
Aciunea poate fi realizat i prin alte tehnici (de exemplu utilizarea unui Timer etc.). Sintaxa este
DoEvents( )
Funcia returneaz, n general, valoarea 0.
Controlul este redat programului dup ce sistemul de operare a terminat procesarea evenimentelor
din coada de evenimente, ca i procesarea tuturor caracterelor din coada SendKeys.
Observaie. Pentru alte observaii se va studia documentaia comenzii DoEvents.
End
Termin execuia unei proceduri (sub forma prezentat aici) sau indic sfritul codului unei
structuri de tip bloc (cum ar fi End Function, End If etc., prezentate la structurile respective).
Sintaxa, n ipostaza opririi execuiei, este:
End
Prin aceast instruciune, care poate fi plasat oriunde n program, execuia este terminat imediat,
fr a se mai executa eventualele instruciuni scrise pentru tratarea unor evenimente specifice sfritului
de program (Unload, Terminate etc.).
Fiierele deschise prin Open sunt nchise i toate variabilele sunt eliberate. Obiectele create din
modulele clas sunt distruse, iar referinele din alte aplicaii la asemenea obiecte sunt invalidate. Memoria
este eliberat.

62

Exit
Prin instruciunea Exit, sub una din multiplele ei forme, se ntrerupe o ramur de execuie (cum ar
fi o procedur, o structur iterativ etc.) pentru a se continua nivelul apelant. Sintaxa este
Exit Do
Exit For
Exit Function
Exit Property
Exit Sub
i efectele sunt prezentate la structurile respective. Nu trebuie confundat cu instruciunea End.
Stop
Efectul instruciunii este dependent de modul de execuiei a programului. Dac se execut varianta
compilat a programului (fiierul .exe) atunci instruciunea este similar instruciunii End (suspend
execuia i nchide fiierele deschise). Dac execuia este din mediul VBA, atunci se suspend execuia
programului, dar nu se nchid fiierele deschise i nu se terge valoarea variabilelor. Execuia poate fi
reluat din punctul de suspendare.
Stop
Instruciunea este similar introducerii unui punct de oprire (Breakpoint) n codul surs.
Structuri iterative (Do...Loop, For...Next, For Each...Next, While...Wend, With)
Prin intermediul construciilor de tip bloc prezentate n aceast seciune se poate repeta, n mod
controlat, un grup de instruciuni. n cazul unui numr nedefinit de repetiii, condiia de oprire poate fi
testat la nceputul sau la sfritul unui ciclu, prin alegerea structurii adecvate.
DoLoop
Se vor utiliza structuri DoLoop pentru a executa un grup de instruciuni de un numr de ori
nedefinit aprioric. Dac se cunoate numrul de cicluri, se va utiliza structura ForNext.
nainte de continuare se va testa o condiie (despre care se presupune c poate fi modificat n
instruciunile executate). Diferitele variante posibile pentru DoLoop difer dup momentul evalurii
condiiei i decizia luat.
Do [{While | Until} condition]
[statements]
[Exit Do]
[statements]
Loop

sau
Do
[statements]
[Exit Do]
[statements]
Loop [{While | Until} condition]

unde
condition este o expresie care valoare de adevr True sau False. O condiie care este Null
se consider False.
statements sunt instruciounile care se repet atta timp (while) sau pn cnd (until)
condiia devine True.
Dac decizia este de a nu continua ciclarea, atunci se va executa prima instruciune care urmeaz
ntregii structuri (deci de dup linia care ncepe cu Loop).
Se poate abandona ciclarea oriunde n corpul structurii prin utilizarea comenzii Exit Do (cu
aceast sintax). Dac apare o comand Exit Do se poate omite chiar i condiia din enun ntruct
execuia se va termina prin aceast decizie.

63

Structurile Do pot fi inserate (dar complet) unele n altele. O terminare (prin orice metod) a unei
bucle transfer controlul la nivelul Do imediat superior.
Execuia structurilor este explicat n tabelul urmtor
Do WhileLoop

Testeaz condiia la nceputul buclei, execut bucla


numai dac rezultatul este True i continu astfel
pn cnd o nou evaluare produce False.

Do UntilLoop

Testeaz condiia la nceputul buclei, execut bucla


numai dac rezultatul este False i continu astfel
pn cnd o nou evaluare produce True.

DoLoop While

Se execut ntotdeauna bucla o dat, se testeaz


condiia la sfritul buclei i se repet bucla att
timp ct condiia este True. Oprirea este pe
condiie fals.

DoLoop Until

Se execut ntotdeauna bucla o dat, se testeaz


condiia la sfritul buclei i se repet bucla att
timp ct condiia este False. Oprirea este pe
condiie adevrat.

ForNext
Atunci cnd se cunoate numrul de repetri ale unui bloc de instruciuni, se va folosi structura
ForNext. Structura utilizeaz o variabil contor, a crei valoare se modific la fiecare ciclu, oprirea
fiind atunci cnd se atinge o valoare specificat. Sintaxa este:
For counter = start To end [Step step]
[statements]
[Exit For]
[statements]
Next [counter]

unde
counter este variabila contor (numr repetrile), de tip numeric. Nu poate fi de tip
Boolean sau element de tablou.
start este valoarea iniial a contorului.
end este valoarea final a contorului.
step este cantitatea care se adun la contor la fiecare pas. n cazul n care nu se specific
este implicit 1. Poate fi i negativ.
statements sunt instruciunile care se repet. Dac nu se specific, atunci singura aciune
este cea de modificare a contorului de un numr specificat de ori.
Aciunea este dictat de pasul de incrementare i relaia dintre valoarea iniial i cea final.
Instruciunile din corpul structurii se execut dac
counter <= end pentru step >= 0 sau
counter >= end pentru step < 0.
Dup ce toate instruciunile s-au executat, valoarea step este adugat la valoarea contorului i
instruciunile se execut din nou dup acelai test ca i prima dat, sau bucla ForNext este terminat i
se execut prima instruciune de dup linia Next.
Specificarea numelui contorului n linia Next poate clarifica textul surs, mai ales n cazul cnd
exist structuri ForNext mbricate.
Corpul unei bucle ForNext poate include (complet) o alt structur ForNext. n asemenea
situaii, structurile mbricate trebuie s aib variabile contor diferite.
64

Instruciunile Exit For pot fi plasate oriunde n corpul unei bucle i provoac abandonarea ciclrii.
Controlul execuiei se transfer la prima instruciune de dup linia Next.
For EachNext
Similar structurii ForNext, structura For EachNext repet un grup de instruciuni pentru
fiecare element dintr-o colecie de obiecte sau dintr-un tablou (cu excepia celor de un tip utilizator). Este
util atunci cnd nu se cunoate numrul de elemente sau dac se modific, n timpul execuiei, coninutul
coleciei.
Sintaxa este:
For Each element In group
[statements]
[Exit For]
[statements]
Next [element]
unde
element este variabila utilizat pentru parcurgerea elementelor. Dac se parcurge o colecie
de obiecte, atunci element poate fi Variant, o variabil generic de tip Object, sau o
variabil obiect specific pentru biblioteca de obiecte referit. Pentru parcurgerea unui
tablou, element poate fi doar o variabil de tip Variant.
group este numele coleciei de obiecte sau al tabloului.
statements este grupul de istruciuni executate pentru fiecare element.
Execuia unei structuri For EachNext este:
Se definete element ca numind primul element din grup (dac nu exist nici un element, se
transfer controlul la prima instruciune de dup Next se prsete bucla fr executarea
instruciunilor).
Se execut instruciunile din corpul buclei For.
Se testeaz dac element este ultimul element din grup. Dac rspunsul este afirmatif, se
prsete bucla.
Se definete element ca numind urmtorul element din grup.
Se repet paii 2 pn la 4.
Instruciunile Exit For sunt explicate la ForNext.
Buclele ForEach...Next pot fi mbricate cu condiia ca elementele utilizate la iterare s fie diferite.
Observaie. Pentru tergerea tuturor obiectelor dintr-o colecie se va utiliza ForNext i nu For Each
Next. Se va utiliza ca numr de obiecte colecie.Count.
WhileWend
Execut un grup de instruciuni att timp ct este adevrat o condiie. Sintaxa
While condition
[statements]
Wend
Este recomandat s se utilizeze o structur DoLoop n locul acestei structuri.
With
Programarea orientat pe obiecte produce, datorit calificrilor succesive, construcii foarte
complexe atunci cnd se numesc proprietile unui obiect. n cazul modificrilor succesive ale mai multor
proprieti ale aceluiai obiect, repetarea zonei de calificare poate produce erori de scriere i conduce la
un text greu de citit. Codul este simplificat prin utilizarea structurii WithEnd With. O asemenea
structur execut o serie de instruciuni pentru un obiect sau pentru o variabil de tip utilizator. Sintaxa
este:
With object
[statements]
65

End With
unde
object este numele unui obiect sau a unui tip definit de utilizator
statements sunt instruciunile care se execut pentru entitatea precizat.
Permind omiterea recalificrilor din referinele la obiectul precizat, orice construcie de tipul
".nume" este interpretat n instruciunile structurii drept "object.nume".
ntr-un bloc With nu se poate schimba obiectul procesat.
La plasarea unui bloc With n interiorul altui bloc With, obiectul extern este mascat complet, deci
calificrile eventuale la acest obiect vor fi efectuate.
Nu se recomand saltul n i dintr-un bloc With.
Structuri de decizie (IfThenElse, Select Case)
Ramificarea firului execuiei dup rezultatul verificrii unei condiii este o necesitate frecvent n
orice implementare.
Pe lng structurile prezentate, se pot utiliza trei funcii care realizeaz alegeri n mod liniarizat
(pe o linie de cod): Choose(), Iif(), Switch().
IfThenElse
O asemenea structur, ntlnit de altfel n toate limbajele de programare, execut un grup de
instruciuni ca rspuns la ndeplinirea unei condiii (compus sau nu din mai multe condiii testate
secvenial). Sintaxa permite o mare varietate de forme:
If condition Then [statements] [Else elsestatements]
sau
If condition Then
[statements]
[ElseIf condition-n Then
[elseifstatements] ...
[Else
[elsestatements]]
End If
unde
condition are una din formele: expresie numeric sau ir care se poate evalua True sau
False (Null este interpretat False);
expresie de forma TypeOf objectname Is objecttype, evaluat True dac objectname este
de tipul obiect specificat n objecttype.
statements, elsestatements, elseifstatements sunt blocurile de instruciuni executate atunci
cnd condiiile corespunztoare sunt True.
La utilizarea primei forme, fr clauza Else, este posibil s se scrie mai multe instruciuni,
separate de ":", pe aceeai linie.
Verificarea condiiilor implic evaluarea tuturor subexpresiilor, chiar dac prin jocul operanzilor i
operatorilor rezultatul poate fi precizat mai nainte (de exemplu OR cu primul operand True).
Select Case
Instruciunea Select Case se poate utiliza n locul unor instruciuni ElseIf multiple (dintr-o
structur IfThenElseIf) atunci cnd se compar aceeai expresie cu mai multe valori, diferite ntre
ele. Instruciunea Select Case furnizeaz, prin urmare, un sistem de luare a deciziilor similar instruciunii
IfThenElseIf. Totui, Select Case produce un un cod mai eficient i mai inteligibil. Sintaxa este:
Select Case testexpression
[Case expressionlist-n
[statements-n]] ...
[Case Else
[elsestatements]]
66

End Select
unde
testexpression este o expresie numeric sau ir.
expressionlist-n este lista, separat prin virgule, a uneia sau mai multe expresii de forma:
expression.
expression To expression. Cuvntul To introduce un interval de valori, valoarea minim
fiind prima specificat.
Is comparisonoperator expression. Se va utiliza Is cu operatori de comparare (exceptnd
Is i Like) pentru a specifica un domeniu de valori.
statements-n reprezint una sau mai multe instruciuni care se vor executa dac
testexpression este egal cu un element din expressionlist-n.
elsestatements reprezint una sau mai multe instruciuni care se vor executa dac
testexpression nu este egal cu nici un element din listele liniilor Case.
Dac testexpression se potrivete cu un element dintr-o list Case, se vor executa instruciunile
care urmeaz aceast clauz Case pn la urmtoarea clauz Case, sau pn la End Select. Control
execuiei trece apoi la instruciunea care urmeaz liniei finale End Select. Rezult c dac testexpression
se regsete n mai multe liste, doar prima potrivire este considerat.
Clauza Case Else are semnificaia uzual "altfel, n rest, n caz contrar etc.", adic introduce
instruciunile care se execut atunci cnd expresia de test nu se potrivete nici unui element din listele
clauzelor Else. Dac aceasta este situaia i nu este specificat o clauz Case Else, atunci execuia
urmeaz cu prima instruciune de dup End Select.
Instruciunile Select Case pot fi scufundate unele n altele, structurile interioare fiind complete
(fiecare structur are End Select propriu, includerea este complet).
Apeluri de proceduri i programe
n aceast seciune se prezint doar funcia Shell(), deoarece despre proceduri i apelul lor s-a
discutat n capitolul 1.
Funcia Shell()
Execut un program executabil i returneaz un Variant(Double) reprezentnd ID-ul de task al
programului n caz de succes; n caz contrar returneaz zero. Sintaxa este
Shell(pathname[,windowstyle])
unde
pathname este Variant (String). Conine numele programului care se execut, argumentele
necesare i poate da calea complet (dac este nevoie).
windowstyle este Variant (Integer) i precizeaz stilul ferestrei n care se va executa
programul (implicit este minimizat, cu focus).
Valorile posibile pentru argumentul windowstyle sunt
Constanta numit Valoarea
Semnificaia
VbHide
0
Fereastra este ascuns iar focus-ul este pe fereastra ascuns.
VbNormalFocus
1
Fereastra are focus-ul i este dimensionat i poziionat normal.
VbMinimizedFocus
2
Fereastra este afiat ca o icoan (minimizat) dar are focus-ul.
VbMaximizedFocus
3
Fereastr maximizat, cu focus.
VbNormalNoFocus
4
Fereastra este normal (restaurat la mrimea i poziia cea mai recent)
dar nu are focus-ul. Fereastra activ curent i pstreaz focus-ul.
VbMinimizedNoFocus
6
Fereastr minimizat, fr focus. Fereastra activ curent i pstreaz
focus-ul.

67

Dac funcia Shell nu poate porni programul specificat se va semnala eroare. Programul pornit
prin Shell se execut asincron, deci nu exist certitudinea c acest program se termin nainte de execuia
instruciunilor care urmeaz liniei Shell.

68

CAPITOLUL VIII
REGULI IMPORTANTE PRIVIND ALEGEREA UNUI LIMBAJ DE PROGRAMARE
Prezentm n continuare mai multe reguli importante, majoritatea dintre ele prezente i explicate
n seciunile anterioare.
1. Definete complet problema.
Aceast indicaie, foarte important n activitatea de programare, pare fr sens pentru unii cititori.
Dar nu se poate rezolva o problem dac nu se cunoate aceast problem. Specificarea corect i
complet a problemei nu este o sarcin trivial, ci una foarte important i adeseori chiar dificil.
Programul trebuie s respecte aceast specificaie, s fie construit avnd tot timpul n fa aceast
specificaie, s i se demonstreze corectitudinea n raport cu aceast specificaie, s fie testat i validat
innd seama de aceast specificaie.
2. Gndete mai nti, programeaz pe urm.
ncepnd cu scrierea specificaiilor problemei, trebuie pus n prim plan gndirea. Este specificaia
problemei corect? ntre metodele de rezolvare posibile, care ar fi cea mai potrivit scopului urmrit? n
paralel cu proiectarea algoritmului demonstreaz corectitudinea lui. Verific corectitudinea fiecrui pas
nainte de a merge mai departe.
3. Nu folosi variabile neiniializate.
Este vorba de prezena unei variabile ntr-o expresie fr ca n prealabil aceast variabil s fi
primit valoare. Este o eroare foarte frecvent a programatorilor nceptori (dar nu numai a lor). Destule
compilatoare permit folosirea variabilelor neiniializate, neverificnd dac o variabil a fost iniializat
naintea folosirii ei. Alte compilatoare iniializeaz automat variabilele numerice cu valoarea zero. Cu
toate acestea nu e bine s ne bazm pe o asemenea iniializare ci s atribuim singuri valorile iniiale
corespunztoare variabilelor. Programul realizat trebuie s fie portabil, s nu se bazeze pe specificul unui
anumit compilator.
4. Verific valoarea variabilei imediat dup obinerea acesteia.
Dac o variabil ntreag trebuie s ia valori ntr-un subdomeniu c1..c2 verific respectarea acestei
proprieti. Orice nclcare a ei indic o eroare care trebuie nlturat. Valoarea variabilei poate fi
calculat sau introdus de utilizator. n primul caz, verificarea trebuie fcut dup calcul, n al doilea caz
se recomand ca verificarea s urmeze imediat dup citirea valorii respectivei variabile.
5. Cunoate i folosete metodele de programare.
Este vorba de programarea Top-Down, Rafinarea n pai succesivi, Divide et impera [Gries85]),
Bottom-up i mixt, programarea modular, programarea structurat i celelalte metode prezentate n
acest curs, sau alte metode ce vor fi asimilate ulterior.
Aceste metode ncurajeaz reutilizarea, reducnd costul realizrii programelor. De asemenea,
folosirea unor componente existente (deci testate) mrete gradul de fiabilitate a produselor soft realizate
i scurteaz perioada de realizare a acestora. Evident, dac o parte din SUBPROGRAMii necesari
programului sunt deja scrii i verificai, viteza de lucru va crete prin folosirea lor. Folosete deci
bibliotecile de componente reutilizabile existente i construiete singur astfel de biblioteci, care s
nglobeze experiena proprie.
69

O bun programare modular elimin legturile ntre dou module prin variabile globale. Se
recomand ca fiecare modul s realizeze o activitate bine definit i independent de alt modul.
Comunicarea ntre dou module trebuie s se realizeze numai prin mecanismul parametrilor formaliactuali.
6. Amn pe mai trziu detaliile nesemnificative.
Aceast regul stabilete prioritile de realizare a componentelor unui program; n primul rnd se
acord atenie aspectelor eseniale, ncepnd cu modulul principal. n fiecare faz d atenie lucrurilor
importante. De exemplu, este inutil s se piard timp cu scrierea unor pri de program pentru tiprirea
rezultatelor i a constata ulterior c rezultatele nu sunt cele dorite, sau nu sunt corecte.
Nu uita ns c pentru beneficiar "Detaliile nesemnificative sunt semnificative". Beneficiarii in
foarte mult la forma rezultatelor i, adeseori, judec programatorii dup aceast form. E pcat de munca
depus dac tiprirea rezultatelor las o impresie proast asupra beneficiarului.
7. Evit artificiile.
Prin folosirea artificiilor n programare, a prescurtrilor i simplificrilor se pierde adesea din
claritatea programului i, mult mai grav, uneori se ajunge chiar la introducerea unor erori. n plus se poate
pierde portabilitatea programului.
Exist ns situaii n care prin anumite artificii se ctig eficien n execuie sau se face
economie de memorie. Dac acest fapt este important atunci artificiile sunt binevenite, n caz contrar nu
se recomand folosirea lor.
8. Folosete constante simbolice.
Folosirea intensiv a constantelor simbolice este recomandat oriunde n textul surs trebuie scris
un numr (la declararea tablourilor, la precizarea limitelor de variaie a unor variabile, etc.). Prin
utilizarea acestor constante se mrete gradul de generalitate a textului scris, iar n situaia n care
valoarea unei constante trebuie schimbat, modificarea este mult mai uoar (doar la locul definiiei
constantei) i nu duce la erori. Ea implic numai definiia constantei, nu modificarea valorii concrete n
toate instruciunile programului.
9. Verific corectitudinea algoritmului i programului n fiecare etap a elaborrii lor.
Detectarea i eliminarea unei erori imediat dup comiterea ei duce la creterea vitezei de realizare
a produsului, evitndu-se activiti inutile de depanare. Se recomand demonstrarea corectitudinii fiecrui
algoritm folosit, ntruct erorile semnalate n timpul testrii sunt adeseori greu de descoperit i, cteodat,
imposibil de eliminat altfel dect prin rescrierea modulului sau programului respectiv. Urmeaz testarea
fiecrui subprogram imediat dup ce a fost scris (codificat). Acest lucru se potrivete codificrii bottomup i sugereaz o abordare sistematic a activitii de codificare. Dac pentru proiectare se pot folosi
oricare dintre metodele indicate, n codificare (i testarea aferent codificrii), abordarea de jos n sus este
esenial. Sugerm ca aceast testare s se fac independent de programul n care se va folosi
subprogramul testat. Este adevrat c activitatea de testare necesit un anumit timp, dar ea este util cel
puin din trei puncte de vedere:
scoate n eviden erorile provocate de proiectarea algoritmului sau codificarea
neadecvat a acestuia;
faciliteaz detectarea erorilor, deoarece dimensiunea problemei este mai mic; n fapt nu
se pierde timp cu scrierea unui program de test, ci se ctig timp, deoarece la fiecare nivel
de detaliere se vor folosi numai componente testate deja; ceea ce rmne de testat la
nivelul respectiv este gestiunea corect a apelurilor respectivelor componente;
70

oblig implementatorul s gndeasc nc o utilizare (cel puin) a respectivului


subprogram, independent de cea pentru care a fost iniial conceput.
10. Folosete denumiri sugestive pentru identificatorii utilizai n program.
Fiecare identificator (nume de variabil, de tip de date, de constante, de subprograme) i are rolul
i semnificaia lui ntr-un program. E bine ca denumirea s reflecte aceast semnificaie, mrind astfel
claritatea textului programului.
Unii programatori exagereaz ns, folosind identificatori lungi, obinui prin concatenarea mai
multor cuvinte. E clar c denumirea ales red semnificaia variabilei, dar claritatea textului scade,
lungimea programului crete i citirea lui devine greoaie.
11. Cunoate i respect semnificaia fiecrei variabile.
Fiecare variabil are o semnificaie. n demonstrarea corectitudinii algoritmului aceast
semnificaie se reflect, de cele mai multe ori, printr-un predicat invariant. O greeal frecvent fcut de
unii programatori const n folosirea unei variabile n mai multe scopuri.
12. Folosete variabile auxiliare numai acolo unde este strict necesar.
Fiecare variabil trebuie s aib o semnificaie proprie, iar n demonstrarea corectitudinii
programului, acesteia i se ataeaz un invariant, care trebuie verificat.
Folosirea necontrolat a mai multor variabile auxiliare, ruperea unor expresii chiar lungi n
subexpresii cu diferite denumiri, pot duce la reducerea claritii programului.
13. Prin scriere red ct mai fidel structura programului.
Importana indentrii i spaierii pentru claritatea programului au fost artate anterior. Fiecare
programator trebuie s aib propriile reguli de scriere, care s scoat ct mai bine n eviden structura
programului i funciile fiecrei pri a acestuia.
14. Nu uita s testezi programul chiar dac ai demonstrat corectitudinea lui.
Sunt cunoscute demonstraii greite pentru unele teoreme celebre din matematic. i o
demonstraie a corectitudinii unui program poate fi greit. Dar, chiar dac demonstrarea corectitudinii
algoritmului este valid, programul poate conine greeli de codificare, de introducere (tastare) sau pot fi
alte cauze care genereaz erori.
15. Nu recalcula limitele i nu modifica variabila de ciclare n interiorul unei structuri repetitive
dat prin propoziia Pseudocod PENTRU.
O astfel de practic poate duce la erori greu de detectat i ncalc regulile programrii structurate.
Atunci cnd este necesar schimbarea variabilei de ciclare sau a limitelor se recomand folosirea uneia
din structurile repetitive REPET sau CTTIMP.
16. Nu iei forat din corpul unei structuri repetitive redat prin propoziia Pseudocod PENTRU.
Instruciunea Pseudocod PENTRU corespunde unui numr cunoscut de execuii ale corpului
ciclului. n situaia cnd corpul conine i testarea condiiei de continuare a ciclrii, recomandm a se
folosi structurile REPET sau CTTIMP i nu PENTRU.

71

17. Elaboreaz documentaia programului n paralel cu realizarea lui.


Aa cum s-a artat n mai multe locuri din acest material, pe durata de via a unui program se iau
mai multe decizii. E bine ca aceste decizii s rmn consemnate mpreun cu rezultatul final al fiecrei
faze din viaa programului (specificarea problemei, proiectarea algoritmilor, programul propriu-zis, datele
de test folosite). Vor rezulta documentaii de analiz, proiectare, implementare i exploatare. Primele trei
sunt necesare la ntreinerea aplicaiei, trebuind a fi actualizate ori de cte ori se produc modificri, iar
ultima este necesar celor care exploateaz aplicaia. Pe lng acestea, un program bun va trebui s
posede i o component de asisten on-line (funcie help), care contribuie la asigurarea a ceea ce am
numit interfa prietenoas.
18. Folosete comentariile.
Rolul comentariilor a fost explicat n seciunea 4.4. Este foarte greu s descifrm un program lipsit
de comentarii, chiar dac este vorba de propriu; program scris n urm cu cteva luni sau ani de zile.
Orice program sau modul trebuie s fie nsoit de comentarii explicative dac dorim s-l refolosim i nu
trebuie s scriem programe care s nu poat fi refolosite. Minimum de comentarii ntr-un modul trebuie s
conin specificarea acestui modul i semnificaia fiecrei variabile.

72

CAPITOLUL IX
METODA BACKTRACKING
La dispoziia celor care rezolv probleme cu ajutorul calculatorului exist mai multe metode.
Dintre acestea cel mai des utilizate sunt:
metoda Greedy;
metoda Divide et impera;
metoda Branch and Bound;
metoda Backtracking;
Metoda backtracking se aplic problemelor n care soluia poate fi reprezentat sub forma unui
vector x = (x1, x2, x3, xk, xn) S, unde S este mulimea soluiilor problemei i S = S1 x S2 x x
Sn, i Si sunt mulimi finite avnd s elemente si xi si , ()i = 1..n.
Pentru fiecare problem se dau relaii ntre componentele vectorului x, care sunt numite condiii
interne; soluiile posibile care satisfac condiiile interne se numesc soluii rezultat. Metoda de generare a
tuturor soluiilor posibile si apoi de determinare a soluiilor rezultat prin verificarea ndeplinirii condiiilor
interne necesit foarte mult timp.
Metoda backtracking evit aceast generare i este mai eficient. Elementele vectorului x,
primesc pe rnd valori n ordinea cresctoare a indicilor, x[k] va primi o valoare numai daca au fost
atribuite valori elementelor x1.. x[k-1]. La atribuirea valorii lui x[k] se verifica ndeplinirea unor condiii
de continuare referitoare la x1x[k-1]. Daca aceste condiii nu sunt ndeplinite, la pasul k, acest lucru
nseamn ca orice valori i-am atribui lui x[k+1], x[k+1], .. x[n] nu se va ajunge la o soluie rezultat.
Metoda backtracking construiete un vector soluie n mod progresiv ncepnd cu prima
component a vectorului i mergnd spre ultima cu eventuale reveniri asupra atribuirilor anterioare.
Metoda se aplica astfel :
1) se alege prima valoare sin S1 si I se atribuie lui x1 ;
2) se presupun generate elementele x1x[k-1], cu valori din S1..S[k-1]; pentru generarea lui x[k] se
alege primul element din S[k] disponibil si pentru valoarea aleasa se testeaz ndeplinirea
condiiilor de continuare.
Pot aprea urmtoarele situaii :
a) x[k] ndeplinete condiiile de continuare. Daca s-a ajuns la soluia final (k = n) atunci se
afieaz soluia obinut. Daca nu s-a ajuns la soluia final se trece la generarea
elementului urmtor x [k-1];
b) x[k] nu ndeplinete condiiile de continuare. Se ncearc urmtoarea valoare disponibila
din S[k]. Daca nu se gsete nici o valoare n S[k] care s ndeplineasc condiiile de
continuare, se revine la elementul x[k-1] i se reia algoritmul pentru o nou valoare a
acestuia. Algoritmul se ncheie cnd au fost luate in considerare toate elementele lui S1.
Problemele rezolvate prin aceast metod necesit timp mare de execuie, de aceea este indicat sa
se foloseasc metoda numai daca nu avem alt algoritm de rezolvare.
Dac mulimile S1,S2,Sn au acelai numr k de elemente, timpul necesar de execuie al
algoritmului este k la n. Dac mulimile S1, S2.. Sn nu au acelai numr de elemente, atunci se noteaz cu
m minimul cardinalelor mulimilor S1Sn si cu M, maximul. Timpul de execuie este situat n
intervalul [m la n .. M la n]. Metoda backtracking are complexitatea exponenial, in cele mai multe
cazuri fiind ineficient. Ea insa nu poate fi nlocuit cu alte variante de rezolvare mai rapide n situaia n
care se cere determinarea tuturor soluiilor unei probleme.
Generarea permutrilor. Se citete un numr natural n. S se genereze toate permutrile
mulimii {1, 2, 3, ,n}.
Generarea permutrilor se va face innd cont c orice permutare va fi alctuit din elemente
distincte ale mulimii A. Din acest motiv, la generarea unei permutri, vom urmri ca numerele s fie
distincte.
73

Prezentm algoritmul corespunztor cazului n=3:

1
1

2
1

1
2
1

2
2
1

3
2
1

3
1

1
3
1

2
3
1

3
3
1

1
2

1
1
2

2
1
2

3
1
2

2
2

3
2

1
3
2

se ncarc n stiv pe nivelul 1 valoarea 1;


ncrcarea valorii 1 pe nivelul al 2-lea nu este posibil, ntruct aceast valoare se
gsete i pe nivelul 1 al stivei;
ncrcarea valorii 2 pe nivelul al 2-lea este posibil, deoarece aceast valoare nu mai
este ntlnit;
valoarea 1 din nivelul al 3-lea se regsete pe nivelul 1;
valoarea 2 din nivelul al 3-lea se regsete pe nivelul al 2-lea;
valoarea 3 pe nivelul al 3-lea nu e ntlnit pe nivelurile anterioare; ntruct nivelul 3
este completat corect. Tiprim: 1 2 3

Algoritmul continu pn cnd stiva devine vid.


Programul sursa este urmatorul:
Private Sub CommandButton14_Click()
cit_n "n = ", n
back_perm
End Sub
Sub back_perm()
Dim k As Integer
k = 1
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid1 ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_r
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
74

End Sub
Sub valid1(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Then
ev = False
End If
Next
End Sub
Sub tipar_r()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + Str$(st.ss(i)) + ","
Next
MsgBox b
End Sub
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

Stiva este acea form de organizare a datelor (structur de date) cu proprietatea c operaiile de
introducere i scoatere a datelor se fac n vrful ei.
Stivele se pot simula utiliznd vectori.
Fie ST(i) un vector. ST(1), ST(2), ..., ST(n) pot reine numai litere sau numai cifre. O variabil K
indic n permanent vrful stivei.
Exemplificm, n continuare, modul de lucru cu stiva:
A
B
A

n stiva iniial vid se introduce litera A, vrful stivei va fi la nivelul 1 (k-1);


introducem n stiv litera B, deci k va lua valoarea 2;
scoatem din stiv pe B (A nu poate fi scos);
scoatem din stiv pe A; stiva rmne vid

n mod practic la scoaterea unei variabile din stiv, scade cu 1 valoarea variabilei ce indic vrful
stivei, iar atunci cnd scriem ceva n stiv, o eventual valoare rezidual se pierde:
Pe un anumit nivel se retine, de regul, o singur informaie (liter sau cifr), ns este posibil; aa
cum va rezulta din exemplele, prezentate n lucrare, s avem mai multe informaii, caz n care avem de a
face cu stive duble, triple, etc.
ntreaga teorie a recursivitii se bazeaz pe structura de tip stiv.
75

Prezentarea tehnicii Backtracking


Aceast tehnic se folosete n rezolvarea problemelor care ndeplinesc simultan urmtoarele
condiii:
soluia lor poate fi pus sub forma unui vector S=x1,x2, ...,xn, cu x1 A1, x2 A2 , xn

An
mulimile A1, A2 , ., An sunt mulimi finite, iar elementele lor se consider c se afl

ntr-o relaie de ordine bine stabilit;


nu se dispune de o alt metod de rezolvare, mai rapid

x1 x2 , xn pot fi la rndul lor vectori;

A1, A2 , An pot coincide.

La ntlnirea unei astfel de probleme, dac nu cunoatem aceast tehnic, suntem tentai s
generm toate elementele produsului cartezian A1,A2 ,An si fiecare element s fie testat dac este
soluie. Rezolvnd problema n acest mod, timpul de execuie este att de mare, nct poate fi considerat
infinit, algoritmul neavnd nici o valoare practic.
De exemplu, dac dorim s generm toate permutrile unei mulimi finite A, nu are rost s
generm produsul cartezian AxAx.....xA, pentru ca apoi, s testm, pentru fiecare element al acestuia,
dac este sau nu permutare (nu are rost s generm 1.1,1.......1, pentru ca apoi s constatm c nu am
obinut o permutare, cnd de la a doua cifr 1 ne puteam da seama c cifrele nu sunt distincte).
Tehnica Backtracking are la baz un principiu extrem de simplu:
se construiete soluia pas cu pas: x1, x2 ,xn

dac se constat c, pentru o valoare aleas, nu avem cum s ajungem la soluie, se

renun la acea valoare i se reia cutarea din punctul n care am rmas.


Concret:
se alege primul element x, ce aparine lui A;
presupunnd generate elementele x1,x2 ,xk , aparinnd mulimilor A1, A2 ,Ak, se
alege (dac exist) xk+1, primul element disponibil din mulimea Ak+1, apar dou posibiliti:
1) Nu s-a gsit un astfel de element, caz n care caz n care se reia cutarea considernd
generate elementele x1,x2 ,xk+1 , iar aceasta se reia de la urmtorul element al mulimii
Ak rmas netestat;
2) A fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii de
continuare aprnd astfel dou posibiliti:
ndeplinete, caz n care se testeaz dac s-a ajuns la soluie si apar din nou dou
posibiliti:
- s-a ajuns la soluie, se tiprete soluia si se reia algoritmul considernd generate
elementele x1,x2 ,xk, (se caut n continuare, un alt element al mulimii Ak, rmas
netestat);
- nu s-a ajuns la soluie, caz n care se reia algoritmul considernd generate elementele
x1,x2 ,xk , si se caut un prim element xk+2 Ak.
nu le ndeplinete caz n care se reia algoritmul considernd generate elementele x 1,x2
, xk , iar elementul xk-1 se caut ntre elementele mulimii A, rmase netestate.
Algoritmii se termin atunci cnd nu exist nici un element x1 A1 netestat.
Observaie: tehnica Backtracking are ca rezultat obinerea tuturor soluiilor problemei. n cazul n care
se cere o sigur soluie se poate fora oprirea, atunci cnd a fost gsit.
Am artat c orice soluie se genereaz sub form de vector. Vom considera c generarea soluiilor
se face intr-o stiv. Astfel, x1 A1, se va gsi pe primul nivel al stivei, x2 A2 se va gsi pe al doilea nivel
al stivei,... xk Ak se va gsi pe nivelul k al stivei. n acest fel, stiva (notat ST) va arta astfel:

76

...
xk

x2
ST

x1

Nivelul k+1 al stivei trebuie iniializat


(pentru a alege, n ordine, elementele mulimii
k+1 ). Iniializarea trebuie fcut cu o valoare aflat (n relaia de ordine considerat, pentru mulimea
Ak+1 ) naintea tuturor valorilor posibile din mulime. De exemplu, pentru generarea permutrilor mulimii
{1,2.....n}, orice nivel al stivei va lua valori de la 1 la n. Iniializarea unui nivel (oarecare) se face cu
valoarea 0. Procedura de iniializare o vom numi INIT i va avea doi parametri: k (nivelul care trebuie
iniializat si ST (stiva)).
Gsirea urmtorului element al mulimii Ak (element care a fost netestat) se face cu ajutorul
procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o variabil boolean. n situaia n
care am gsit elementul, acesta este pus n stiv i AS ia valoarea TRUE, contrar (nu a rmas un element
netestat) AS ia valoarea FALSE..
Odat ales un element, trebuie vzut dac acesta ndeplinete condiiile de continuare (altfel spus,
dac elementul este valid). Acest test se face cu ajutorul procedurii VALID (EV,ST,K).
Testul dac s-a ajuns sau nu la soluia final se face cu ajutorul funciei SOLUTIE(k) iar o soluie
se tiprete cu ajutorul procedurii TIPAR. Prezentm n continuare rutina Backtracking:
k:=1; CALL init(1,st);
while k>0
do
CALL succesor (as, st, k) ;
if as then CALLvalid(ev,st,k) then
loop until (not as) or (as and ev) ;
if as then
if solutie(k) then
CALL tipar
else
k:=k+l;
CALL init ( k, st );
end;
else
k:=k-1
wend

Observaie: Problemele rezolvate prin aceast metod necesit un timp ndelungat. Din acest motiv, este
bine s utilizm metoda numai atunci cnd nu avem la dispoziie un alt algoritm mai eficient. Cu toate c
exist probleme pentru care nu se pot elabora ali algoritmi mai eficieni, tehnica backtracking trebuie
aplicat numai n ultim instan.
Fiind dat o tabl de ah, de dimensiune n, x n, se cer toate soluiile de aranjare a n dame, astfel
nct s nu se afle dou dame pe aceeai linie, coloan sau diagonal (dame s nu se atace reciproc).
Exemplu: Presupunnd c dispunem de o tabl de dimensiune 4x4, o soluie ar fi urmtoarea:
77

D
D
D
D
Observm c o dam trebuie s fie plasat singur pe linie. Plasm prima dam pe linia 1, coloana 1.
D

A doua dam nu poate fi aezat dect n coloana 3.


D
D

Observm c a treia dam nu poate fi plasat n linia 3. ncercm atunci plasarea celei de-a doua dame n
coloana 4.
D
D

A treia dam nu poate fi plasat dect n coloana 2.


D
D
D

n aceast situaie dama a patra nu mai poate fi aezat.


ncercnd s avansm cu dama a treia, observm c nu este posibil s o plasm nici n coloana 3,
nici n coloana 4, deci o vom scoate de pe tabl. Dama a doua nu mai poate avansa, deci i ea este scoas
de pe tabl. Avansm cu prima dam n coloana 2.
D

A doua dam nu poate fi aezat dect n coloana 4.


D

78

Dama a treia se aeaz n prima coloan.


D
D
D

Acum este posibil s plasm a patra dam n coloana 3 si astfel am obinut o soluie a problemei.
D
D
D
D
Algoritmul continu n acest mod pn cnd trebuie scoas de pe tabl prima dam.
Pentru reprezentarea unei soluii putem folosi un vector cu n componente (avnd n vedere c pe
fiecare linie se gsete o singur dam).
Exemplu pentru soluia gsit avem vectorul ST ce poate fi asimilat unei stive.
Dou dame se gsesc pe aceeai diagonal dac si numai dac este ndeplinit condiia: |st(i)-st(j)|
=|i-j| ( diferena, n modul, ntre linii si coloane este aceeai).
n general ST(i)=k semnific faptul c pe linia i dama ocup poziia k.
3

ST(4)

ST(3)

ST(2)

ST(1)

Exemplu: n tabla 4 x4 avem situaia:


D

st(1)= 1 i = 1
st(3)= 3 j = 3
|st(1) - st(3)| = |1 3| = 2
|i j| = |1 3| = 2

D
D
D
sau situaia
D
D
D
D

st(1) = 3 i = 1
st(3) = 1 j = 3
|st(i) - st(j)| = |3 1| = 2
79

|i j| = |1 3| = 2
ntruct doua dame nu se pot gsi n aceeai coloan, rezult c o soluie este sub form de
permutare. O prim idee ne conduce la generarea tuturor permutrilor si la extragerea soluiilor pentru
problema ca dou dame s nu fie plasate n aceeai diagonal. A proceda astfel, nseamn c lucrm
conform strategiei backtracking. Aceasta presupune ca imediat ce am gsit dou dame care se atac, s
relum cutarea.
Iat algoritmul, conform strategiei generate de backtracking:
n prima poziie a stivei se ncarc valoarea 1, cu semnificaia c n linia unu se aeaz
prima dam n coloan.
Linia 2 se ncearc aezarea damei n coloana 1, acest lucru nefiind posibil ntruct
avem doua dame pe aceeai coloan.
n linia 2 se ncearc aezarea damei n coloana 2 , ns acest lucru nu este posibil,
pentru c damele se gsesc pe aceiai diagonal (|st(1)-st(2)|=|1-2|);
Aezarea damei 2 n coloana 3 este posibil.
Nu se poate plasa dama 3 n coloana 1, ntruct n liniile 1-3 damele ocupa acelai
coloan.
i aceast ncercare eueaz ntruct damele de pe 2 i 3 sunt pe aceeai diagonal.
Damele de pe 2-3 se gsesc pe aceeai coloan.
Damele de pe 2-3 se gsesc pe aceeai diagonal.
Am cobort n stiv mutnd dama de pe linia 2 i coloana 3 n coloana 4.
Algoritmul se ncheie atunci cnd stiva este vid. Semnificaia procedurilor utilizate este
urmtoarea:
INIT - nivelul k al stivei este iniializat cu 0;
SUCCESOR - mrete cu 1 valoarea aflat pe nivelul k al stivei n situaia n care aceasta
este mai mic dect n i atribuie variabilei EV valoarea TRUE, n caz contrar, atribuie
variabilei EV valoarea FALSE;
VALID - valideaz valoarea pus pe nivelul k al stivei, verificnd dac nu avem dou
dame pe aceeai linie (st(k)=st(i)), sau dac nu avem dou dame pe aceeai diagonal
(st(k)-st(i)=|k-i|)caz n care variabilei EV i se atribuie FALSE; n caz contrar, variabilei EV
i se atribuie TRUE;
SOLUTIE - verific dac stiva a fost completat pn la nivelul n inclusiv;
TIPAR - tiprete o soluie.
Subprogramele prezentate in limbajul Visual Basic sunt descrise mai jos:
Global n As Integer, am_suc As Boolean, ev As Boolean
Type stiva
ss(100) As Integer
End Type
Global st As stiva
Sub init(k As Integer, st As stiva)
st.ss(k) = 0
End Sub
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
80

End Sub
Sub valid(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Or (Abs(st.ss(i) - st.ss(k)) = Abs(k i)) Then
ev = False
End If
Next
End Sub
Function solutie(k As Integer) As Integer
If k = n Then
solutie = True
Else
solutie = False
End If
End Function
Sub tipar()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "(" + Str$(i) + "," + Str$(st.ss(i)) + "),"
Next
MsgBox b
End Sub
Sub back()
Dim k As Integer
k = 1
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Sub Button2_Click()
n = InputBox("n=", ib_title)
back
End Sub
81

Produsul cartezian a n mulimi. Se dau mulimile de mai jos i se cere produsul cartezian al lor.
A1 = {1, 2, 3, , k1}
A2 = {1, 2, 3, , k2}

An = {1, 2, 3, , kn}
Exemplu:
A1 = {1, 2}
A2 = {1, 2, 3}
A3 = {1, 2, 3}
A1 A2 A3 = {(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 1), (1, 3, 2), (1, 3, 3),
(2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 1), (2, 3, 2), (2, 3, 3)}.
Pentru rezolvare, se folosesc stiva ST i un vector A ce reine numerele k 1, k2, kn. Utilizm
metoda backtracking, uor modificat din urmtoarele motive:
a) Orice element aflat la nivelul k al stivei este valid, motiv pentru care procedura valid nu
face altceva dect s atribuie variabilei ev valoarea TRUE.
b) Limita superioar pe nivelul k al stivei este dat de A(k).
Modul de concepere a algoritmului rezult din cele ce urmeaz:
1

Observaii:
Algoritmul prezentat aici este de tip backtracking? ntrebarea are sens pentru c este absent mecanismul
de ntoarcere. Vom admite c i aceasta este backtracking, dar degenerat.
Private Sub CommandButton16_Click()
Dim a As vector
cit_n "n=", n
cit_date "a", n, a
tipar " multimile sunt : ", n, a
back_prod_cart
End Sub
Sub cit_n(mes As String, nnn As Integer)
Do
nnn = InputBox(mes, y)
Loop Until n > 0 And n < 100
End Sub
Sub cit_date(mes As String, n As Integer, a As vector)
For i = 1 To n
a.v(i) = InputBox(mes + "(" + Str$(i) + ")=", y)
82

Next
End Sub
Sub tipar(mes
sir = ""
For i = 1 To
sir = sir +
Next
MsgBox mes +
End Sub

As String, n As Integer, a As vector)


n
Str$(a.v(i)) + ","
" " + sir

Sub back_prod_cart()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_prod am_suc, st, k
If am_suc = True Then
valid_prod ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_r
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Sub valid_prod(ev As Boolean, st As stiva, k As Integer)
ev = True
End Sub
Function solutie(k As Integer) As Boolean
If k = n Then
solutie = True
Else
solutie = False
End If
End Function
Sub succesor_prod(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < a.v(k) Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub init(k As Integer, st As stiva)
st.ss(k) = 0
End Sub
83

Generarea aranjamentelor. Se citesc n i p. S se genereze toate aranjamentele de n luate cte p.


Din analiza problemei rezult urmtoarele:
stiva are nlimea p;
fiecare nivel ia valori ntre 1 i n;
elementele plasate pe diverse niveluri trebuie s fie distincte.
Algoritmul este asemntor cu cel de la permutri, cu deosebirea c aici stipa are nlimea p.
Private Sub CommandButton17_Click()
cit_n "n = ", n
cit_n "p = ", p
back_aranj
End Sub
Sub back_aranj()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid1 ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie1(k) Then
tipar_rr
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Sub valid1(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Then
ev = False
End If
Next
End Sub
Sub tipar_rr()
Dim i As Integer, b As String
b = " "
For i = 1 To p
b = b + Str$(st.ss(i)) + ","
Next
MsgBox b
End Sub
84

Function solutie1(k As Integer) As Boolean


If k = p Then
solutie1 = True
Else
solutie1 = False
End If
End Function
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub init(k As Integer, st As stiva)
st.ss(k) = 0
End Sub

Generarea combinrilor. Se citesc n i p numere naturale, np. Se cere s se genereze toate


submulimile cu p elemente ale mulimii {1, 2, 3, , n}.
Pentru rezolvarea problemei trebuie inut cont de urmtoarele:
stiva are nlimea p;
elementele aflate pe niveluri diferite ale stivei trebuie s fie distincte;
pentru a evita repetiia elementele se aeaz n ordine cresctoare: pe nivelul k se va afla
o valoare mai mare dect pe nivelul k-1 i mai mic sau egal cu n-p+k.
Private Sub CommandButton18_Click()
cit_n "n = ", n
cit_n "p = ", p
back_comb
End Sub
Sub back_comb()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_c am_suc, st, k
If am_suc = True Then
valid_c ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie1(k) Then
tipar_rr
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
85

End Sub
Sub succesor_c(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n - p + k Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub valid_c(ev As Boolean, st As stiva, k As Integer)
Dim i As Integer
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Then
ev = False
End If
Next
If k > 1 Then
If st.ss(k) < st.ss(k - 1) Then
ev = False
End If
End If
End Sub
Function solutie1(k As Integer) As Boolean
If k = p Then
solutie1 = True
Else
solutie1 = False
End If
End Function
Sub tipar_col()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "Tara = " + Str$(i) + "; culoarea " + Str$(st.ss(i)) + " "
Next
MsgBox b
End Sub

Problema comis-voiajorului. Un comis voiajor trebuie s viziteze un numr n de orae. Iniial, el


se afl ntr-unul dintre ele, notat 1. Comis voiajorul dorete s nu treac de dou ori prin acelai ora, iar
la ntoarcere s revin n oraul 1. Cunoscnd legturile existente ntre orae, se cere s se tipreasc toate
drumurile posibile pe care le poate efectua comis voiajorul.

Exemplu: n figura alturat sunt simbolizate cele 6 orae, precum i drumurile existente ntre ele.
86

Comis - voiajorul are urmtoarele posibiliti de parcurgere:


1, 2, 3, 4, 5, 6, 1;
1, 2, 5, 4, 3, 6, 1;
1, 6, 3, 4, 5, 2, 1;
1, 6, 5, 4, 3, 2, 1;
Legturile existente ntre orae sunt date n matricea An,n. Elementele matricei A pot fi 0 sau 1
(matricea este binar).
1, dac exist drum ntre oraele i i j;
A(i,j) =
0 , altfel
Se observ c A(i,j) = A(j,i), oricare ar fi i,j {1, 2, 3, , n} matricea este simetric.
Pentru rezolvarea problemei folosim stiva st. la baza stivei (nivelul 1) se ncarc numrul 1.
Prezentm n continuare modul de rezolvare a problemei.
2
1

De la oraul 1 la oraul 2 exist drum, deci se va urca n stiv;

2
2
1

Oraul 2 se mai gsete n stiv, deci nu este acceptat;

3
2
1

De la oraul 2 la oraul 3 se gsete drum; prin oraul 3 nu s-a mai trecut, deci
oraul 3 este acceptat.

Algoritmul continu n acest mod pn se ajunge din nou la nivelul 1, caz n care algoritmul se
ncheie.
Un succesor, ntre 2 i n, aflat pe nivelul k al stivei, este considerat valid dac sunt ndeplinite
urmtoarele condiii:
nu s-a mai trecut prin oraul simbolizat de succesor, deci acesta nu se regsete n stiv;
exist drum ntre oraul aflat la nivelul k-1 i cel aflat la nivelul k;
dac succesorul se gsete la nivelul n, s existe drum de la el la oraul 1.
Observaii:
1. Problemele rezolvate prin aceast metod necesit un timp ndelungat de execuie. Din
acest motiv este bine s utilizm metoda atunci numai atunci cnd nu mai avem la
dispoziie un alt algoritm mai eficient
87

2. Menionm c nu exist probleme pentru care nu se cunosc algoritmi eficieni de


rezolvare, deci backtracking este indicat.
3. Rezolvarea iterativ ncalc principiul stivei atunci cnd verificm condiiile de
continuare, sau atunci cnd tiprim soluia gsit, pentru c accesm orice nivel al stivei.
Consider c o structur trebuie folosit ca atare atunci cnd este strict necesar. De exemplu,
chiar i segmentul de stiv al calculatorului poate fi accesat oriunde. Asta nu nseamn c
acolo nu se utilizeaz din plin mecanismul stivei.
Sub back_comis()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_col am_suc, st, k
If am_suc = True Then
valid_col ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_col
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Sub succesor_comis(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub valid_comis(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) And (mat.m(i, k) = 1) Then
ev = False
End If
Next
End Sub
Sub tipar_comis()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "Tara = " + Str$(i) + "; vizitat " + Str$(st.ss(i)) + " "
Next
MsgBox b
88

End Sub

PROBLEMA COLORRII HRILOR


Enun:
Fiind dat o hart cu n ri, se cer toate soluiile de colorare a hrii, utiliznd cel mult patru culori,
astfel nct dou ri de frontier comun s fie colorate diferit. Este demonstrat faptul c sunt suficiente
numai patru culori pentru ca orice hart s poat fi colorat.
Rezolvare:
Pentru exemplificare, vom considera urmtoarea hart unde rile sunt numerotate cu cifre
cuprinse ntre 1 i 5:
1
4
2

3
5

Figura 9.1 Harta rilor


O soluie a acestei probleme este urmtoarea:
ara 1 culoarea 1
ara 2 culoarea 2
ara 3 culoarea 1
ara 4 culoarea 3
ara 5 culoarea 4
Harta este furnizat programului cu ajutorul unei matrice An,n
1, dac ara i se nvecineaz cu ara j;
A(i,j) =
0 , altfel
Matricea A este simetric. Pentru rezolvarea problemei se utilizeaz stiva st, unde nivelul k al
stivei simbolizeaz ara k, iar st[k] culoarea ataat rii k. Stiva are nlimea n i pe fiecare nivel ia
valori ntre 1 i 4.
Sub back_col()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_col am_suc, st, k
If am_suc = True Then
valid_col ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_col
Else
k = k + 1
89

init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Sub succesor_col(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < 4 Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub valid_col(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) And (mat.m(i, k) = 1) Then
ev = False
End If
Next
End Sub
Sub tipar_col()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "Tara = " + Str$(i) + "; culoarea " + Str$(st.ss(i)) + " "
Next
MsgBox b
End Sub
Sub tipar_rr()
Dim i As Integer, b As String
b = " "
For i = 1 To p
b = b + Str$(st.ss(i)) + ","
Next
MsgBox b
End Sub

90

CAPITOLUL X
METODA DIVIDE ET IMPERA
Metoda de programare DIVIDE ET IMPERA consta in impartirea problemei initiale de
dimensiuni [n] in doua sau mai multe probleme de dimensiuni reduse. In general se executa impartirea in
doua subprobleme de dimensiuni aproximativ egale si anume [n/2]. Impartirea in subprobleme are loc
pana cand dimensiunea acestora devine suficient de mica pentru a fi rezolvate in mod direct(cazul de
baza). Dupa rezolvarea celor doua subprobleme se executa faza de combinare a rezultatelor in vederea
rezolvarii intregii probleme.
Metoda DIVIDE ET IMPERA se poate aplica in rezolvarea unei probleme care indeplineste
urmatoarele conditii:
se poate descompune in (doua sau mai multe) suprobleme;
aceste suprobleme sunt independente una fata de alta (o subproblema nu se rezolva pe
baza alteia si nu se foloseste rezultate celeilalte);
aceste subprobleme sunt similare cu problema initiala;
la randul lor subproblemele se pot descompune (daca este necesar) in alte subprobleme
mai simple;
aceste subprobleme simple se pot solutiona imediat prin algoritmul simplificat.
Deoarece putine probleme indeplinesc conditiile de mai sus ,aplicarea metodei este destul de rara.
Dupa cum sugereaza si numele "desparte si stapaneste "etapele rezolvarii unei probleme (numita
problema initiala) in DIVIDE ET IMPERA sunt :
descompunerea problemei initiale in subprobleme independente, smilare problemei de
baza, de dimensiuni mai mici;
descompunerea treptata a subproblemelor in alte subprobleme din ce in ce mai simple,
pana cand se pot rezolva imediata ,prin algoritmul simplificat;
rezolvarea subproblemelor simple;
combinarea solutiilor gasite pentru construirea solutiilor subproblemelor de dimensiuni
din ce in ce mai mari;
combinarea ultimelor solutii determina obtinerea solutiei problemei initiale
Metoda DIVIDE ET IMPERA admite o implementare recursiva, deorece subproblemele sunt
similare problemei initiale, dar de dimensiuni mai mici.
Principiul fundamental al recursivitatii este autoapelarea unui subprogram cand acesta este activ;
ceea ce se intampla la un nivel, se intampla la orice nivel, avand grija sa asiguram conditia de terminare
ale apelurilor repetate. Asemanator se intampla si in cazul metodei DIVITE ET IMPERA; la un anumit
nivel sunt doua posibilitati:
s-a ajuns la o (sub)problema simpla ce admite o rezolvare imediata caz in care se
rezolva (sub)problema si se revine din apel (la subproblema anterioara, de dimensiuni mai
mari);
s-a ajuns la o (sub)problema care nu admite o rezolvare imediata, caz in care o
descompunem in doua sau mai multe subprobleme si pentru fiecare din ele se continua
apelurile recursive (ale procedurii sau functiei).
In etapa finala a metodei DIVIDE ET IMPERA se produce combinarea subproblemelor (rezolvate
deja) prin secventele de revenire din apelurile recursive.
Etapele metodei DIVIDE ET IMPERA (prezentate anterior) se pot reprezenta prin urmatorul
subprogram general (procedura sau functie )recursiv exprimat in limbaj natural:
Subprogram DIVIMP (PROB);
Daca PROBLEMA PROB este simpla
Atunci se rezolva si se obtine solutia SOL
Altfel pentru i=1,k executa DIVIMP(PROB) si se obtine SOL1;
91

Se combina solutiile SOL 1,... ,SOL K si se obtine SOL;


Sfarsit_subprogram;
Deci, subprogramul DIVIMP se apeleaza pentru problema initiala PROB; aceasta admite
descompunerea in K subprobleme simple; pentru acestea se reapeleaza recursiv subprogramul; in final se
combina solutiile acestor K subprobleme.
De obicei problema initiala se descompune in doua subprobleme mai simple; in acest caz etapele
generale ale metodei DIVIDE ET IMPERA se pot reprezenta concret, in limbaj pseudocod, printr-o
procedura recursiva astfel:
Procedura DIVIMP(li,ls,sol);
Daca ((ls-li)<=eps)
Atunci REZOLVA (li,ls,sol);
Altfel
DIVIDE (li,m,ls);
DIVIMP(li,msol1);
DIVIMP(m,ls,sol2);
COMBINA(sol1,sol2,sol);
Sfarsit_procedura;
Procedura DIVIMP se apeleaza pentru problema initiala care are dimensiunea intre limita
inferioara (li) si limita inferioara(ls); daca (sub)problema este simpla (ls-li<=eps), atunci procedura
REZOLVA ii afla solutia imediat si se produce intoarcerea din apelul recursiv; daca (sub)problema este
(inca) complexa, atunci procedura DIVIDE o imparte in doua subprobleme, alegand pozitia m intre
limitele li si ls; pentru fiecare din cele doua subprobleme se reapeleaza recursiv procedura DIVIMP; in
final, la intoarcerile din apeluri se produce combinarea celor doua soluitii sol1 si sol2 prin apelul
procedurii COMBINA.
PROBLEMA TURNURILOR DIN HANOI
Prezentarea algoritmului rezolvarii
Fie trei tije verticale notate A,B,C. Pe tija A se gasesc asezate n discuri de diametre diferite, in
ordinea crescatoare a diametrelor, privind de sus in jos. Initial, tijele B si C sunt goale. Sa se afiseze toate
mutarile prin care discurile de pe tija A se muta pe tija B, in aceeasi ordine, folosind ca tija de manevra C
si resspectand urmatoarele reguli:
la fiecare pas se muta un singur disc;
un disc se poate aseza numai peste un disc cu diametrul mai mare.
Rezolvarea acestei probleme se bazeaza pe urmatoarele considerente logice:
daca n=1, atunci mutarea este immediata AB (mut discul de pe A pe B);
daca n=2, atunci sirul mutarilor este: AC,AB,CB;
daca n>2 procedam astfel :
- mut (n-1) discuri AC;
- mut un disc AB;
- mut cele (n-1) discuri CB.
Observam ca problema initiala se descompune in trei subprobleme mai simple, similare problemei
initiale: mut (n-1)discuri AC, mut ultimul disc pe B, mut cele (n-1)discuri C-->B. Dimensiunile acestor
subprobleme sunt: n-1,1,n-1.
Aceste subprobleme sunt independente, deoarece tijele initial (pe care sunt dispuse discurile),
tijele finale si tijele intermediare sunt diferite. Notam H(n,A,B,C)=sirul mutarilor a n discuri de pe A pe
B, folosind C.
PENTRU
n=1 AB
n>1 H(n,A,B,C)= H(n-1,A,C,B),AB, H(n-1,C,B,A)
92

Sortare rapida (quicksort)


Un tablou V se completeaza cu n elemente numere reale .Sa se ordoneze crescator folosind
metoda de sortare rapida .
Solutia problemei se bazeaza pe urmatoarele etape implementate in programul principal:
se apeleaza procedura quick cu limita inferioara li=1 si limita superioara ls=n;
functiapoz realizeaza mutarea elementului v[i] exact pe pozitia ce o va ocupa acesta
in vectorul final ordonat ; functiapoz intoarce (in k ) pozitia ocupata de acest element;
in acest fel , vectorul V se imparte in doua parti: li k-1 si k+1ls;
pentru fiecare din aceste parti se reapeleaza procedura quick, cu limitele modificate
corespunzator;
in acest fel, primul element din fiecare parte va fi pozitionat exact pe pozitia finala ce o
va ocupa in vectorul final ordonat (functiapoz);
fiecare din cele doua parti va fi, astfel, inpartita in alte doua parti; procesul continua
pana cand limitele partilor ajung sa se suprapuna ,ceea ce indica ca toate elementele
vectorului au fost mutate exact pe pozitiile ce le vor ocupa in vectorul final ;deci vectorul
este ordonat ;
in acest moment se produc intoarcerile din apelurile recursive si programul isi termina
executia.
Observaii:
daca elementul se afla in stanga, atunci se compara cu elementele din dreapta lui si se
sar (j:=j-1) elementele mai mari decat el;
daca elementul se afla in dreapta, atunci se compara cu elemente din stanga lui si se sar
(i:=i+1) elementele mai mici decat el.
Sortare prin interclasare(mergesort)
Tabloul unidimensional V se completeaza cu n numere reale. Sa se ordoneze crescator folosind
sortare prin interclasare.
Sortarea prin interclasare se bazeaza pe urmatoarea logica:
vectorul V se imparte, prin injumatatiri succesive,in vectori din ce in ce mai mici;
cand se ating vectorii de maxim doua elemente, fiecare dintre acestia se ordoneaza
printr-o simpla comparare a elementelor;
cate doi astfel de mini-vectori ordonati se interclaseaza succesiv pana se ajunge iar la
vectorul V.
Observaii:
mecanismul general de tip Divide et Impera se gaseste implementat in procedura divi;
astfel de abordare a problemei sortarii unii vector conduce la economie de timp de
calcul, deoarece operatia de interclasare a doi vectori deja ordonati este foarte rapida, iar
ordonarea independenta celor doua jumatati (mini-vectori) consuma in total aproximativ a
doua parte din timpul care ar fi necesar ordonarii vectorului luat ca intreg .
CONCLUZII LA TEHNICA DIVIDE ET IMPERA
Sortare prin insertie binara
Sa se ordoneze crescator un tablou unidimensional V de n numere reale, folosind sortarea prin
insertie binara.
Pentru fiecare element v[i] se procedeaza in patru pasi:
1. se considera ordonate elementele v[1],v[2],.,v[i-1];
2. se cauta pozitia k pe care urmeaza s-o ocupe v[i] intre elementele v[1],v[2],,v[i-1]
(procedura poz prin cautare binara);
3. se deplaseaza spre dreapta elementele din pozitiile k,k+1,,n (procedura deplasare);
93

4. insereaza elementul v[i] in pozitia k (proceduradeplasare);


Se obtine o succesiune de k+1 elemente ordonate crescator.
Analiza a complexitatii timp pentru algoritmii Divide et Impera
Algoritmii de tip Divide et Impera au buna comportare in timp, daca se indeplinesc urmatoarele
conditii:
dimensiunile subprogramelor (in care se imparte problema initiala) sunt aproximativ
egale (principiul balansarii);
lipsesc fazele de combinare a solutiilor subproblemelor (cautare binara).

94

CAPITOLUL XI
METODA GREEDY
11.1 Algoritmi greedy
Pusi in fata unei probleme pentru care trebuie sa elaboram un algoritm, de multe ori nu stim cum
sa incepem. Ca si in orice alta activitate, exista cateva principii generale care ne pot ajuta in aceasta
situatie. Ne propunem sa prezentam in urmatoarele capitole tehnicile fundamentale de elaborare a
algoritmilor. Cateva din aceste metode sunt atat de generale, incat le folosim frecvent, chiar daca numai
intuitiv, ca reguli elementare in gandire.
11.2 Tehnica greedy
Algoritmii greedy (greedy = lacom) sunt in general simpli si sunt folositi la probleme de
optimizare, cum ar fi: sa se gaseasca cea mai buna ordine de executare a unor lucrari pe calculator, sa se
gaseasca cel mai scurt drum intr-un graf etc. In cele mai multe situatii de acest fel avem:
multime de candidati (lucrari de executat, varfuri ale grafului etc)
o functie care verifica daca o anumita multime de candidati constituie o solutie posibila
o functie care verifica daca o multime de candidati este fezabila, adica daca este posibil
sa completam aceasta multime astfel incat sa obtinem o solutie posibila, nu neaparat
optima, a problemei
o functie de selectie care indica la orice moment care este cel mai promitator dintre
candidatii inca nefolositi
o functie obiectiv care da valoarea unei solutii (timpul necesar executarii tuturor
lucrarilor intr-o anumita ordine, lungimea drumului pe care l-am gasit etc); aceasta este
functia pe care urmarim sa o optimizam (minimizam/maximizam)
Pentru a rezolva problema noastra de optimizare, cautam o solutie posibila care sa optimizeze
valoarea functiei obiectiv. Un algoritm greedy construieste solutia pas cu pas. Initial, multimea
candidatilor selectati este vida. La fiecare pas, incercam sa adaugam acestei multimi cel mai promitator
candidat, conform functiei de selectie. Daca, dupa o astfel de adaugare, multimea de candidati selectati nu
mai este fezabila, eliminam ultimul candidat adaugat; acesta nu va mai fi niciodata considerat. Daca, dupa
adaugare, multimea de candidati selectati este fezabila, ultimul candidat adaugat va ramane de acum
incolo in ea. De fiecare data cand largim multimea candidatilor selectati, verificam daca aceasta multime
nu constituie o solutie posibila a problemei noastre. Daca algoritmul greedy functioneaza corect, prima
solutie gasita va fi totodata o solutie optima a problemei. Solutia optima nu este in mod necesar unica: se
poate ca functia obiectiv sa aiba aceeasi valoare optima pentru mai multe solutii posibile. Descrierea
formala a unui algoritm greedy general este:
function greedy(C)
S

{C este multimea candidatilor}


{S este multimea in care construim solutia}

while not solutie(S) and C do


x un element din C care maximizeaza/minimizeaza select(x)
C C \ {x}
if fezabil(S {x}) then S S {x}
if solutie(S)
then return S
else return nu exist soluie

95

Este de inteles acum de ce un astfel de algoritm se numeste lacom (am putea sa-i spunem si
nechibzuit). La fiecare pas, procedura alege cel mai bun candidat la momentul respectiv, fara sa-i pese
de viitor si fara sa se razgandeasca. Daca un candidat este inclus in solutie, el ramane acolo; daca un
candidat este exclus din solutie, el nu va mai fi niciodata reconsiderat. Asemenea unui intreprinzator
rudimentar care urmareste castigul imediat in dauna celui de perspectiva, un algoritm greedy actioneaza
simplist. Totusi, ca si in afaceri, o astfel de metoda poate da rezultate foarte bune tocmai datorita
simplitatii ei.
Functia select este de obicei derivata din functia obiectiv; uneori aceste doua functii sunt chiar
identice.
Un exemplu simplu de algoritm greedy este algoritmul folosit pentru rezolvarea urmatoarei
probleme. Sa presupunem ca dorim sa dam restul unui client, folosind un numar cat mai mic de monezi.
In acest caz, elementele problemei sunt:
candidatii: multimea initiala de monezi de 1, 5, si 25 unitati, in care presupunem ca din
fiecare tip de moneda avem o cantitate nelimitata
solutie posibila: valoarea totala a unei astfel de multimi de monezi selectate trebuie sa
fie exact valoarea pe care trebuie sa o dam ca rest
multime fezabila: valoarea totala a unei astfel de multimi de monezi selectate nu este
mai mare decat valoarea pe care trebuie sa o dam ca rest
functia de selectie: se alege cea mai mare moneda din multimea de candidati ramasa
functia obiectiv: numarul de monezi folosite in solutie; se doreste minimizarea acestui
numar
Se poate demonstra ca algoritmul greedy va gasi in acest caz mereu solutia optima (restul cu un
numar minim de monezi). Pe de alta parte, presupunand ca exista si monezi de 12 unitati sau ca unele din
tipurile de monezi lipsesc din multimea initiala de candidati, se pot gasi contraexemple pentru care
algoritmul nu gaseste solutia optima, sau nu gaseste nici o solutie cu toate ca exista solutie.
Evident, solutia optima se poate gasi incercand toate combinarile posibile de monezi. Acest mod
de lucru necesita insa foarte mult timp.
Un algoritm greedy nu duce deci intotdeauna la solutia optima, sau la o solutie. Este doar un
principiu general, urmand ca pentru fiecare caz in parte sa determinam daca obtinem sau nu solutia
optima.
11.3 Minimizarea timpului mediu de asteptare
O singura statie de servire (procesor, pompa de benzina etc) trebuie sa satisfaca cererile a n clienti.
Timpul de servire necesar fiecarui client este cunoscut in prealabil: pentru clientul i este necesar un timp
ti, 1 i n. Dorim sa minimizam timpul total de asteptare
(timpul de asteptare pentru clientul i)
ceea ce este acelasi lucru cu a minimiza timpul mediu de asteptare, care este T/n. De exemplu, daca avem
trei clienti cu t1 = 5, t2 = 10, t3 = 3, sunt posibile sase ordini de servire. In primul caz, clientul 1 este servit
primul, clientul 2 asteapta pana este servit clientul 1 si apoi este servit, clientul 3 asteapta pana sunt serviti
clientii 1, 2 si apoi este servit. Timpul total de asteptare a celor trei clienti este 38.
Ordinea
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

T
5+(5+10)+(5+10+3)
5+(5+3)+(5+3+10)
10+(10+5)+(10+5+3)
10+(10+3)+(10+3+5)
3+(3+5)+(3+5+10)
3+(3+10)+(3+10+5)
96

=
=
=
=
=
=

38
31
43
41
29
34

optim

Algoritmul greedy este foarte simplu: la fiecare pas se selecteaza clientul cu timpul minim de
servire din multimea de clienti ramasa. Vom demonstra ca acest algoritm este optim.
Fie I = (i1 i2 ... in) o permutare oarecare a intregilor {1, 2, ..., n}. Daca servirea are loc in ordinea I,
avem

Presupunem acum ca I este astfel incat putem gasi doi intregi a < b cu
Interschimbam pe ia cu ib in I; cu alte cuvinte, clientul care a fost servit al b-lea va fi servit acum al
a-lea si invers. Obtinem o noua ordine de servire J, care este de preferat deoarece

Prin metoda greedy obtinem deci intotdeauna planificarea optima a clientilor.


Problema poate fi generalizata pentru un sistem cu mai multe statii de servire.
Interclasarea optima a sirurilor ordonate
Sa presupunem ca avem doua siruri S1 si S2 ordonate crescator si ca dorim sa obtinem prin
interclasarea lor sirul ordonat crescator care contine elementele din cele doua siruri. Daca interclasarea
are loc prin deplasarea elementelor din cele doua siruri in noul sir rezultat, atunci numarul deplasarilor
este #S1 + #S2.
Generalizand, sa consideram acum n siruri S1, S2, ..., Sn, fiecare sir Si, 1 i n, fiind format din qi
elemente ordonate crescator (vom numi qi lungimea lui Si). Ne propunem sa obtinem sirul S ordonat
crescator, continand exact elementele din cele n siruri. Vom realiza acest lucru prin interclasari succesive
de cate doua siruri. Problema consta in determinarea ordinii optime in care trebuie efectuate aceste
interclasari, astfel incat numarul total al deplasarilor sa fie cat mai mic. Exemplul de mai jos ne arata ca
problema astfel formulata nu este banala, adica nu este indiferent in ce ordine se fac interclasarile.
Fie sirurile S1, S2, S3 de lungimi q1 = 30, q2 = 20, q3 = 10. Daca interclasam pe S1 cu S2, iar
rezultatul il interclasam cu S3, numarul total al deplasarilor este (30+20)+(50+10)=110. Daca il
interclasam pe S3 cu S2, iar rezultatul il interclasam cu S1, numarul total al deplasarilor este
(10+20)+(30+30)=90.
Atasam fiecarei strategii de interclasare cate un arbore binar in care valoarea fiecarui varf este data
de lungimea sirului pe care il reprezinta. Daca sirurile S1, S2, ..., S6 au lungimile q1 = 30, q2 = 10, q3 = 20,
q4 = 30, q5 = 50, q6 = 10, doua astfel de strategii de interclasare sunt reprezentate prin arborii din Figura
11.1.

Figura 11.1 Reprezentarea strategiilor de interclasare.


Observam ca fiecare arbore are 6 varfuri terminale, corespunzand celor 6 siruri initiale si 5 varfuri
neterminale, corespunzand celor 5 interclasari care definesc strategia respectiva. Numerotam varfurile in
97

felul urmator: varful terminal i, 1 i 6, va corespunde sirului Si, iar varfurile neterminale se
numeroteaza de la 7 la 11 in ordinea obtinerii interclasarilor respective (Figura 11.2).

Figura 11.2 Numerotarea varfurilor arborilor din Figura 11.1


Strategia greedy apare in Figura 11.1b si consta in a interclasa mereu cele mai scurte doua siruri
disponibile la momentul respectiv.
Interclasand sirurile S1, S2, ..., Sn, de lungimi q1, q2, ..., qn, obtinem pentru fiecare strategie cate un
arbore binar cu n varfuri terminale, numerotate de la 1 la n, si n1 varfuri neterminale, numerotate de la
n+1 la 2n1. Definim, pentru un arbore oarecare A de acest tip, lungimea externa ponderata:

unde ai este adancimea varfului i. Se observa ca numarul total de deplasari de elemente pentru strategia
corespunzatoare lui A este chiar L(A). Solutia optima a problemei noastre este atunci arborele (strategia)
pentru care lungimea externa ponderata este minima.
Proprietatea 11.1 Prin metoda greedy se obtine intotdeauna interclasarea optima a n siruri ordonate, deci
strategia cu arborele de lungime externa ponderata minima.
Demonstratie: Demonstram prin inductie. Pentru n = 1, proprietatea este verificata. Presupunem ca
proprietatea este adevarata pentru n1 siruri. Fie A arborele strategiei greedy de interclasare a n siruri de
lungime q1 q2 ... qn. Fie B un arbore cu lungimea externa ponderata minima, corespunzator unei
strategii optime de interclasare a celor n siruri. In arborele A apare subarborele

reprezentand prima interclasare facuta conform strategiei greedy. In arborele B, fie un varf neterminal de
adancime maxima. Cei doi fii ai acestui varf sunt atunci doua varfuri terminale qj si qk. Fie B' arborele
obtinut din B schimband intre ele varfurile q1 si qj, respectiv q2 si qk. Evident, L(B') L(B). Deoarece B
are lungimea externa ponderata minima, rezulta ca L(B') = L(B). Eliminand din B' varfurile q1 si q2,
obtinem un arbore B" cu n1 varfuri terminale q1+q2, q3, ..., qn. Arborele B' are lungimea externa
ponderata minima si L(B') = L(B") + q1+q2. Rezulta ca si B" are lungimea externa ponderata minima.
Atunci, conform ipotezei inductiei, avem L(B") = L(A'), unde A' este arborele strategiei greedy de
interclasare a sirurilor de lungime q1+q2, q3, ..., qn. Cum A se obtine din A' atasand la varful q1+q2 fiii q1 si
q2, iar B' se obtine in acelasi mod din B", rezulta ca L(A) = L(B') = L(B). Proprietatea este deci adevarata
pentru orice n.
98

La scrierea algoritmului care genereaza arborele strategiei greedy de interclasare vom folosi un
min-heap. Fiecare element al min-heap-ului este o pereche (q, i) unde i este numarul unui varf din
arborele strategiei de interclasare, iar q este lungimea sirului pe care il reprezinta. Proprietatea de minheap se refera la valoarea lui q.
Algoritmul interopt va construi arborele strategiei greedy. Un varf i al arborelui va fi memorat in
trei locatii diferite continand:
LU[i] = lungimea sirului reprezentat de varf
ST[i] = numarul fiului stang
DR[i] = numarul fiului drept
procedure interopt(Q[1 .. n])
{construieste arborele strategiei greedy de interclasare
a sirurilor de lungimi Q[i] = qi, 1 i n}
H min-heap vid
for i 1 to n do
(Q[i], i) => H
{insereaza in min-heap}
LU[i] Q[i]; ST[i] 0; DR[i] 0
for i n+1 to 2n1 do
(s, j) <= H
{extrage radacina lui H}
(r, k) <= H
{extrage radacina lui H}
ST[i] j; DR[i] k; LU[i] s+r
(LU[i], i) => H
{insereaza in min-heap}
In cazul cel mai nefavorabil, operatiile de inserare in min-heap si de extragere din min-heap
necesita un timp in ordinul lui log n. Restul operatiilor necesita un timp constant. Timpul total pentru
interopt este deci in O(n log n).
Coduri Huffman
O alta aplicatie a strategiei greedy si a arborilor binari cu lungime externa ponderata minima este
obtinerea unei codificari cat mai compacte a unui text.
Un principiu general de codificare a unui sir de caractere este urmatorul: se masoara frecventa de
aparitie a diferitelor caractere dintr-un esantion de text si se atribuie cele mai scurte coduri, celor mai
frecvente caractere, si cele mai lungi coduri, celor mai putin frecvente caractere. Acest principiu sta, de
exemplu, la baza codului Morse. Pentru situatia in care codificarea este binara, exista o metoda eleganta
pentru a obtine codul respectiv. Aceasta metoda, descoperita de Huffman (1952) foloseste o strategie
greedy si se numeste codificarea Huffman. O vom descrie pe baza unui exemplu.
Fie un text compus din urmatoarele litere (in paranteze figureaza frecventele lor de aparitie):
S (10), I (29), P (4), O (9), T (5)
Conform metodei greedy, construim un arbore binar fuzionand cele doua litere cu frecventele cele
mai mici. Valoarea fiecarui varf este data de frecventa pe care o reprezinta.

Etichetam muchia stanga cu 1 si muchia dreapta cu 0. Rearanjam tabelul de frecvente:


S (10), I (29), O (9), {P, T} (45 = 9)
Multimea {P, T} semnifica evenimentul reuniune a celor doua evenimente independente
corespunzatoare aparitiei literelor P si T. Continuam procesul, obtinand arborele
99

In final, ajungem la arborele din Figura 11.3, in care fiecare varf terminal corespunde unei litere
din text.
Pentru a obtine codificarea binara a literei P, nu avem decat sa scriem secventa de 0-uri si 1-uri in
ordinea aparitiei lor pe drumul de la radacina catre varful corespunzator lui P: 1011. Procedam similar si
pentru restul literelor:
S (11), I (0), P (1011), O (100), T (1010)
Pentru un text format din n litere care apar cu frecventele f1, f2, ..., fn, un arbore de codificare este
un arbore binar cu varfurile terminale avand valorile f1, f2, ..., fn, prin care se obtine o codificare binara a
textului. Un arbore de codificare nu trebuie in mod necesar sa fie construit dupa metoda greedy a lui
Huffman, alegerea varfurilor care sunt fuzionate la fiecare pas putandu-se face dupa diverse criterii.
Lungimea externa ponderata a unui arbore de codificare este:

Figura 11.3 Arborele de codificare Huffman.


unde ai este adincimea varfului terminal corespunzator literei i. Se observa ca lungimea externa ponderata
este egala cu numarul total de caractere din codificarea textului considerat. Codificarea cea mai compacta
a unui text corespunde deci arborelui de codificare de lungime externa ponderata minima. Se poate
demonstra ca arborele de codificare Huffman minimizeaza lungimea externa ponderata pentru toti arborii
de codificare cu varfurile terminale avand valorile f1, f2, ..., fn. Prin strategia greedy se obtine deci
intotdeauna codificarea binara cea mai compacta a unui text.
Arborii de codificare pe care i-am considerat in acesta sectiune corespund unei codificari de tip
special: codificarea unei litere nu este prefixul codificarii nici unei alte litere. O astfel de codificare este
de tip prefix. Codul Morse nu face parte din aceasta categorie. Codificarea cea mai compacta a unui sir de
caractere poate fi intotdeauna obtinuta printr-un cod de tip prefix. Deci, concentrandu-ne atentia asupra
acestei categorii de coduri, nu am pierdut nimic din generalitate.
11.4 Arbori pariali de cost minim
Fie G = <V, M> un graf neorientat conex, unde V este multimea varfurilor si M este multimea
muchiilor. Fiecare muchie are un cost nenegativ (sau o lungime nenegativa). Problema este sa gasim o
submultime A M, astfel incat toate varfurile din V sa ramina conectate atunci cand sunt folosite doar
muchii din A, iar suma lungimilor muchiilor din A sa fie cat mai mica. Cautam deci o submultime A de
cost total minim. Aceasta problema se mai numeste si problema conectarii oraselor cu cost minim, avand
numeroase aplicatii.
100

Graful partial <V, A> este un arbore si este numit arborele partial de cost minim al grafului G
(minimal spanning tree). Un graf poate avea mai multi arbori partiali de cost minim si acest lucru se poate
verifica pe un exemplu.
Vom prezenta doi algoritmi greedy care determina arborele partial de cost minim al unui graf. In
terminologia metodei greedy, vom spune ca o multime de muchii este o solutie, daca constituie un arbore
partial al grafului G, si este fezabila, daca nu contine cicluri. O multime fezabila de muchii este
promitatoare, daca poate fi completata pentru a forma solutia optima. O muchie atinge o multime data de
varfuri, daca exact un capat al muchiei este in multime. Urmatoarea proprietate va fi folosita pentru a
demonstra corectitudinea celor doi algoritmi.
Proprietatea 11.2 Fie G = <V, M> un graf neorientat conex in care fiecare muchie are un cost nenegativ.
Fie W V o submultime stricta a varfurilor lui G si fie A M o multime promitatoare de muchii, astfel
incat nici o muchie din A nu atinge W. Fie m muchia de cost minim care atinge W. Atunci, A {m} este
promitatoare.
Demonstratie: Fie B un arbore partial de cost minim al lui G, astfel incat A B (adica, muchiile din A
sunt continute in arborele B). Un astfel de B trebuie sa existe, deoarece A este promitatoare. Daca m B,
nu mai ramane nimic de demonstrat. Presupunem ca m B. Adaugandu-l pe m la B, obtinem exact un
ciclu. In acest ciclu, deoarece m atinge W, trebuie sa mai existe cel putin o muchie m' care atinge si ea pe
W (altfel, ciclul nu se inchide). Eliminandu-l pe m', ciclul dispare si obtinem un nou arbore partial B' al lui
G. Costul lui m este mai mic sau egal cu costul lui m', deci costul total al lui B' este mai mic sau egal cu
costul total al lui B. De aceea, B' este si el un arbore partial de cost minim al lui G, care include pe m.
Observam ca A B' deoarece muchia m', care atinge W, nu poate fi in A. Deci, A {m} este
promitatoare.
Multimea initiala a candidatilor este M. Cei doi algoritmi greedy aleg muchiile una cate una intr-o
anumita ordine, aceasta ordine fiind specifica fiecarui algoritm.
Algoritmul lui Kruskal
Arborele partial de cost minim poate fi construit muchie, cu muchie, dupa urmatoarea metoda a lui
Kruskal (1956): se alege intai muchia de cost minim, iar apoi se adauga repetat muchia de cost minim
nealeasa anterior si care nu formeaza cu precedentele un ciclu. Alegem astfel #V1 muchii. Este usor de
dedus ca obtinem in final un arbore. Este insa acesta chiar arborele partial de cost minim cautat?
Inainte de a raspunde la intrebare, sa consideram, de exemplu, graful din Figura 11.4a. Ordonam
crescator (in functie de cost) muchiile grafului: {1, 2}, {2, 3}, {4, 5}, {6, 7}, {1, 4}, {2, 5}, {4, 7}, {3, 5},
{2, 4}, {3, 6}, {5, 7}, {5, 6} si apoi aplicam algoritmul. Structura componentelor conexe este ilustrata,
pentru fiecare pas, in Tabelul 11.1.

Figura 11.4 Un graf si arborele sau partial de cost minim.


101

Pasul

Muchia considerata

initializare
1
2
3
4
5
6
7

{1, 2}
{2, 3}
{4, 5}
{6, 7}
{1, 4}
{2, 5}
{4, 7}

Componentele conexe ale


subgrafului <V, A>
{1}, {2}, {3}, {4}, {5}, {6}, {7}
{1, 2}, {3}, {4}, {5}, {6}, {7}
{1, 2, 3}, {4}, {5}, {6}, {7}
{1, 2, 3}, {4, 5}, {6}, {7}
{1, 2, 3}, {4, 5}, {6, 7}
{1, 2, 3, 4, 5}, {6, 7}
respinsa (formeaza ciclu)
{1, 2, 3, 4, 5, 6, 7}

Tabelul 11.1 Algoritmul lui Kruskal aplicat grafului din Figura 11.4a.
Multimea A este initial vida si se completeaza pe parcurs cu muchii acceptate (care nu formeaza
un ciclu cu muchiile deja existente in A). In final, multimea A va contine muchiile {1, 2}, {2, 3}, {4, 5},
{6, 7}, {1, 4}, {4, 7}. La fiecare pas, graful partial <V, A> formeaza o padure de componente conexe,
obtinuta din padurea precedenta unind doua componente. Fiecare componenta conexa este la randul ei un
arbore partial de cost minim pentru varfurile pe care le conecteaza. Initial, fiecare varf formeaza o
componenta conexa. La sfarsit, vom avea o singura componenta conexa, care este arborele partial de cost
minim cautat (Figura 11.4b).
Ceea ce am observat in acest caz particular este valabil si pentru cazul general, din Proprietatea
11.2 rezultand:
Proprietatea 11.3 In algoritmul lui Kruskal, la fiecare pas, graful partial <V, A> formeaza o padure de
componente conexe, in care fiecare componenta conexa este la randul ei un arbore partial de cost minim
pentru varfurile pe care le conecteaza. In final, se obtine arborele partial de cost minim al grafului G.
Pentru a implementa algoritmul, trebuie sa putem manipula submultimile formate din varfurile
componentelor conexe. Folosim pentru aceasta o structura de multimi disjuncte si procedurile de tip find
si merge. In acest caz, este preferabil sa reprezentam graful ca o lista de muchii cu costul asociat lor, astfel
incat sa putem ordona aceasta lista in functie de cost. Iata algoritmul:
function Kruskal(G = <V, M>)
{initializare}
sorteaza M crescator in functie de cost
n #V
A
{va contine muchiile arborelui partial de cost minim}
initializeaza n multimi disjuncte continand
fiecare cate un element din V
{bucla greedy}
repeat
{u, v} muchia de cost minim care
inca nu a fost considerate
ucomp find(u)
vcomp find(v)
if ucomp vcomp then merge(ucomp, vcomp)
A A {{u, v}}
until #A = n-1
return A

102

Pentru un graf cu n varfuri si m muchii, presupunand ca se folosesc procedurile find3 si merge3,


numarul de operatii pentru cazul cel mai nefavorabil este in:
O(m log m) pentru a sorta muchiile. Deoarece m n(n1)/2, rezulta O(m log m)
O(m log n). Mai mult, graful fiind conex, din n-1 m rezulta si O(m log n) O(m log m),
deci O(m log m) = O(m log n).
O(n) pentru a initializa cele n multimi disjuncte.
Cele cel mult 2m operatii find3 si n1 operatii merge3 necesita un timp in O((2m+n1) lg* n). Deoarece O(lg* n) O(log n) si n-1 m, acest timp este si in O(m log n).
O(m) pentru restul operatiilor.
Deci, pentru cazul cel mai nefavorabil, algoritmul lui Kruskal necesita un timp in O(m log n).
O alta varianta este sa pastram muchiile intr-un min-heap. Obtinem astfel un nou algoritm, in care
initializarea se face intr-un timp in O(m), iar fiecare din cele n1 extrageri ale unei muchii minime se face
intr-un timp in O(log m) = O(log n). Pentru cazul cel mai nefavorabil, ordinul timpului ramane acelasi cu
cel al vechiului algoritm. Avantajul folosirii min-heap-ului apare atunci cand arborele partial de cost
minim este gasit destul de repede si un numar considerabil de muchii raman netestate. In astfel de situatii,
algoritmul vechi pierde timp, sortand in mod inutil si aceste muchii.
Algoritmul lui Prim
Cel de-al doilea algoritm greedy pentru determinarea arborelui partial de cost minim al unui graf
se datoreaza lui Prim (1957). In acest algoritm, la fiecare pas, multimea A de muchii alese impreuna cu
multimea U a varfurilor pe care le conecteaza formeaza un arbore partial de cost minim pentru subgraful
<U, A> al lui G. Initial, multimea U a varfurilor acestui arbore contine un singur varf oarecare din V, care
va fi radacina, iar multimea A a muchiilor este vida. La fiecare pas, se alege o muchie de cost minim, care
se adauga la arborele precedent, dand nastere unui nou arbore partial de cost minim (deci, exact una dintre
extremitatile acestei muchii este un varf in arborele precedent). Arborele partial de cost minim creste
natural, cu cate o ramura, pina cand va atinge toate varfurile din V, adica pina cand U = V. Functionarea
algoritmului, pentru exemplul din Figura 11.4a, este ilustrata in Tabelul 11.2. La sfarsit, A va contine
aceleasi muchii ca si in cazul algoritmului lui Kruskal. Faptul ca algoritmul functioneaza intotdeauna
corect este exprimat de urmatoarea proprietate, pe care o puteti demonstra folosind Proprietatea 11.2.
Pasul
initializare
1
2
3
4
5
6

Muchia considerata

{2, 1}
{3, 2}
{4, 1}
{5, 4}
{7, 4}
{6, 7}

U
{1}
{1, 2}
{1, 2, 3}
{1, 2, 3, 4}
{1, 2, 3, 4, 5}
{1, 2, 3, 4, 5, 6}
{1, 2, 3, 4, 5, 6, 7}

Tabelul 11.2 Algoritmul lui Prim aplicat grafului din Figura 11.4a.
Proprietatea 11.4 In algoritmul lui Prim, la fiecare pas, <U, A> formeaza un arbore partial de cost minim
pentru subgraful <U, A> al lui G. In final, se obtine arborele partial de cost minim al grafului G.
Descrierea formala a algoritmului este data in continuare.
function Prim-formal(G = <V, M>)
{initializare}
A
{va contine muchiile arborelui partial de cost minim}
U {un varf oarecare din V}
{bucla greedy}
while U V do
103

gaseste {u, v} de cost minim astfel ca u V \ U si v U


A A {{u, v}}
U U {u}
return A
Pentru a obtine o implementare simpla, presupunem ca: varfurile din V sunt numerotate de la 1 la
n, V = {1, 2, ..., n}; matricea simetrica C da costul fiecarei muchii, cu C[i, j] = + , daca muchia {i, j} nu
exista. Folosim doua tablouri paralele. Pentru fiecare i V \ U, vecin[i] contine varful din U, care este
conectat de i printr-o muchie de cost minim; mincost[i] da acest cost. Pentru i U, punem mincost[i] =
1. Multimea U, in mod arbitrar initializata cu {1}, nu este reprezentata explicit. Elementele vecin[1] si
mincost[1] nu se folosesc.
function Prim(C[1 .. n, 1 .. n])
{initializare; numai varful 1 este in U}
A
for i 2 to n do vecin[i] 1
mincost[i] C[i, 1]
{bucla greedy}
repeat n1 times
min +
for j 2 to n do
if 0 < mincost[ j] < min then min mincost[ j]
kj

AA
{{k, vecin[k]}}
mincost[k] 1
{adauga varful k la U}
for j 2 to n do
if C[k, j] < mincost[ j] then mincost[ j] C[k, j]
vecin[ j] k
return A
Bucla principala se executa de n1 ori si, la fiecare iteratie, buclele for din interior necesita un
timp in O(n). Algoritmul Prim necesita, deci, un timp in O(n2). Am vazut ca timpul pentru algoritmul lui
Kruskal este in O(m log n), unde m = #M. Pentru un graf dens (adica, cu foarte multe muchii), se deduce
ca m se apropie de n(n1)/2. In acest caz, algoritmul Kruskal necesita un timp in O(n2 log n) si algoritmul
Prim este probabil mai bun. Pentru un graf rar (adica, cu un numar foarte mic de muchii), m se apropie de
n si algoritmul Kruskal necesita un timp in O(n log n), fiind probabil mai eficient decat algoritmul Prim.
11.5 Cele mai scurte drumuri care pleaca din acelasi punct
Fie G = <V, M> un graf orientat, unde V este multimea varfurilor si M este multimea muchiilor.
Fiecare muchie are o lungime nenegativa. Unul din varfuri este desemnat ca varf sursa. Problema este sa
determinam lungimea celui mai scurt drum de la sursa catre fiecare varf din graf.
Vom folosi un algoritm greedy, datorat lui Dijkstra (1959). Notam cu C multimea varfurilor
disponibile (candidatii) si cu S multimea varfurilor deja selectate. In fiecare moment, S contine acele
varfuri a caror distanta minima de la sursa este deja cunoscuta, in timp ce multimea C contine toate
celelalte varfuri. La inceput, S contine doar varful sursa, iar in final S contine toate varfurile grafului. La
fiecare pas, adaugam in S acel varf din C a carui distanta de la sursa este cea mai mica.
Spunem ca un drum de la sursa catre un alt varf este special, daca toate varfurile intermediare de-a
lungul drumului apartin lui S. Algoritmul lui Dijkstra lucreaza in felul urmator. La fiecare pas al
104

algoritmului, un tablou D contine lungimea celui mai scurt drum special catre fiecare varf al grafului.
Dupa ce adaugam un nou varf v la S, cel mai scurt drum special catre v va fi, de asemenea, cel mai scurt
dintre toate drumurile catre v. Cand algoritmul se termina, toate varfurile din graf sunt in S, deci toate
drumurile de la sursa catre celelalte varfuri sunt speciale si valorile din D reprezinta solutia problemei.
Presupunem, pentru simplificare, ca varfurile sunt numerotate, V = {1, 2, ..., n}, varful 1 fiind
sursa, si ca matricea L da lungimea fiecarei muchii, cu L[i, j] = + , daca muchia (i, j) nu exista. Solutia
se va construi in tabloul D[2 .. n]. Algoritmul este:
function Dijkstra(L[1 .. n, 1 .. n])
{initializare}
C {2, 3, ..., n}
{S = V \C exista doar implicit}
for i 2 to n do D[i] L[1, i]
{bucla greedy}
repeat n2 times
v varful din C care minimizeaza D[v]
C C \ {v}
{si, implicit, S S {v}}
for fiecare w C do
D[w] min(D[w], D[v]+L[v, w])
return D
Pentru graful din Figura 11.5, pasii algoritmului sunt prezentati in Tabelul 11.3.

Figura 11.5 Un graf orientat.


Pasul
initializare
1
2
3

5
4
3

C
{2, 3, 4, 5}
{2, 3, 4}
{2, 3}
{2}

D
[50, 30, 100, 10]
[50, 30, 20, 10]
[40, 30, 20, 10]
[35, 30, 20, 10]

Tabelul 11.3 Algoritmul lui Dijkstra aplicat grafului din Figura 11.5.
Observam ca D nu se schimba daca mai efectuam o iteratie pentru a-l scoate si pe {2} din C. De
aceea, bucla greedy se repeta de doar n-2 ori.
Se poate demonstra urmatoarea proprietate:
Proprietatea 11.5. In algoritmul lui Dijkstra, daca un varf i
i) este in S, atunci D[i] da lungimea celui mai scurt drum de la sursa catre i;
ii) nu este in S, atunci D[i] da lungimea celui mai scurt drum special de la sursa catre i.
La terminarea algoritmului, toate varfurile grafului, cu exceptia unuia, sunt in S. Din proprietatea
precedenta, rezulta ca algoritmul lui Dijkstra functioneaza corect.
105

Daca dorim sa aflam nu numai lungimea celor mai scurte drumuri, dar si pe unde trec ele, este
suficient sa adaugam un tablou P[2 .. n], unde P[v] contine numarul nodului care il precede pe v in cel
mai scurt drum. Pentru a gasi drumul complet, nu avem decat sa urmarim, in tabloul P, varfurile prin care
trece acest drum, de la destinatie la sursa. Modificarile in algoritm sunt simple:
initializeaza P[i] cu 1, pentru 2 i n
continutul buclei for cea mai interioara se inlocuieste cu
if D[w] > D[v] + L[v, w] then D[w] D[v] + L[v, w]
P[w] v
bucla repeat se executa de n -1 ori
Sa presupunem ca aplicam algoritmul Dijkstra asupra unui graf cu n varfuri si m muchii.
Initializarea necesita un timp in O(n). Alegerea lui v din bucla repeat presupune parcurgerea tuturor
varfurilor continute in C la iteratia respectiva, deci a n -1, n -2, ..., 2 varfuri, ceea ce necesita in total un
timp in O(n2). Bucla for interioara efectueaza n-2, n-3, ..., 1 iteratii, totalul fiind tot in O(n2). Rezulta ca
algoritmul Dijkstra necesita un timp in O(n2).
Incercam sa imbunatatim acest algoritm. Vom reprezenta graful nu sub forma matricii de adiacenta
L, ci sub forma a n liste de adiacenta, continand pentru fiecare varf lungimea muchiilor care pleaca din el.
Bucla for interioara devine astfel mai rapida, deoarece putem sa consideram doar varfurile w adiacente lui
v. Aceasta nu poate duce la modificarea ordinului timpului total al algoritmului, daca nu reusim sa scadem
si ordinul timpului necesar pentru alegerea lui v din bucla repeat. De aceea, vom tine varfurile v din C
intr-un min-heap, in care fiecare element este de forma (v, D[v]), proprietatea de min-heap referindu-se la
valoarea lui D[v]. Numim algoritmul astfel obtinut Dijkstra-modificat. Sa il analizam in cele ce urmeaza.
Initializarea min-heap-ului necesita un timp in O(n). Instructiunea C C \ {v} consta in
extragerea radacinii min-heap-ului si necesita un timp in O(log n). Pentru cele n2 extrageri este nevoie
de un timp in O(n log n).
Pentru a testa daca D[w] > D[v]+L[v, w], bucla for interioara consta acum in inspectarea
fiecarui varf w din C adiacent lui v. Fiecare varf v din C este introdus in S exact o data si cu acest prilej
sunt testate exact muchiile adiacente lui; rezulta ca numarul total de astfel de testari este de cel mult m.
Daca testul este adevarat, trebuie sa il modificam pe D[w] si sa operam un percolate cu w in min-heap,
ceea ce necesita din nou un timp in O(log n). Timpul total pentru operatiile percolate este deci in
O(m log n).
In concluzie, algoritmul Dijkstra-modificat necesita un timp in O(max(n, m) log n). Daca graful
este conex, atunci m n si timpul este in O(m log n). Pentru un graf rar este preferabil sa folosim
algoritmul Dijkstra-modificat, iar pentru un graf dens algoritmul Dijkstra este mai eficient.
Este usor de observat ca, intr-un graf G neorientat conex, muchiile celor mai scurte drumuri de la
un varf i la celelalte varfuri formeaza un arbore partial al celor mai scurte drumuri pentru G. Desigur,
acest arbore depinde de alegerea radacinii i si el difera, in general, de arborele partial de cost minim al lui
G.
Problema gasirii celor mai scurte drumuri care pleaca din acelasi punct se poate pune si in cazul
unui graf neorientat.
11.6 Euristica greedy
Pentru anumite probleme, se poate accepta utilizarea unor algoritmi despre care nu se stie daca
furnizeaza solutia optima, dar care furnizeaza rezultate acceptabile, sunt mai usor de implementat si
mai eficienti decat algoritmii care dau solutia optima. Un astfel de algoritm se numeste euristic.
Una din ideile frecvent utilizate in elaborarea algoritmilor euristici consta in descompunerea
procesului de cautare a solutiei optime in mai multe subprocese succesive, fiecare din aceste subprocese
constand dintr-o optimizare. O astfel de strategie nu poate conduce intotdeauna la o solutie optima,
deoarece alegerea unei solutii optime la o anumita etapa poate impiedica atingerea in final a unei solutii
optime a intregii probleme; cu alte cuvinte, optimizarea locala nu implica, in general, optimizarea globala.
106

Regasim, de fapt, principiul care sta la baza metodei greedy. Un algoritm greedy, despre care nu se poate
demonstra ca furnizeaza solutia optima, este un algoritm euristic.
Vom da doua exemple de utilizare a algoritmilor greedy euristici.
11.6.1 Colorarea unui graf
Fie G = <V, M> un graf neorientat, ale carui varfuri trebuie colorate astfel incat oricare doua
varfuri adiacente sa fie colorate diferit. Problema este de a obtine o colorare cu un numar minim de culori.
Folosim urmatorul algoritm greedy: alegem o culoare si un varf arbitrar de pornire, apoi consideram
varfurile ramase, incercand sa le coloram, fara a schimba culoarea. Cand nici un varf nu mai poate fi
colorat, schimbam culoarea si varful de start, repetand procedeul.

Figura 11.6 Un graf care va fi colorat.


Daca in graful din Figura 11.6 pornim cu varful 1 si il coloram in rosu, mai putem colora tot in
rosu varfurile 3 si 4. Apoi, schimbam culoarea si pornim cu varful 2, colorandu-l in albastru. Mai putem
colora cu albastru si varful 5. Deci, ne-au fost suficiente doua culori. Daca coloram varfurile in ordinea 1,
5, 2, 3, 4, atunci se obtine o colorare cu trei culori.
Rezulta ca, prin metoda greedy, nu obtinem decat o solutie euristica, care nu este in mod necesar
solutia optima a problemei. De ce suntem atunci interesati intr-o astfel de rezolvare? Toti algoritmii
cunoscuti, care rezolva optim aceasta problema, sunt exponentiali, deci, practic, nu pot fi folositi pentru
cazuri mari. Algoritmul greedy euristic propus furnizeaza doar o solutie acceptabila, dar este simplu si
eficient.
Un caz particular al problemei colorarii unui graf corespunde celebrei probleme a colorarii
hartilor: o harta oarecare trebuie colorata cu un numar minim de culori, astfel incat doua tari cu frontiera
comuna sa fie colorate diferit. Daca fiecarui varf ii corespunde o tara, iar doua varfuri adiacente
reprezinta tari cu frontiera comuna, atunci hartii ii corespunde un graf planar, adica un graf care poate fi
desenat in plan fara ca doua muchii sa se intersecteze. Celebritatea problemei consta in faptul ca, in toate
exemplele intalnite, colorarea s-a putut face cu cel mult 4 culori. Aceasta in timp ce, teoretic, se putea
demonstra ca pentru o harta oarecare este nevoie de cel mult 5 culori.
Problema colorarii unui graf poate fi interpretata si in contextul planificarii unor activitati. De
exemplu, sa presupunem ca dorim sa executam simultan o multime de activitati, in cadrul unor sali de
clasa. In acest caz, varfurile grafului reprezinta activitati, iar muchiile unesc activitatile incompatibile.
Numarul minim de culori necesare pentru a colora graful corespunde numarului minim de sali necesare.
11.6.2 Problema comis-voiajorului
Se cunosc distantele dintre mai multe orase. Un comis-voiajor pleaca dintr-un oras si doreste sa se
intoarca in acelasi oras, dupa ce a vizitat fiecare din celelalte orase exact o data. Problema este de a
minimiza lungimea drumului parcurs. Si pentru aceasta problema, toti algoritmii care gasesc solutia
optima sunt exponentiali.
Problema poate fi reprezentata printr-un graf neorientat, in care oricare doua varfuri diferite ale
grafului sunt unite intre ele printr-o muchie, de lungime nenegativa. Cautam un ciclu de lungime minima,
care sa se inchida in varful initial si care sa treaca prin toate varfurile grafului.
107

Conform strategiei greedy, vom construi ciclul pas cu pas, adaugand la fiecare iteratie cea mai
scurta muchie disponibila cu urmatoarele proprietati:
nu formeaza un ciclu cu muchiile deja selectate (exceptand pentru ultima muchie aleasa,
care completeaza ciclul)
nu exista inca doua muchii deja selectate, astfel incat cele trei muchii sa fie incidente in
acelasi varf
La: 2

De la:
1
3 10 11 7 25
2
6 12 8 26
3
9 4 20
4
5 15
5
18
Tabelul 11.4 Matricea distantelor pentru problema comis-voiajorului.
De exemplu, pentru sase orase a caror matrice a distantelor este data in Tabelul 11.4, muchiile se
aleg in ordinea: {1, 2}, {3, 5}, {4, 5}, {2, 3}, {4, 6}, {1, 6} si se obtine ciclul (1, 2, 3, 5, 4, 6, 1) de
lungime 58. Algoritmul greedy nu a gasit ciclul optim, deoarece ciclul (1, 2, 3, 6, 4, 5, 1) are lungimea 56.

108

CAPITOLUL XII
STUDII DE CAZ APLICAII

109

1. S se determine toate numerele perechile de numere gemene pana la o anumita valoare n. Dou
numere sunt gemene dac sunt ambele prime i diferena dintre cel mai mare i cel mai mic este 2.
Private Sub CommandButton1_Click()
Dim rad As Integer, n As Integer, p As Integer, i As Integer, j
As Integer
cit_n "n = ", n
For i = 3 To n
p = 1
rad = Int(Sqr(i + 2))
For j = 2 To Int(rad)
If i Mod j = 0 Or (i + 2) Mod j = 0 Then
prim = 0
j = Int(rad)
End If
Next
If p Then
MsgBox "(" + Str$(i) + "," + Str$(i + 2) + ")" + Chr(13)
End If
Next
End Sub

2. S se citeasc o valoare naturala n cu valori cuprinse intre 1 i 100.


Sub cit_n(mes As String, nnn As Integer)
Do
nnn = InputBox(mes, y)
Loop Until n > 0 And n < 100
End Sub

3. Citirea unui vector cu n componente


Sub cit_date(mes As String, n As Integer, a As vector)
For i = 1 To n
110

a.v(i) = InputBox(mes + "(" + Str$(i) + ")=", y)


Next
End Sub

4. Tiprirea unui tablou cu n componente


Sub tipar(mes
sir = ""
For i = 1 To
sir = sir +
Next
MsgBox mes +
End Sub

As String, n As Integer, a As vector)


n
Str$(a.v(i)) + ","
" " + sir

5. Generarea permutrilor utiliznd metoda backtracking


Private Sub CommandButton14_Click()
cit_n "n = ", n
back_perm
End Sub

6. Generarea produsului cartezian a n mulimi utiliznd metoda backtracking


Private Sub CommandButton16_Click()
Dim a As vector
cit_n "n=", n
cit_date "a", n, a
tipar " multimile sunt : ", n, a
back_prod_cart
End Sub

7. Generarea permutrilor utiliznd metoda backtracking


Private Sub CommandButton17_Click()
cit_n "n = ", n
cit_n "p = ", p
back_aranj
End Sub

8. Problema celor n dame utiliznd metoda backtracking


Private Sub CommandButton15_Click()
cit_n "n = ", n
back
End Sub

9. Generarea combinrilor (de n luate cte m) utiliznd metoda backtracking


Private Sub CommandButton18_Click()
cit_n "n = ", n
cit_n "p = ", p
back_comb
End Sub

10. Generarea partiiilor unei mulimi utiliznd metoda backtracking


Private Sub CommandButton19_Click()
111

cit_n "n=", n
back_partitii
End Sub

11. Cutarea binar utiliznd metoda Divide et Impera pentru sortarea unui ir de numere
Private Sub CommandButton2_Click()
Dim n As Integer, x As Integer, a As vector
cit_n "n = ", n
cit_date "a", n, a
tipar "sirul dat este : ", n, a
divimp 1, n, a
'MsgBox "Sirul a sortat este"
tipar "Sirul a sortat este", n, a
x = InputBox(" x = ", y)
st = 1
dr = n
l = True
While st <= dr And l = True
pp = (st + dr) / 2
If a.v(pp) = x Then
l = False
MsgBox "numarul x = " + Str$(x) + " se afla printre elementele
vectorului a"
End If
If a.v(pp) < x Then
st = pp + 1
Else
dr = p - 1
End If
Wend
If l = True Then
MsgBox "numarul x = " + Str$(x) + " nu se fala in sir "
End If
End Sub

12. Realizarea unei subrutine pentru sortarea rapid Quicksort


Sub sort(p As Integer, q As Integer, a As vector)
Dim m As Integer
If a.v(p) > a.v(q) Then
m = a.v(p)
a.v(p) = a.v(q)
a.v(q) = m
End If
End Sub

13. Sortarea Merge-Sort utiliznd metoda Divide et impera


Sub interc(p As Integer, q As Integer, m As Integer, a As vector)
Dim b As vector, i, j, k As Integer
i = p
j = m + 1
k = 1
While (i <= m) And (j <= q)
If a.v(i) <= a.v(j) Then
b.v(k) = a.v(i)
112

i = i + 1
k = k + 1
Else
b.v(k) = a.v(j)
j = j + 1
k = k + 1
End If
Wend
If i <= m Then
For j = i To m
b.v(k) = a.v(j)
k = k + 1
Next
Else
For i = j To q
b.v(k) = a.v(i)
k = k + 1
Next
End If
k = 1
For i = p To q
a.v(i) = b.v(k)
k = k + 1
Next
End Sub

14. Sortarea rapid utiliznd metoda Divide et impera


Sub divimp(p As Integer, q As Integer, a As vector)
Dim m As Integer
If (q - p) <= 1 Then
sort p, q, a
Else
m = Int((p + q) / 2)
divimp p, m, a
divimp m + 1, q, a
interc p, q, m, a
End If
End Sub

15. Problema colorrii hrilor utiliznd metoda backtracking


Private Sub CommandButton20_Click()
Dim mat As matrice
cit_n " n = ", n
cit_mat "a", n, n, mat
tipar_mat "a", n, n, mat
For i = 1 To n
For j = 1 To n
mat.m(j, i) = mat.m(i, j)
Next
Next
back_col
End Sub

113

16. Interclasarea a 2 iruri ordonate cresctor


Private Sub CommandButton3_Click()
Dim n As Integer, x As Integer, a As vector, m As Integer, b As
vector, k As Integer, c As vector
cit_n "n = ", n
cit_date "a", n, a
tipar "sirul dat este : ", n, a
divimp 1, n, a
'MsgBox "Sirul a sortat este"
tipar "Sirul a sortat este", n, a
cit_n "m = ", m
cit_date "a", m, b
tipar "sirul dat este : ", m, b
divimp 1, m, b
'MsgBox "Sirul a sortat este"
tipar "Sirul b sortat este", m, b
i = 1
j = 1
k = 0
While i <= n And j <= m
If a.v(i) < b.v(j) Then
k = k + 1
c.v(k) = a.v(i)
i = i + 1
Else
If a.v(i) = b.v(j) Then
k = k + 1
c.v(k) = a.v(i)
i = i + 1
j = j + 1
Else
k = k + 1
c.v(k) = b.v(j)
j = j + 1
End If
End If
Wend
If i <= n Then
For l = i To n
k = k + 1
c.v(k) = a.v(l)
Next
End If
If j <= m Then
For l = j To m
k = k + 1
c.v(k) = b.v(l)
Next
End If
tipar "A U B = ", k, c
End Sub

17. Sortarea Shell-Sort utiliznd metoda Greedy


Private Sub CommandButton4_Click()
Dim n As Integer, k As Integer, a As vector
114

cit_n "n = ", n


cit_date "a", n, a
tipar "sirul dat este : ", n, a
k = n
Do
k = k / 2
Do
b = 1
For i = 1 To n - k
If a.v(i) > a.v(i + k) Then
x = a.v(i)
a.v(i) = a.v(i + k)
a.v(i + k) = x
b = 0
End If
Next
Loop Until Not (b = 0)
Loop Until Not (k <> 1)
'MsgBox "Sirul a sortat este"
tipar "Sirul a sortat este", n, a
End Sub

18. Citirea si scrierea unei matrici pe ecran


Private Sub CommandButton5_Click()
Dim n As Integer, m As Integer, a As matrice, b As matrice, p As
Integer, c As matrice
cit_n "n = ", n
cit_n "m = ", m
cit_mat "a", n, m, a
tipar_mat "a", n, m, a
End Sub

19. Citirea unei matrici de pe dispozitivul de intrare


Sub cit_mat(mes As String, n As Integer, m As Integer, a As
matrice)
For i = 1 To n
For j = 1 To m
a.m(i, j) = InputBox(mes + "(" + Str$(i) + "," + Str$(j) +
")=", y)
Next
Next
End Sub

20. Scrierea unei matrici pe ecran


Sub tipar_mat(mes As String, n As Integer, m As Integer, a As
matrice)
sir = mes + Chr(10)
For i = 1 To n
For j = 1 To m
sir = sir + Str$(a.m(i, j)) + " "
Next
sir = sir + Chr(10)
Next
MsgBox sir
115

End Sub

21. Produsul a dou matrici


Private Sub CommandButton6_Click()
Dim n As Integer, m As Integer, a As matrice, b As matrice, p As
Integer, c As matrice
cit_n "n = ", n
cit_n "m = ", m
cit_mat "a", n, m, a
tipar_mat "a", n, m, a
cit_n "p = ", p
'cit_n "m = ", m
cit_mat "b", m, p, b
tipar_mat "m", m, p, b
prod_mat n, m, p, a, b, c
tipar_mat "axb=", n, p, c
End Sub
Sub prod_mat(n As Integer, m As Integer, p As Integer, a As
matrice, b As matrice, c As matrice)
For i = 1 To n
For j = 1 To p
c.m(i, j) = 0
For k = 1 To m
c.m(i, j) = c.m(i, j) + a.m(i, k) * b.m(k, j)
Next
Next
Next
End Sub

22. Programul principal pentru adunarea a dou matrici


Private Sub CommandButton7_Click()
Dim n As Integer, m As Integer, a As matrice, b As matrice, p As
Integer, c As matrice
cit_n "n = ", n
cit_n "m = ", m
cit_mat "a", n, m, a
tipar_mat "a", n, m, a
'cit_n "p = ", p
'cit_n "m = ", m
cit_mat "b", n, m, b
tipar_mat "b", n, m, b
ad_mat n, m, a, b, c
tipar_mat "a+b=", n, m, c
End Sub

23. Subrutina pentru adunarea a dou matrici


Sub ad_mat(n As Integer, m As Integer, a As matrice, b As matrice,
c As matrice)
For i = 1 To n
For j = 1 To m
c.m(i, j) = a.m(i, j) + b.m(i, j)
Next
Next
116

End Sub

24. Programul principal pentru scderea a dou matrici


Private Sub CommandButton8_Click()
Dim n As Integer, m As Integer, a As matrice, b As matrice, p As
Integer, c As matrice
cit_n "n = ", n
cit_n "m = ", m
cit_mat "a", n, m, a
tipar_mat "a", n, m, a
'cit_n "p = ", p
'cit_n "m = ", m
cit_mat "b", n, m, b
tipar_mat "b", n, m, b
scad_mat n, m, a, b, c
tipar_mat "a-b=", n, m, c
End Sub

25. Subrutina pentru adunarea a dou matrici


Sub scad_mat(n As Integer, m As Integer, a As matrice, b As
matrice, c As matrice)
For i = 1 To n
For j = 1 To m
c.m(i, j) = a.m(i, j) - b.m(i, j)
Next
Next
End Sub

26. Programul principal pentru ridicarea unei matrici la o putere p


Private Sub CommandButton9_Click()
Dim n As Integer, m As Integer, a As matrice, b As matrice, p As
Integer, c As matrice, k As Integer
'Sub scad_mat(n As Integer, m As Integer, a As matrice, b As
matrice, c As matrice)
'const t as vector ={0,31,28,31,30,31,30,31,30,31,30,31,30}
cit_n "n = ", n
'cit_n "m = ", m
cit_mat "a", n, n, a
tipar_mat "a", n, n, a
cit_n "putere = ", k
'cit_n "m = ", m
'cit_mat "b", n, m, b
'tipar_mat "b", n, m, b
putere_mat n, a, k, c
tipar_mat "a^p=", n, n, c
End Sub

27. Subprogramul pentru ridicarea unei matrici la o putere p


Sub putere_mat(n As Integer, a As matrice, k As Integer, c As
matrice)
Dim b As matrice, c1 As matrice
For i = 1 To n
For j = 1 To n
117

c.m(i, j) = 0
c1.m(i, j) = 0
Next
Next
For i = 1 To n
c.m(i, i) = 1
c1.m(i, i) = 1
Next
'Next
While k > 0
If k Mod 2 = 1 Then
prod_mat n, n, n, c1, a, c
End If
For i = 1 To n
For j = 1 To n
c1.m(i, j) = c.m(i, j)
'c1.m(i, j) = 0
Next
Next
prod_mat n, n, n, a, a, b
k = Int(k / 2)
For i = 1 To n
For j = 1 To n
a.m(i, j) = b.m(i, j)
'c1.m(i, j) = 0
Next
Next
Wend
For i = 1 To n
For j = 1 To n
c.m(i, j) = c1.m(i, j)
'c1.m(i, j) = 0
Next
Next
End Sub

28. Subrutina de iniializare a stivei pentru metoda backtracking


Sub init(k As Integer, st As stiva)
st.ss(k) = 0
End Sub

29. Subrutina successor pentru problema celor n dame


Sub succesor(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

30. Subrutina successor pentru generarea combinrilor


Sub succesor_c(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n - p + k Then
118

am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

31. Subrutina succesor pentru problema produsului cartezian a n mulimi utiliznd metoda
backtracking
Sub succesor_prod(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < a.v(k) Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

32. Subrutina successor pentru colorarea hrilor


Sub succesor_col(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < 4 Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

33. Subrutina valid pentru problema celor n dame


Sub valid(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Or (Abs(st.ss(i) - st.ss(k)) = Abs(k i)) Then
ev = False
End If
Next
End Sub

34. Subrutina valid pentru colorarea hrilor


Sub valid_col(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) And (mat.m(i, k) = 1) Then
ev = False
End If
Next
End Sub
Sub valid_c(ev As Boolean, st As stiva, k As Integer)
Dim i As Integer
ev = True
For i = 1 To k - 1
119

If (st.ss(i) = st.ss(k)) Then


ev = False
End If
Next
If k > 1 Then
If st.ss(k) < st.ss(k - 1) Then
ev = False
End If
End If
End Sub

35. Subrutina valid pentru produs cartezian a n mulimi


Sub valid_prod(ev As Boolean, st As stiva, k As Integer)
ev = True
End Sub

36. Subrutina soluie pentru generarea permutrilor


Function solutie(k As Integer) As Boolean
If k = n Then
solutie = True
Else
solutie = False
End If
End Function

37. Subrutina soluie pentru generarea aranjamentelor sau combinrilor


Function solutie1(k As Integer) As Boolean
If k = p Then
solutie1 = True
Else
solutie1 = False
End If
End Function

38. Subrutina tiprire pentru problema celor n dame


Sub tiparr()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "(" + Str$(i) + "," + Str$(st.ss(i)) + "),"
Next
MsgBox b
End Sub

39. Subrutina tiprire pentru colorarea hrilor


Sub tipar_col()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "Tara = " + Str$(i) + "; culoarea " + Str$(st.ss(i)) + " "
Next
120

MsgBox b
End Sub

40. Subrutina back pentru problema celor n dame


Sub back()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tiparr
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub

41. Programul principal pentru problema celor n dame


Sub Button2_Click()
n = InputBox("n=", ib_title)
back
End Sub

42. Subrutina back pentru generarea permutrilor


Sub back_perm()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid1 ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_r
Else
k = k + 1
init k, st
End If
Else
121

k = k - 1
End If
Wend
End Sub

43. Subrutina back pentru generarea aranjamentelor


Sub back_aranj()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid1 ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie1(k) Then
tipar_rr
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub

44. Subrutina valid pentru metoda backtracking


Sub valid1(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Then
ev = False
End If
Next
End Sub

45. Subrutina tipar pentru metoda backtracking


Sub tipar_r()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + Str$(st.ss(i)) + ","
Next
MsgBox b
End Sub

46. Subrutina tipar pentru metoda backtracking


Sub tipar_rr()
Dim i As Integer, b As String
122

b = " "
For i = 1 To p
b = b + Str$(st.ss(i)) + ","
Next
MsgBox b
End Sub

47. Subrutina back pentru generarea combinrilor


Sub back_comb()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_c am_suc, st, k
If am_suc = True Then
valid_c ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie1(k) Then
tipar_rr
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub

48. Subrutina back pentru generarea produsului cartezian a n multimi


Sub back_prod_cart()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_prod am_suc, st, k
If am_suc = True Then
valid_prod ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_r
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
123

End Sub

49. Subrutina back pentru generarea partiiilor unei mulimi


Sub back_partitii()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_part am_suc, st, k
If am_suc = True Then
valid_prod ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_part
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub

50. Subrutina tiparire pentru problema generare partiii a unei mulimi


Sub tipar_part()
Dim i As Integer, max As Integer, j As Integer, sir As String
sir = ""
max = st.ss(1)
For i = 2 To n
If max < st.ss(i) Then
max = st.ss(i)
End If
Next
sir = "
PARTITII
"
For j = 1 To max
For i = 1 To n
If st.ss(i) = j Then
sir = sir + Str$(i) + " "
End If
Next
sir = sir + Chr(10)
Next
MsgBox sir
End Sub

51. Subrutina succesor pentru problema generare partiii a unei mulimi


Sub succesor_part(am_suc As Boolean, st As stiva, k As Integer)
Dim i As Integer, max As Integer
If k = 1 Then
max = 1
124

Else
max = st.ss(1)
For i = 2 To k - 1
If max < st.ss(i) Then
max = st.ss(i)
End If
Next
End If
If st.ss(k) < max + 1 And st.ss(k) < k Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub

52. Subrutina back pentru colorarea hrilor


Sub back_col()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor_col am_suc, st, k
If am_suc = True Then
valid_col ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_col
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
Public s As String

53. Funcia pentru a verifica dac un numr natural n este prim sau nu
Function prim(n As Integer) As Boolean
b = True
For i = 2 To Int(Sqr(n))
If n Mod i = 0 Then
b = False
i = Int(Sqr(n))
End If
Next
prim = b
End Function

54. Programul principal pentru inversarea unui numr natural n


125

Sub buton1_Click()
Dim n As Integer, ninv As Integer, n1 As Integer, sir As String
Do
n = InputBox(" n = ", y)
Loop Until n > 0
n1 = n
ninv = 0
sir = ""
While n <> 0
sir = sir + LTrim(RTrim(Str$(n Mod 10)))
ninv = ninv * 10 + n Mod 10
n = Int(n / 10)
Wend
MsgBox " numarul initial este : " + Str$(n1) + " numarul inversat
este: " + sir
End Sub

55. Algoritmul lui Euclid pentru calcularea CMMDC a dou numere naturale pozitive
Private Sub Buton10_Click()
Dim a As Integer, b As Integer, c As Integer
Do
a = InputBox("a = ", y)
b = InputBox("b = ", y)
a1 = a
b1 = b
Loop Until a > 0 And b > 0 And a > b
c = euclid2(a, b)
If c = 1 Then
MsgBox " nr. sunt prime intre ele (" + Str$(a1) + "," + Str$(b1)
+ ")"
Else
MsgBox "Cmmdc (" + Str$(a1) + "," + Str$(b1) + ")=" + Str$
(euclid2(a, b))
End If
End Sub

56. Sortarea unui sir cu n componente utiliznd metoda bulelor


Private Sub Buton11_Click()
Dim n As Integer, a As vector
cit_n "n = ", n
cit_date "a", n, a
tipar "vectorul initial a este ", n, a
bule n, a
tipar "vectorul a sortat este : ", n, a
End Sub

57. Subrutina pentru sortarea prin metoda bulelor


Sub bule(n As Integer, a As vector)
Do
k = 0
For i = 1 To n - 1
If a.v(i) > a.v(i + 1) Then
x = a.v(i)
126

a.v(i) = a.v(i + 1)
a.v(i + 1) = x
k = 1
End If
Next
Loop Until k = 0
End Sub

58. Sortarea unui sir cu n componente utiliznd metoda seleciei directe


Private Sub Buton12_Click()
Dim n As Integer, a As vector
cit_n "n = ", n
cit_date "a", n, a
tipar "vectorul initial a este ", n, a
selectie n, a
tipar "vectorul a sortat este : ", n, a
End Sub

59. Subrutina pentru sortarea prin metoda seleciei directe


Sub selectie(n As Integer, a As vector)
For i = 1 To n - 1
min = a.v(i)
k = i
For j = i + 1 To n
If min > a.v(j) Then
min = a.v(j)
k = j
End If
Next
If k <> i Then
x = a.v(i)
a.v(i) = a.v(k)
a.v(k) = x
End If
Next
End Sub

60. Sortarea unui sir cu n componente utiliznd metoda prin numrare


Private Sub Buton14_Click()
Dim n As Integer, a As vector
cit_n "n = ", n
cit_date "a", n, a
tipar "vectorul initial a este ", n, a
numarare n, a
tipar "vectorul a sortat este : ", n, a
End Sub

61. Suma cifrelor unui numr natural dat n


Sub buton2_Click()
Dim n As Integer, s As Long, n1 As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
127

n1 = n
s = 0
While n <> 0
s = s + n Mod 10
n = Int(n / 10)
Wend
MsgBox " suma cifrelor numarului n = " + Str$(n1) + " este : " +
Str$(s)
End Sub

62. Verificarea unui numar natural n daca este prim sau nu


Sub buton3_Click()
Dim n As Integer, s As Long, n1 As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
n1 = n
b = True
For i = 2 To Int(Sqr(n))
If n Mod i = 0 Then
b = False
i = Int(Sqr(n))
End If
Next
If b = True Then
MsgBox "numarul n = " + Str$(n) + " este prim"
Else
MsgBox "numarul n = " + Str$(n) + " nu este prim"
End If
End Sub

63. Determinarea numerelor prime mai mici sau egale cu n utiliznd metoda direct
Sub buton4_Click()
Dim n As Integer, s As Long, n1 As Integer, i As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
n1 = n
If n = 2 Then
MsgBox "numerele prime sunt : 2"
Else
sir = "2,"
i = 3
While i <= n
If prim(i) = True Then
sir = sir + Str$(i) + ","
End If
i = i + 2
Wend
End If
MsgBox "numere prime sunt : " + sir
End Sub

64. Ciurul lui Eratostene


128

Sub buton5_Click()
Dim n As Integer, a As vector, sir As String
Do
n = InputBox(" n = ", y)
Loop Until n > 0
For i = 1 To n
a.v(i) = i
Next
For i = 2 To Int(Sqr(n))
If a.v(i) <> 0 Then
j = 2 * i
While j <= n
j = j + i
a.v(j) = 0
Wend
End If
Next
sir = ""
For i = 2 To n
If a.v(i) <> 0 Then
sir = sir + Str$(i) + ","
End If
Next
MsgBox "Numerele prime sunt : " + sir
End Sub

65. Descompunerea unui numar in factori primi


Sub buton6_Click()
Dim n As Integer, a As vector, sir As String, n1 As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
i = 2
n1 = n
l = 0
sir = ""
Do
fm = 0
While n Mod i = 0
fm = fm + 1
l = 1
n = Int(n / i)
Wend
If fm <> 0 Then
sir = sir + Str$(i) + "^" + Str$(fm) + "*"
End If
i = i + 1
Loop Until n = 1
If l = 0 Then
sir = Str$(n) + "^1"
End If
MsgBox Str$(n1) + "=" + sir
End Sub

66. Scrierea unui numr ca suma a dou cuburi


129

Sub buton7_Click()
Dim n As Integer, a As vector, sir As String, n1 As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
n1 = n
For n = 1 To n1
Max = Int(n / 2)
nr = 0
For i = 1 To Max
For j = i To Max
If i * i * i + j * j * j = n Then
If nr = 0 Then
i1 = i
j1 = j
Else
i2 = i
j2 = j
End If
nr = nr + 1
End If
Next
Next
If nr > 1 Then
MsgBox Str$(n) + "=" + Str$(i1) + "^" + Str$(j1) + "+" + Str$
(i2) + "^" + Str$(j2)
End If
Next
End Sub

67. CMMDC a dou numere utiliznd recursivitatea


Sub buton8_Click()
Dim a As Integer, b As Integer, c As Integer
Do
a = InputBox("a = ", y)
b = InputBox("b = ", y)
a1 = a
b1 = b
Loop Until a > 0 And b > 0 And a > b
c = euclid(a, b)
If c = 1 Then
MsgBox " nr. sunt prime intre ele (" + Str$(a1) + "," + Str$(b1)
+ ")"
Else
MsgBox "Cmmdc (" + Str$(a1) + "," + Str$(b1) + ")=" + Str$
(euclid(a, b))
End If
End Sub

68. Funcia euclid


Function euclid(a As Integer, b As Integer) As Integer
Dim r As Integer
Do
r = a Mod b
MsgBox r
130

a = b
b = r
Loop Until Not (r = 0 And r = 1)
If r = 1 Then
euclid = 1
Else
euclid = a
End If
End Function

69. CMMDC a dou numere utiliznd scderi repetate


Private Sub Buton9_Click()
Dim a As Integer, b As Integer, c As Integer
Do
a = InputBox("a = ", y)
b = InputBox("b = ", y)
a1 = a
b1 = b
Loop Until a > 0 And b > 0 And a > b
c = euclid1(a, b)
If c = 1 Then
MsgBox " nr. sunt prime intre ele (" + Str$(a1) + "," + Str$(b1)
+ ")"
Else
MsgBox "Cmmdc (" + Str$(a1) + "," + Str$(b1) + ")=" + Str$
(euclid1(a, b))
End If
End Sub

70. Funcia Euclid utiliznd scderi repetate


Function euclid1(a As Integer, b As Integer) As Integer
If a > b Then
euclid1 = euclid1(a - b, b)
Else
If a < b Then
euclid1 = euclid1(a, b - a)
Else
euclid1 = a
End If
End If
End Function

71. Funcia Euclid utiliznd scderi repetate


Function euclid2(a As Integer, b As Integer) As Integer
If b = 0 Then
euclid2 = a
Else
euclid2 = euclid2(b, a Mod b)
End If
End Function

72. x ^ y utiliznd un numr minim de nmuliri


131

Sub Button15_Click()
Dim x As Integer, y As Integer, z As Integer, t As String, bb As
vector
Dim xx As Integer
Do
x = InputBox("a=", ib_title)
y = InputBox("b=", ib_title)
Loop Until (x > 0) And (y > 0) And (x >= y)
baza1 x, y, bb, xx
t = ""
MsgBox "n = " + Str$(xx)
For z = xx To 1 Step -1
t = t + Str$(bb.v(z))
Next
MsgBox t
End Sub

73. Verific dac un numr natural este palindrome sau nu


Sub Button16_Click()
Dim n As Long, m As Long
Do
n = InputBox("n=", ib_title)
Loop Until (n > 0)
m = n
If palindrom(n) = True Then
MsgBox "n=" + Str$(m) + " este plaindrom"
Else
MsgBox "n=" + Str$(m) + " nu este plaindrom"
End If
End Sub

74. Baza la exponent


Sub Button17_Click()
Dim x As Double, y As Byte, z As Double, t As Byte
Do
x = InputBox("baza=", ib_title)
y = InputBox("exponent=", ib_title)
Loop Until (x > 0) And (y > 0)
z = putere(x, y, t)
MsgBox Str$(z) + " " + Str$(t - 1)
End Sub

75. Quicksort
Sub Button18_Click()
Dim n As Integer, a As vector
cit_n "n = ", n
cit_date "a", n, a
'MsgBox "Sirul a este"
tipar "Sirul a este", n, a
divimp 1, n, a
'MsgBox "Sirul a sortat este"
tipar "Sirul a sortat este", n, a
End Sub
132

76. Minimul dintr-un ir de numere utiliznd divide et impera


Sub Button19_Click()
Dim n As Integer, a As vector
cit_n "n=", n
cit_date "a", n, a
'MsgBox "Sirul a este"
tipar "sirul dat este ", n, a
MsgBox "minimul in Sirul a este" + Str$(minim(1, n))
End Sub

77. Turnurile din Hanoi


Sub Button20_Click()
Dim n As Integer, a As sir, b As sir, c As sir
d = ""
a.s = "A"
b.s = "B"
c.s = "C"
n = InputBox("n=", ib_title)
hanoi n, a, b, c
MsgBox d
End Sub

78. Subrutina Hanoi


Sub hanoi(n As Integer, a As sir, b As sir, c As sir)
If n = 1 Then
d = d + "(" + a.s + "->" + b.s + "),"
Else
hanoi n - 1, a, c, b
d = d + "(" + a.s + "->" + b.s + "),"
hanoi n - 1, c, b, a
End If
End Sub

79. Subrutina back pentru permutri


Sub back_perm()
Dim k As Integer
k = 1
init k, st
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid1 ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar_r
Else
k = k + 1
init k, st
End If
Else
133

k = k - 1
End If
Wend
End Sub

80. Calculul sumei 1-1,1-1-1,.,1-1-1-1-1-1-1.-1


Private Sub Buttton3_Click()
Dim n As Integer, ss As String
cit_n "n = ", n
ss = ""
i = 0
j = 1
While (i < n)
ss = ss + " 1"
i = i + 1
k = 1
While k <= j And i < n
ss = ss + " -1"
i = i + 1
k = k + 1
Wend
j = j + 1
Wend
MsgBox ss
End Sub

134

Bibliografie
[1.] Brassard, G., Bratley, P. Algorithmics - Theory and Practice, Prentice-Hall, Englewood Cliffs,
1988.
[2.] Cormen, T.H., Leiserson, C.E., Rivest, R.L. Introduction to Algorithms, The MIT Press,
Cambridge, Masshusetts, 1992 (eighth printing).
[3.] Ellis, M., Stroustrup, B. The Annotated C++ Reference Manual, Addison-Wesley, Reading,
1991.
[4.] Graham, R.L., Knuth, D.E., Patashnik, O. Concrete Mathematics, Addison-Wesley, Reading,
1989.
[5.] Horowitz, E., Sahni, S. Fundamentals of Computer Algorithms, Computer Science Press,
Rockville, 1978.
[6.] Knuth, D.E. Tratat de programarea calculatoarelor. Algoritmi fundamentali, Editura Tehnica,
Bucuresti, 1974.
[7.] Knuth, D.E. Tratat de programarea calculatoarelor. Sortare si cautare, Editura Tehnica,
Bucuresti, 1976.
[8.] Lippman, S. B. C++ Primer, Addison-Wesley, Reading, 1989.
[9.] Livovschi, L., Georgescu, H. Sinteza si analiza algoritmilor, Editura Stiintifica si Enciclopedica,
Bucuresti, 1986.
[10.] Morariu N, Limbaje de programare, curs ID,2003
[11.] Sedgewick, R. Algorithms, Addison-Wesley, Reading, 1988.
[12.] Sedgewick, R. Algorithms in C, Addison-Wesley, Reading, 1990.
[13.] Sethi, R. Programming Languages. Concepts and Constructs, Addison-Wesley, Reading, 1989.
[14.] Smith, J.H. Design and Analysis of Algorithms, PWS-KENT Publishing Company, Boston, 1989.
[15.] Standish, T.A. Data Structure Techniques, Addison-Wesley, Reading, 1979.
[16.] Stroustrup, B. The C++ Programming Language, Addison-Wesley, Reading, 1991.
[17.] Stroustrup, B. The Design and Evolution of C++, Addison-Wesley, Reading, 1994.
[18.] http://thor.info.uaic.ro/~dlucanu/

135

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