Sunteți pe pagina 1din 133

VALERIU LUPU

ALGORITMI. TEHNICI I LIMBAJE DE PROGRAMARE

EDITURA UNIVERSITII TEFAN cel MARE SUCEAVA 2007

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

Cuprins

Capitolul I Capitolul II Capitolul III Capitolul IV Capitolul V Capitolul VI Capitolul VII Capitolul VIII Capitolul IX Capitolul X Capitolul XI Capitolul XII Bibliografie

Descrierea algoritmilor .................................................................................................6 Subprograme ................................................................................................. .............16 Metode de proiectare a algoritmilor ...........................................................................23 Analiza algoritmilor ...................................................................................... .............27 Clase de algoritmi ........................................................................................................34 Evoluia limbajelor de programare .............................................................................41 Limbajul Visual Basic ................................................................................................55 Reguli privind alegerea unui limbaj de programare ...................................................69 Metoda backtracking ..................................................................................................73 Metoda Divide et impera ............................................................................................91 Metoda Greedy ...........................................................................................................95 Studii de caz Aplicaii ...........................................................................................109 ....................................................................................................................................135

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

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

Fig.1.2.1. Blocurile schemelor logice


7

Blocurile de decizie marcheaz punctele de ramificaie ale algoritmului n etapa de decizie. Ramificarea poate fi dubl (blocul logic, Fig.1.2.1.f) sau tripl (blocul aritmetic, Fig. 1.2.1.g). Blocul de decizie logic indic ramura pe care se va continua execuia algoritmului n funcie de ndeplinirea (ramura Da) sau nendeplinirea (ramura Nu) unei condiii. Condiia care se va nscrie n blocul de decizie logic va fi o expresie logic a crei valoare poate fi una dintre valorile "adevrat" sau "fals". Blocul de decizie aritmetic va hotr ramura de continuare a algoritmului n funcie de semnul valorii expresiei aritmetice nscrise n acest bloc, care poate fi negativ, nul sau pozitiv. Blocurile de conectare marcheaz ntreruperile sgeilor de legtur dintre blocuri, dac din diverse motive s-au efectuat astfel de ntreruperi (Fig.1.2.1.h). Pentru exemplificare vom da n continuare dou scheme logice, corespunztoare unor algoritmi pentru rezolvarea problemelor P1.2.1 i P1.2.2. P1.2.1. S se rezolve ecuaia de grad doi aX2+bX+c=0 (a,b,cR _i a 0). 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: x1, x2xn i adunarea celor pozitive la suma S. Pentru aceast parcurgere se folosete o variabil contor i, care este iniializat cu 1 i crete mereu cu 1 pentru a atinge valoarea n, indicele ultimului numr dat. Schemele logice dau o reprezentare grafic a algoritmilor cu ajutorul unor blocuri de calcul. Execuia urmeaz sensul indicat de sgeat, putnd avea loc reveniri n orice punct din schema logic. Din acest motiv se poate obine o schem logic nclcit, greu de urmrit. Rezult importana compunerii unor scheme logice structurate (D-scheme, dup Djikstra), care s conin numai anumite structuri standard de calcul i n care drumurile de la START la STOP s fie uor de urmrit. 1.3. Limbajul PSEUDOCOD Limbajul Pseudocod este un limbaj inventat n scopul proiectrii algoritmilor i este format din propoziii asemntoare propoziiilor limbii romne, care corespund structurilor de calcul folosite n construirea algoritmilor. Acesta va fi limbajul folosit de noi n proiectarea algoritmilor i va fi definit n cele ce urmeaz. innd seama c obinerea unui algoritm pentru rezolvarea unei probleme nu este ntotdeauna o sarcin simpl, c n acest scop sunt folosite anumite metode pe care le vom descrie n capitolele urmtoare, n etapele intermediare din obinerea algoritmului vom folosi propoziii curente din limba romn. Acestea sunt considerate elemente nefinisate din algoritm, asupra crora trebuie s se revin i le vom numi propoziii nestandard. Deci limbajul Pseudocod are dou tipuri de propoziii: propoziii standard, care vor fi prezentate fiecare cu sintaxa i semnificaia (semantica) ei i propoziii nestandard. Aa cum se va arta mai trziu, propoziiile nestandard sunt texte care descriu pri ale algoritmului nc incomplet elaborate, nefinisate, asupra crora urmeaz s se revin. Pe lng aceste propoziii standard i nestandard, n textul algoritmului vom mai introduce propoziii explicative, numite comentarii. Pentru a le distinge de celelalte propoziii, comentariile vor fi nchise ntre acolade. Rolul lor va fi explicat puin mai trziu. Propoziiile standard ale limbajului Pseudocod folosite n aceast lucrare, corespund structurilor de calcul prezentate n figura 1.3.1 i vor fi prezentate n continuare. Fiecare propoziie standard ncepe cu un cuvnt cheie, aa cum se va vedea n cele ce urmeaz. Pentru a deosebi aceste cuvinte de celelalte denumiri, construite de programator, n acest capitol vom scrie cuvintele cheie cu litere mari. Menionm c i propoziiile simple se termin cu caracterul ';' n timp ce propoziiile compuse, deci cele n interiorul crora se afl alte propoziii, au un marcaj de sfrit propriu. De asemenea, menionm c propoziiile limbajului Pseudocod vor fi luate n seam n ordinea ntlnirii lor n text, asemenea oricrui text al limbii romne. Prin execuia unui algoritm descris n Pseudocod se nelege efectuarea operaiilor precizate de propoziiile algoritmului, n ordinea citirii lor. n figura 1.3.1, prin A, B s-au notat subscheme logice, adic secvene de oricte structuri construite conform celor trei reguli menionate n continuare. Structura secvenial (fig.1.3.1.a) este redat prin concatenarea propoziiilor, simple sau compuse, ale limbajului Pseudocod, care vor fi executate n ordinea ntlnirii lor n text.

