Documente Academic
Documente Profesional
Documente Cultură
Algoritmi
Algoritmi
ALGORITMI. TEHNICI I
LIMBAJE DE PROGRAMARE
3
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
4
Cuprins
Bibliografie ....................................................................................................................................135
5
CAPITOLUL I
DESCRIEREA ALGORITMILOR
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).
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.
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.
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.
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.
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.
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.
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.
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
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
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
19
DAC ind=0 ATUNCI k:=k+1; rk:=bj SFDAC
SFPENTRU
SF-REUNIUNE
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.
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
22
CAPITOLUL III
METODE DE PROIECTARE A 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.
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 printr-
o 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.
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.
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
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 le-
a 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.
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.
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.
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
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.
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).
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
sfdac
35
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
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
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.
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
ordonarea unui subir se poate rezolva elementar fr a mai fi necesar desprirea lui n alte dou
subiruri (lungimea subirului este cel mult 2).
37
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.
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:
sortarea echilibrat;
sortarea polifazic;
39
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).
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.
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.).
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 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.
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.
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.
49
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.
50
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.
51
limbaj de programare evoluat (PAL Paradox Application Language), dotat cu
compilator.
52
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.
GENERAII DE CALCULATOARE
Generaia I (1946-1956) caracterizat prin:
53
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
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:
56
Obiect Prefix Exemplu
Bare de derulare
- orizontal hsb
- vertical vsb
Meniu Mnu mnuMeniuPrinc
Caset de validare Chk
Caset cu lista Lst
Cadru Fra
Imagine Img
Buton de opiune (radio) Opt optBO1
Generaliti
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
- Scderea sau operanzii pot fi doar numerici. Rezultatul este de tipul cel
inversarea "mai precis" al operanzilor, ordinea de "precizie" fiind pentru
semnului 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 negaia logic Not Null este Null. Prin operatorul Not se poate inversa bit
cu bit valorile unei variabile, poziionndu-se
corespunztor un rezultat numeric.
Or 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.
Xor disjuncia Dac un operand este Null, atunci rezultatul este Null. Se
exclusiv 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.
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.
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.
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
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).
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.
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.
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.
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.
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.
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 formali-
actuali.
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.
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.
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 bottom-
up 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.
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.
12. Folosete variabile auxiliare numai acolo unde este strict necesar.
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.
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.
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 2 3
1 2 2 2 2
1 1 1 1 1 1
1 2 3
3 3 3 3 1
1 1 1 1 2 2
1 2 3 1
1 1 1 2 3 3
2 2 2 2 2 2
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
End Sub
74
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
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:
B
A
introducem n stiv litera B, deci k va lua valoarea 2;
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.
Prezentarea tehnicii Backtracking
75
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:
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, xn, 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).
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
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).
3 ST(4)
1 ST(3)
4 ST(2)
2 ST(1)
sau situaia
D st(1) = 3 i = 1
D st(3) = 1 j = 3
|st(i) - st(j)| = |3 1| = 2
D
|i j| = |1 3| = 2
D
79
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:
80
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
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
Produsul cartezian a n mulimi. Se dau mulimile de mai jos i se cere produsul cartezian al lor.
81
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 2 3 1
1 1 1 2 2
1 1 1 1 1 1
2 3 1 2 3
2 2 3 3 3 3
1 1 1 1 1 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.
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
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.
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 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
If k = p Then
solutie1 = True
Else
solutie1 = False
End If
End Function
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
85
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 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
Exemplu: n figura alturat sunt simbolizate cele 6 orae, precum i drumurile existente ntre ele.
86
2 3
1 4
6 5
2
De la oraul 1 la oraul 2 exist drum, deci se va urca n stiv;
1
2
2 Oraul 2 se mai gsete n stiv, deci nu este acceptat;
1
3
De la oraul 2 la oraul 3 se gsete drum; prin oraul 3 nu s-a mai trecut, deci
2
oraul 3 este acceptat.
1
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 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
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:
3
2
5
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 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
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.
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 .
94
CAPITOLUL XI
METODA 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.
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)
{C este multimea candidatilor}
S {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.
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 T
1 2 3 5+(5+10)+(5+10+3) = 38
1 3 2 5+(5+3)+(5+3+10) = 31
2 1 3 10+(10+5)+(10+5+3) = 43
2 3 1 10+(10+3)+(10+3+5) = 41
3 1 2 3+(3+5)+(3+5+10) = 29 optim
3 2 1 3+(3+10)+(3+10+5) = 34
96
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
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).
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.
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 min-
heap 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
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.
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:
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.
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.
101
subgrafului <V, A>
initializare {1}, {2}, {3}, {4}, {5}, {6}, {7}
1 {1, 2} {1, 2}, {3}, {4}, {5}, {6}, {7}
2 {2, 3} {1, 2, 3}, {4}, {5}, {6}, {7}
3 {4, 5} {1, 2, 3}, {4, 5}, {6}, {7}
4 {6, 7} {1, 2, 3}, {4, 5}, {6, 7}
5 {1, 4} {1, 2, 3, 4, 5}, {6, 7}
6 {2, 5} respinsa (formeaza ciclu)
7 {4, 7} {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:
{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+n-
1) 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.
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.
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.
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:
Pentru graful din Figura 11.5, pasii algoritmului sunt prezentati in Tabelul 11.3.
Pasul v C D
initializare {2, 3, 4, 5} [50, 30, 100, 10]
1 5 {2, 3, 4} [50, 30, 20, 10]
2 4 {2, 3} [40, 30, 20, 10]
3 3 {2} [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:
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.
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.
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.
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.
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 3 4 5 6
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.
End Sub
111
Private Sub CommandButton19_Click()
cit_n "n=", n
back_partitii
End Sub
11. Cutarea binar utiliznd metoda Divide et Impera pentru sortarea unui ir de numere
112
While (i <= m) And (j <= q)
If a.v(i) <= a.v(j) Then
b.v(k) = a.v(i)
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
115
Next
sir = sir + Chr(10)
Next
MsgBox sir
End Sub
116
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
117
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
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
31. Subrutina succesor pentru problema produsului cartezian a n mulimi utiliznd metoda
backtracking
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
120
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
MsgBox b
End Sub
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
Sub Button2_Click()
n = InputBox("n=", ib_title)
back
End Sub
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
121
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 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 tipar_r()
Dim i As Integer, b As String
b = " "
For i = 1 To n
122
b = b + 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
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
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
123
tipar_r
Else
k = k + 1
init k, st
End If
Else
k = k - 1
End If
Wend
End Sub
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
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
124
MsgBox sir
End Sub
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
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
127
tipar "vectorul a sortat este : ", n, a
End Sub
Sub buton2_Click()
Dim n As Integer, s As Long, n1 As Integer
Do
n = InputBox(" n = ", y)
Loop Until n > 0
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
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
128
sir = sir + Str$(i) + ","
End If
i = i + 2
Wend
End If
MsgBox "numere prime sunt : " + sir
End Sub
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
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
129
i = i + 1
Loop Until n = 1
If l = 0 Then
sir = Str$(n) + "^1"
End If
MsgBox Str$(n1) + "=" + sir
End Sub
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
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))
130
End If
End Sub
131
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
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
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
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
132
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
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
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
133
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
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