a) structura secvenial

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


9

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

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

11

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

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

{ rdcini reale }

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

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

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

15

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

16

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

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

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

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

DAC ind=0 ATUNCI k:=k+1; rk:=bj SFDAC SFPENTRU SF-REUNIUNE SUBPROGRAMUL TIPMUL(n,M) ESTE: PENTRU i:=1;n EXECUT TIPRETE mi SFPENTRU SF-TIPMUL SUBPROGRAMUL TIPORDON(n,M) ESTE: CHEAM ORDON(n,M); CHEAM TIPMUL(n,M); SF-TIPORDON { Tiprete cele n elemente } { ale mulimii M }

{ Ordoneaz i tiprete } { elementele mulimii M }

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

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

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

22

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

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

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

25

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

26

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

27

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

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

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

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

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

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

33

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

Fie p:=0;

34

Dac a k1 atunci p:=1 altfel Dac a>kn atunci p:=n+1 altfel Pentru i:=2; n execut Dac (p=0) i (a ki) 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, n 1 i} {k1 < k2 < .... < kn} {Se caut p astfel ca:} {(p=1 i a k1) sau (p=n+1 i a>kn)} {sau (1<p n) i (kp-1 < a kp). Fie p:=1; Dac a>k1 atunci Cttimp p n 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, n 1 i k1 < k2 < .... < kn} {Se caut p astfel ca: (p=1 i a k1) sau} {(p=n+1 i a>kn) sau (1<p n) i (kp-1 < a kp)} Dac a k1 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 St Dr-1 atunci BinarySearch:=Dr altfel m:=(St+Dr) Div 2; Dac a K[m] atunci BinarySearch:=BinarySearch(a,n,K,St,m) altfel BinarySearch:=BinarySearch(a,n,K,m,Dr) sfdac
35

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

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

{Ipoteza "este ordine"}

{N-a fost ordine!} {Ordonare}

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

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

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

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

{Sortare prin interclasare a} {elementelor ASt,ASt+1,...,ADr}

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

40

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

Trebuie s aib o unitate de comand , capabil s interpreteze instruciunile obinute din memorie i capabil s selecteze diferite moduri de desfurare a activitii calculatorului pe baza rezultatelor calculelor. Primul calculator comercializat a fost UNIVAC (UNIversal Automatic Computer ) realizat pe structura calculatorului EDVAC, n anul 1951. n anii 1960 a aprut un nou tip de calculatoare: minicalculatoarele. Aceste maini erau mai ieftine, mai mici, nu avea nevoie de aer condiionat i erau mult mai uor de folosit (cel puin dup standardele acelor timpuri) fa de mainframe-uri. n fa ereziei, preoii mainframe-urilor s-au nfiorat. Deinerea unui mainframe era problema corporaiei, datorit cheltuielilor necesare, dar un departament putea avea propriul minicalculator, pentru c acesta nu necesita spaii speciale sau specialiti necesari unui mainframe. Pe scurt, minicalculatoarele erau ieftine.Aceast dezvoltare a dus la apariia unui nou personaj pe scena calculatoarelor. Minicalculatoarele au adus la nlocuirea programatorilor de mainframe, curai i bine mbrcai, cu o nou specie de programatori. Minicalculatoarele au nceput s fie introduse n universiti i alte instituii de nvmnt, pentru c erau ieftine. Ele erau accesibile i proiectate pentru a putea suporta modificri ulterioare, ceea ce a atras un grup de entuziati cunoscui sub numele de hackeri. Aceti hackers nu sunt identici cu cei din zilele noastre. Acei hacker-i erau plini de entuziasm fa de calculatoare, oameni care voiau s fac programe mai bune, mai rapide i mai elegante.Din rndurile lor s-au ridicat o parte din oameni care au fcut revoluia calculatoarelor personale. Piaa minicalculatoarelor a crescut repede. Imediat ce departamentele puteau justifica nevoia minicalculatorului, acesta era instalat. Acesta a fost momentul cnd DEC (Digital Equipment Corporation) a devenit a doua mare companie productoare de calculatoare din lume.n privina mbuntirilor aduse programelor, gama funciilor care pot fi realizate a crescut. Un minicalculator poate fi folosit simultan de mai muli utilizatori, cu ajutorul unui procedeu de mprire a timpului de folosire a procesului numit time-sharing. Astfel, fiecare utilizator poate s prelucreze date, s creeze programe sau s utilizeze, ca i cnd ar fi singurul utilizator. Acest sistem a fost introdus i n tehnologia de realizare a mainframe-urilor. Sisteme sofisticate de time-sharing, cu componente disc mai puternice i programe mai sofisticate, au fost dezvoltate n acelai timp pentru mainframe-uri.Aceasta era piaa calculatoarelor n anii 70: mainframe-uri i minicalculatoare erau prezente n toate companiile i principalele departamente. Pentru sacinile pe care le puteau rezolva n moduri n care le rezolvau, erau bune. Au adus metode noi i eficiente n birouri i au fcut afacirele mai eficiente. Totui, au euat n mrirea productivitii personale (n creterea eficienei personalului, nu a corporaiilor).

Apariia calculatoarelor personale La mijlocul anilor 70 a aprut o nou tehnologie: miniprocesorul. Acesta folosea multe tranzistoare conectate pe o pastil de siliciu pentru a realiza un dispozitiv de calcul.Primele microprocesoare au fost, dup standardele actuale, destul de simple. Primul microprocesor, devine cunoscut ca 4004, a fost proiectat pe patru bii de ctre inginerul Marcian E. Ted Hoff de la Intel, n anul 1969. Clientul care i-a comandat lui Intel microprocesorul a fost o firm japonez, care a dat faliment n 1970; dup aceasta Intel nu se putea hotr dac s lanseze sau nu circuitul pe pia. L-au lansat, i n 1974 existau mai mult de 19 tipuri de microprocesoare pe pia, inclusiv Intel 8088, cel care va deveni trambulina actualelor calculatoare personale.Microprocesoarele au fost iniial folosite drept controler - dispozitive de control pentru maini de splat vesel i frigidere. Productorii i proiectanii de calculatoare nu au pierdut ocazia dat de potenial acestor dispozitive de a fi folosite drept calculatoare. 8080, Z80, CP/M Primele succese ale pieei au fost microprocesorul Intel 8080 i noul sistem de operare numit CP/M-80 scris pentru acest cercuit. CP/M-80 a fost creat n 1975 de Gary Kildall, fondatorul i preedintele companiei Digital Research primul productor al unui sistem de operare pentru microcalculatoare. Astzi, compania este o divizie a lui Novell Inc. cea mai mare companie n domeniul sistemelor de operare n reea.CP/M este prescurtat de la Controlul Programului/Microcalculatorului cel mai sugestiv nume de produs, dac mai existase unul, de pn atunci. Acest sistem de operare a fost, la
42

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

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

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

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

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

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

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

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

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

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

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

LISP (LISt Processing language) conceput n 1976 i implementat pe PC-uri de firma Microsoft sub forma MuLISP.

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

54

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

55

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

Exemplu frmForma1 cmdButon, btnOK txtCaseta1

Obiect Bare de derulare - orizontal - vertical Meniu Caset de validare Caset cu lista Cadru Imagine Buton de opiune (radio) 7.3 Instruciunile VBA Generaliti

Prefix hsb vsb Mnu Chk Lst Fra Img Opt

Exemplu

mnuMeniuPrinc

optBO1

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

57

Comentariul de pe aceeai linie cu o instruciune se introduce printr-un apostrof urmat de comentariu. 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 Ridicarea la putere nmulirea Observaii rezultatul este Double sau Variant(Double) cu excepia: dac un operand este Null, rezultatul este tot Null rezultatul este dat de cel "mai precis" factor, ordinea cresctoare a "preciziei" fiind, pentru nmulire, Byte, Integer, Long, Single, Currency, Double i Decimal. Dac o expresie este Null, rezultatul este Null. O expresie Empty este considerat ca 0. Pentru excepii se va studia Help *(operator). rezultatul este, n general, Double sau Variant(Double). Dac o expresie este Null, rezultatul este Null. O expresie Empty este considerat ca 0. Pentru excepii se va studia Help / (operator). nainte de mprire, operanzii sunt rotunjii la Byte, Integer sau Long. Rezultatul este Byte, Variant(Byte), Integer, Variant (Integer), Long, sau Variant(Long). Dac o expresie este Null, rezultatul este Null. O expresie Empty este considerat ca 0. operanzii sunt rotunjii la ntregi i se obine restul mpririi. Rezultatul este Byte, Variant(Byte), Integer, Variant (Integer), Long, sau Variant(Long). Dac o expresie este Null, rezultatul este Null. O expresie Empty este considerat ca 0. n general, operanzi numerici produc adunarea, iar operanzi iruri produc concatenarea. n cazul numeric, rezultatul este de tipul cel "mai precis" al operanzilor, ordinea de "precizie" fiind pentru adunare i scdere: Byte, Integer, Long, Single, Double, Currency i Decimal. Deoarece operanzii pot fi orice expresie, pentru o informare complet (de exemplu operanzi Variant) se va studia Help +(operator). operanzii pot fi doar numerici. Rezultatul este de tipul cel "mai precis" al operanzilor, ordinea de "precizie" fiind pentru adunare i scdere: Byte, Integer, Long, Single, Double, Currency i Decimal. Dac o expresie este Null, rezultatul este Null. O expresie Empty este considerat ca 0. Pentru excepii se va studia Help -(operator).

mprirea

mprirea ntreag

Mod

Restul mpririi

Adunarea numeric sau concatenarea irurilor

Scderea sau inversarea semnului

58

Operatori de comparare 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. 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. 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. negaia logic Not Null este Null. Prin operatorul Not se poate inversa bit cu bit valorile unei variabile, poziionndu-se corespunztor un rezultat numeric.

Eqv

Imp

Not

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. disjuncia exclusiv Dac un operand este Null, atunci rezultatul este Null. Se poate efectua operaia de sau exclusiv i bit cu bit pentru dou expresii numerice [b1+b2(mod 2)].

Xor

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

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

61

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

62

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

sau

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

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

63

Structurile Do pot fi inserate (dar complet) unele n altele. O terminare (prin orice metod) a unei bucle transfer controlul la nivelul Do imediat superior. Execuia structurilor este explicat n tabelul urmtor Do WhileLoop Testeaz condiia la nceputul buclei, execut bucla numai dac rezultatul este True i continu astfel pn cnd o nou evaluare produce False. Testeaz condiia la nceputul buclei, execut bucla numai dac rezultatul este False i continu astfel pn cnd o nou evaluare produce True. Se execut ntotdeauna bucla o dat, se testeaz condiia la sfritul buclei i se repet bucla att timp ct condiia este True. Oprirea este pe condiie fals. Se execut ntotdeauna bucla o dat, se testeaz condiia la sfritul buclei i se repet bucla att timp ct condiia este False. Oprirea este pe condiie adevrat.

Do UntilLoop

DoLoop While

DoLoop Until

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

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

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

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

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

67

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

68

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

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

oblig implementatorul s gndeasc nc o utilizare (cel puin) a respectivului subprogram, independent de cea pentru care a fost iniial conceput.

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

71

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

72

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

Prezentm algoritmul corespunztor cazului n=3: 1 1 1 3 1 2 1 2 2 1 2 3 1 3 1 2 1 2 1 3 3 1 2 2 2 2 1 3 2 1 1 2 1 3 2

1 3 1 1 1 2

2 3 2

se ncarc n stiv pe nivelul 1 valoarea 1; ncrcarea valorii 1 pe nivelul al 2-lea nu este posibil, ntruct aceast valoare se gsete i pe nivelul 1 al stivei; ncrcarea valorii 2 pe nivelul al 2-lea este posibil, deoarece aceast valoare nu mai este ntlnit; valoarea 1 din nivelul al 3-lea se regsete pe nivelul 1; valoarea 2 din nivelul al 3-lea se regsete pe nivelul al 2-lea; valoarea 3 pe nivelul al 3-lea nu e ntlnit pe nivelurile anterioare; ntruct nivelul 3 este completat corect. Tiprim: 1 2 3 Algoritmul continu pn cnd stiva devine vid. Programul sursa este urmatorul:
Private Sub CommandButton14_Click() cit_n "n = ", n back_perm End Sub Sub back_perm() Dim k As Integer k = 1 While k > 0 Do succesor am_suc, st, k If am_suc = True Then valid1 ev, st, k End If Loop Until (Not am_suc) Or (am_suc And ev) If am_suc Then If solutie(k) Then tipar_r Else k = k + 1 init k, st End If Else k = k - 1 End If Wend
74

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

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

n stiva iniial vid se introduce litera A, vrful stivei va fi la nivelul 1 (k-1); introducem n stiv litera B, deci k va lua valoarea 2; scoatem din stiv pe B (A nu poate fi scos); scoatem din stiv pe A; stiva rmne vid

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

Prezentarea tehnicii Backtracking Aceast tehnic se folosete n rezolvarea problemelor care ndeplinesc simultan urmtoarele condiii: soluia lor poate fi pus sub forma unui vector S=x1,x2, ...,xn, cu x1 A1, x2 A2 , xn An mulimile A1, A2 , ., An sunt mulimi finite, iar elementele lor se consider c se afl ntr-o relaie de ordine bine stabilit; nu se dispune de o alt metod de rezolvare, mai rapid x1 x2 , xn pot fi la rndul lor vectori; A1, A2 , An pot coincide. La ntlnirea unei astfel de probleme, dac nu cunoatem aceast tehnic, suntem tentai s generm toate elementele produsului cartezian A1,A2 ,An si fiecare element s fie testat dac este soluie. Rezolvnd problema n acest mod, timpul de execuie este att de mare, nct poate fi considerat infinit, algoritmul neavnd nici o valoare practic. De exemplu, dac dorim s generm toate permutrile unei mulimi finite A, nu are rost s generm produsul cartezian AxAx.....xA, pentru ca apoi, s testm, pentru fiecare element al acestuia, dac este sau nu permutare (nu are rost s generm 1.1,1.......1, pentru ca apoi s constatm c nu am obinut o permutare, cnd de la a doua cifr 1 ne puteam da seama c cifrele nu sunt distincte). Tehnica Backtracking are la baz un principiu extrem de simplu: se construiete soluia pas cu pas: x1, x2 ,xn dac se constat c, pentru o valoare aleas, nu avem cum s ajungem la soluie, se renun la acea valoare i se reia cutarea din punctul n care am rmas. Concret: se alege primul element x, ce aparine lui A; presupunnd generate elementele x1,x2 ,xk , aparinnd mulimilor A1, A2 ,Ak, se alege (dac exist) xk+1, primul element disponibil din mulimea Ak+1, apar dou posibiliti: 1) Nu s-a gsit un astfel de element, caz n care caz n care se reia cutarea considernd generate elementele x1,x2 ,xk+1 , iar aceasta se reia de la urmtorul element al mulimii Ak rmas netestat; 2) A fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii de continuare aprnd astfel dou posibiliti: ndeplinete, caz n care se testeaz dac s-a ajuns la soluie si apar din nou dou posibiliti: - s-a ajuns la soluie, se tiprete soluia si se reia algoritmul considernd generate elementele x1,x2 ,xk, (se caut n continuare, un alt element al mulimii Ak, rmas netestat); - nu s-a ajuns la soluie, caz n care se reia algoritmul considernd generate elementele x1,x2 ,xk , si se caut un prim element xk+2 Ak. nu le ndeplinete caz n care se reia algoritmul considernd generate elementele x1,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 x1
ST Nivelul k+1 al stivei trebuie iniializat (pentru a alege, n ordine, elementele mulimii k+1 ). Iniializarea trebuie fcut cu o valoare aflat (n relaia de ordine considerat, pentru mulimea Ak+1 ) naintea tuturor valorilor posibile din mulime. De exemplu, pentru generarea permutrilor mulimii {1,2.....n}, orice nivel al stivei va lua valori de la 1 la n. Iniializarea unui nivel (oarecare) se face cu valoarea 0. Procedura de iniializare o vom numi INIT i va avea doi parametri: k (nivelul care trebuie iniializat si ST (stiva)). Gsirea urmtorului element al mulimii Ak (element care a fost netestat) se face cu ajutorul procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o variabil boolean. n situaia n care am gsit elementul, acesta este pus n stiv i AS ia valoarea TRUE, contrar (nu a rmas un element netestat) AS ia valoarea FALSE.. Odat ales un element, trebuie vzut dac acesta ndeplinete condiiile de continuare (altfel spus, dac elementul este valid). Acest test se face cu ajutorul procedurii VALID (EV,ST,K). Testul dac s-a ajuns sau nu la soluia final se face cu ajutorul funciei SOLUTIE(k) iar o soluie se tiprete cu ajutorul procedurii TIPAR. Prezentm n continuare rutina Backtracking:
k:=1; CALL init(1,st); while k>0 do CALL succesor (as, st, k) ; if as then CALLvalid(ev,st,k) then loop until (not as) or (as and ev) ; if as then if solutie(k) then CALL tipar else k:=k+l; CALL init ( k, st ); end; else k:=k-1 wend

Observaie: Problemele rezolvate prin aceast metod necesit un timp ndelungat. Din acest motiv, este bine s utilizm metoda numai atunci cnd nu avem la dispoziie un alt algoritm mai eficient. Cu toate c exist probleme pentru care nu se pot elabora ali algoritmi mai eficieni, tehnica backtracking trebuie aplicat numai n ultim instan. Fiind dat o tabl de ah, de dimensiune n, 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). Exemplu: Presupunnd c dispunem de o tabl de dimensiune 4x4, o soluie ar fi urmtoarea:
77

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

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

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

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

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

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


78

Dama a treia se aeaz n prima coloan. D D D

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

ST(4) ST(3) ST(2) ST(1)

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

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

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

Produsul cartezian a n mulimi. Se dau mulimile de mai jos i se cere produsul cartezian al lor. A1 = {1, 2, 3, , k1} A2 = {1, 2, 3, , k2} An = {1, 2, 3, , kn} Exemplu: A1 = {1, 2} A2 = {1, 2, 3} A3 = {1, 2, 3} A1 A2 A3 = {(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 1), (1, 3, 2), (1, 3, 3), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 1), (2, 3, 2), (2, 3, 3)}. Pentru rezolvare, se folosesc stiva ST i un vector A ce reine numerele k1, 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 1 1 2 2 1 1 3 2 1 3 1 2 1 1 3 1 1 1 3 1 2 1 2 3 1 1 2 1 3 3 1

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

Next End Sub Sub tipar(mes sir = "" For i = 1 To sir = sir + Next MsgBox mes + End Sub As String, n As Integer, a As vector) n Str$(a.v(i)) + "," " " + sir

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

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

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

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

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

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

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

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

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

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

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

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

End Sub

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

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

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

90

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

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

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

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

94

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

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

95

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

= = = = = =

38 31 43 41 29 34

optim

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

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

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

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

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

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

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

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

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

Etichetam muchia stanga cu 1 si muchia dreapta cu 0. Rearanjam tabelul de frecvente: S (10), I (29), O (9), {P, T} (45 = 9) Multimea {P, T} semnifica evenimentul reuniune a celor doua evenimente independente corespunzatoare aparitiei literelor P si T. Continuam procesul, obtinand arborele
99

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

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

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

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


101

Pasul initializare 1 2 3 4 5 6 7

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

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

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

102

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

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

gaseste {u, v} de cost minim astfel ca u V \ U si v U A A {{u, v}} U U {u} return A Pentru a obtine o implementare simpla, presupunem ca: varfurile din V sunt numerotate de la 1 la n, V = {1, 2, ..., n}; matricea simetrica C da costul fiecarei muchii, cu C[i, j] = + , daca muchia {i, j} nu exista. Folosim doua tablouri paralele. Pentru fiecare i V \ U, vecin[i] contine varful din U, care este conectat de i printr-o muchie de cost minim; mincost[i] da acest cost. Pentru i U, punem mincost[i] = 1. Multimea U, in mod arbitrar initializata cu {1}, nu este reprezentata explicit. Elementele vecin[1] si mincost[1] nu se folosesc. function Prim(C[1 .. n, 1 .. n]) {initializare; numai varful 1 este in U} A for i 2 to n do vecin[i] 1 mincost[i] C[i, 1] {bucla greedy} repeat n1 times min + for j 2 to n do if 0 < mincost[ j] < min then min mincost[ j] kj {{k, vecin[k]}} AA mincost[k] 1 {adauga varful k la U} for j 2 to n do if C[k, j] < mincost[ j] then mincost[ j] C[k, j] vecin[ j] k return A Bucla principala se executa de n1 ori si, la fiecare iteratie, buclele for din interior necesita un timp in O(n). Algoritmul Prim necesita, deci, un timp in O(n2). Am vazut ca timpul pentru algoritmul lui Kruskal este in O(m log n), unde m = #M. Pentru un graf dens (adica, cu foarte multe muchii), se deduce ca m se apropie de n(n1)/2. In acest caz, algoritmul Kruskal necesita un timp in O(n2 log n) si algoritmul Prim este probabil mai bun. Pentru un graf rar (adica, cu un numar foarte mic de muchii), m se apropie de n si algoritmul Kruskal necesita un timp in O(n log n), fiind probabil mai eficient decat algoritmul Prim. 11.5 Cele mai scurte drumuri care pleaca din acelasi punct Fie G = <V, M> un graf orientat, unde V este multimea varfurilor si M este multimea muchiilor. Fiecare muchie are o lungime nenegativa. Unul din varfuri este desemnat ca varf sursa. Problema este sa determinam lungimea celui mai scurt drum de la sursa catre fiecare varf din graf. Vom folosi un algoritm greedy, datorat lui Dijkstra (1959). Notam cu C multimea varfurilor disponibile (candidatii) si cu S multimea varfurilor deja selectate. In fiecare moment, S contine acele varfuri a caror distanta minima de la sursa este deja cunoscuta, in timp ce multimea C contine toate celelalte varfuri. La inceput, S contine doar varful sursa, iar in final S contine toate varfurile grafului. La fiecare pas, adaugam in S acel varf din C a carui distanta de la sursa este cea mai mica. Spunem ca un drum de la sursa catre un alt varf este special, daca toate varfurile intermediare de-a lungul drumului apartin lui S. Algoritmul lui Dijkstra lucreaza in felul urmator. La fiecare pas al
104

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

Figura 11.5 Un graf orientat. Pasul initializare 1 2 3 v 5 4 3 C {2, 3, 4, 5} {2, 3, 4} {2, 3} {2} D [50, 30, 100, 10] [50, 30, 20, 10] [40, 30, 20, 10] [35, 30, 20, 10]

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

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

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

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

Conform strategiei greedy, vom construi ciclul pas cu pas, adaugand la fiecare iteratie cea mai scurta muchie disponibila cu urmatoarele proprietati: nu formeaza un ciclu cu muchiile deja selectate (exceptand pentru ultima muchie aleasa, care completeaza ciclul) nu exista inca doua muchii deja selectate, astfel incat cele trei muchii sa fie incidente in acelasi varf La: 2 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.
Private Sub CommandButton1_Click() Dim rad As Integer, n As Integer, p As Integer, i As Integer, j As Integer cit_n "n = ", n For i = 3 To n p = 1 rad = Int(Sqr(i + 2)) For j = 2 To Int(rad) If i Mod j = 0 Or (i + 2) Mod j = 0 Then prim = 0 j = Int(rad) End If Next If p Then MsgBox "(" + Str$(i) + "," + Str$(i + 2) + ")" + Chr(13) End If Next End Sub

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


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

3. Citirea unui vector cu n componente


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

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

4. Tiprirea unui tablou cu n componente


Sub tipar(mes sir = "" For i = 1 To sir = sir + Next MsgBox mes + End Sub As String, n As Integer, a As vector) n Str$(a.v(i)) + "," " " + sir

5. Generarea permutrilor utiliznd metoda backtracking


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

6. Generarea produsului cartezian a n mulimi utiliznd metoda backtracking


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

7. Generarea permutrilor utiliznd metoda backtracking


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

8. Problema celor n dame utiliznd metoda backtracking


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

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


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

10. Generarea partiiilor unei mulimi utiliznd metoda backtracking


Private Sub CommandButton19_Click()
111

cit_n "n=", n back_partitii End Sub

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

12. Realizarea unei subrutine pentru sortarea rapid Quicksort


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

13. Sortarea Merge-Sort utiliznd metoda Divide et impera


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

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

14. Sortarea rapid utiliznd metoda Divide et impera


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

15. Problema colorrii hrilor utiliznd metoda backtracking


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

113

16. Interclasarea a 2 iruri ordonate cresctor


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

17. Sortarea Shell-Sort utiliznd metoda Greedy


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

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

18. Citirea si scrierea unei matrici pe ecran


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

19. Citirea unei matrici de pe dispozitivul de intrare


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

20. Scrierea unei matrici pe ecran


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

End Sub

21. Produsul a dou matrici


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

22. Programul principal pentru adunarea a dou matrici


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

23. Subrutina pentru adunarea a dou matrici


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

End Sub

24. Programul principal pentru scderea a dou matrici


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

25. Subrutina pentru adunarea a dou matrici


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

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


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

27. Subprogramul pentru ridicarea unei matrici la o putere p


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

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

28. Subrutina de iniializare a stivei pentru metoda backtracking


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

29. Subrutina successor pentru problema celor n dame


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

30. Subrutina successor pentru generarea combinrilor


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

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

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

32. Subrutina successor pentru colorarea hrilor


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

33. Subrutina valid pentru problema celor n dame


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

34. Subrutina valid pentru colorarea hrilor


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

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

35. Subrutina valid pentru produs cartezian a n mulimi


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

36. Subrutina soluie pentru generarea permutrilor


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

37. Subrutina soluie pentru generarea aranjamentelor sau combinrilor


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

38. Subrutina tiprire pentru problema celor n dame


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

39. Subrutina tiprire pentru colorarea hrilor


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

MsgBox b End Sub

40. Subrutina back pentru problema celor n dame


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

41. Programul principal pentru problema celor n dame


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

42. Subrutina back pentru generarea permutrilor


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

k = k - 1 End If Wend End Sub

43. Subrutina back pentru generarea aranjamentelor


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

44. Subrutina valid pentru metoda backtracking


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

45. Subrutina tipar pentru metoda backtracking


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

46. Subrutina tipar pentru metoda backtracking


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

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

47. Subrutina back pentru generarea combinrilor


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

48. Subrutina back pentru generarea produsului cartezian a n multimi


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

End Sub

49. Subrutina back pentru generarea partiiilor unei mulimi


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

50. Subrutina tiparire pentru problema generare partiii a unei mulimi


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

51. Subrutina succesor pentru problema generare partiii a unei mulimi


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

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

52. Subrutina back pentru colorarea hrilor


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

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

54. Programul principal pentru inversarea unui numr natural n


125

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

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

56. Sortarea unui sir cu n componente utiliznd metoda bulelor


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

57. Subrutina pentru sortarea prin metoda bulelor


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

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

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


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

59. Subrutina pentru sortarea prin metoda seleciei directe


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

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


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

61. Suma cifrelor unui numr natural dat n


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

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

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


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

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

64. Ciurul lui Eratostene


128

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

65. Descompunerea unui numar in factori primi


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

66. Scrierea unui numr ca suma a dou cuburi


129

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

67. CMMDC a dou numere utiliznd recursivitatea


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

68. Funcia euclid


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

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

69. CMMDC a dou numere utiliznd scderi repetate


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

70. Funcia Euclid utiliznd scderi repetate


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

71. Funcia Euclid utiliznd scderi repetate


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

72. x ^ y utiliznd un numr minim de nmuliri


131

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

73. Verific dac un numr natural este palindrome sau nu


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

74. Baza la exponent


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

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

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


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

77. Turnurile din Hanoi


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

78. Subrutina Hanoi


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

79. Subrutina back pentru permutri


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

k = k - 1 End If Wend End Sub

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


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

134

Bibliografie
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/
[1.]

135

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