Vous êtes sur la page 1sur 21

I.

NOIUNE DE ALGORITM, DESCRIEREA ALGORITMILOR Rezolvarea problemelor cu ajutorul calculatorului presupune existena unei etape premergtoare, clap n care se concepe algoritmul. Noiunea de algoritm este o noiune foarte veche. Cuvntul algoritm este de origine arab. El deriv din numele matematicianului Abu Jafar Mohammed ibn Ms al-Khownzm (autor persan, sec. VII-IX) care a scris o carte de matematic celebr intitulat: Kitab al jabr w'ai-rnuquabala cunoscut n traducere latin ca Algonthmi de numero indorum, iar apoi ca Liber algorithmi, unde algonthm provine de la al-Khowrizm, ceea ce literal nseamn din oraul Khownzm. Acest ora se numete n prezent Khiva i ei se afl n Uzbechistan. n Evul Mediu, att al-Khownzm ct i ali matematicieni nelegeau prin algoritm o regul pe baza creia se efectuau calcule aritmetice.. Astfel, n timpul lui Adam Riese (sec. XVI), algoritmii foloseau la: njumtiri, dublri, nmuliri de numere. n lucrrile lui Stifer (Arithmetica integra, Nurnberg, 1544) i Cardano (Ars magna sive de reguli algebraicis, Nmberg, 1545) apar i ali algoritmi. Chiar i Leibnitz vorbete de algoritmi de nmulire. Totui, mult timp termenul de algoritm a rmas cu o ntrebuinare destul de restrns, chiar i n domeniul matematicii. Un algoritm se definete ca o succesiune de operaii care. pentru o anumit clas de probleme, plecnd de la condiiile iniiale (datele de intrare), cu ajutorul unor operaii efectuate mecanic, fr aportul creator al omului, permite s se obin soluia (datele de ieire). Un algoritm trebuie s satisfac n general urmtoarele proprieti: claritate: descrierea algoritmului s se fac precis, fr nimic arbitrar, fr ambiguiti, parcurgnd toate etapele de calcul n ordinea n care apar. astfel nct la final s se obin soluia corect a problemei. generalitate: un algoritm este util clac rezolv o ntreag clas de probleme finititudine: un algoritm trebuie s furnizeze rezultate pentru orice set de date de intrare ntr-un numr finit i ct mai mic de pai i ntr-un timp finit i ct mai scurt. Pentru rezolvarea aceleiai probleme se pot folosi mai muli algoritmi, diferena dintre ei fiind dat de durata procesului de calcul, de numrul de pai efectuai, de mrimea erorilor ce afecteaz rezultatul, n concluzie, rmne n sarcina programatorului s aleag algoritmul cel mai eficient. Pentru a putea rezolva o problem cu ajutorul calculatorului este necesar parcurgerea urmtoarelor etape preliminare: - problema s fie pus sub form matematic, iar datele de intrare s fie puse sub form numeric: - precizarea valorilor datelor de intrare i de ieire; - ntocmirea schemei logice pentru a descrie grafic algoritmul ales. Sau descrierea algoritmului n limbaj pseudocod: - scrierea programului ntr-un limbaj de programare, corectarea erorilor de sintax i verificarea corectitudinii rezultatului. Un algoritm este compus dintr-o mulime de pai, fiecare necesitnd una sau mai multe operaii. Operaiile care apar n cadrul unui algoritm sunt: operaii de intrare-ieire: datele de intrare se citesc (de la tastatur i /sau din fiiere) i ele reprezint valorile iniiale de la care se ncepe rezolvarea problemei: datele de ieire reprezint rezultatul problemei obinut dup parcurgerea algoritmului i se afieaz (pe ecran i / sau n fiiere). operaii de atribuire: reprezint acele operaii n urma crora valoarea unei expresii (aritmetice, logice sau relaionale) este pstrat ntr-o variabil. operaii de decizie: se determin valoarea de adevr a unei expresii logice i n funcie de rezultatul obinui se continu execuia programului pe una din ramificaii. Programarea structurata folosit n elaborarea algoritmilor presupune folosirea unui numr mic de structuri elementare avnd fiecare o singur intrare i o singur ieire din structur: astfel, orice algoritm apare ca o secven liniar de structuri elementare. structurile elementare sunt: structura liniar: const n execuia necondiionat a unei secvene de instruciuni; structura alternativ: ramific execuia programului in funcie de valoarea de adevr a condiiei evaluat; structura repetitiv: const n execuia repetat, dar finit, a unei secvene de instruciuni n funcie de ndeplinirea sau nu a unei condiii. Una din noiunile de baz din programare este cea de variabil, n general o variabil este caracterizat prin. numele variabilei: format din unul sau mai multe caractere (litere, cifre i caracterul _ cu condiia ca primul caracter s fie o liter). Referirea la o variabil se realizeaz prin numele ei. Prin program vom nelege exprimarea unui algoritm ntr-un limbaj de programare cunoscut de un calculator. Studiul algoritmilor cuprinde mai multe aspecte: -Elaborarea Algoritmilor. Actul de creare a unui algoritm este o art ce presupune creativitate uman bazat pe o sene de reguli cunoscute (tehnici de elaborare a algoritmilor, despre care vom discuta n aceast lucrare) i pe ingeniozitatea (intuiia, creativitatea) uman. -Reprezentarea algoritmilor. Algoritmii pot fi reprezentai prin mai multe metode: pseudocod, scheme logice, diagrame etc. n aceast lucrare noi vom utiliza un limbaj pseudocod foarte apropiat do limbajul Pascal ceea ce face sa fie uor de neles de ctre cititor, aa c nu vom mai expune sintaxa acestui limbaj pseudocod.

-Corectitudinea algoritmilor. Dup elaborarea i reprezentarea sa, un algoritm trebuie s fie validat (s i se verifice corectitudinea) pentru a ne asigura c el funcioneaz corect, indiferent n ce limbai de programare va fi implementat. -Analiza algoritmilor. Pentru o anumit problem pot fi elaborai mai muli algoritmi. Pentru a putea s, decidem care dintre ei este cel mai bun, este nevoie s definim un criteriu de apreciere a valoni unui algoritm. n general, acest criteriu se refer la timpul de calcul i la memoria necesar unui algoritm. n aceast lucrare vom face i cteva analize din acest punct de vedere, dar scopul principal rmne descrierea tehnicilor generale de elaborare a algoritmilor. -Elaborarea programelor. Un algoritm corect, de obicei, este implementat ntr-un limbaj de programare, pentru a fi utilizat pe calculator. n practic, sunt cazuri cnd unu algoritmi sunt implementai n alt context (nu neaprat pe un calculator). Noi ne vom ocupa n mod special de algoritmii ce sunt implementai pe calculator. -Testarea programelor. Acest aspect const din dou faze: depanare i trasare. -Depanarea (debugging) este procesul ce const n executare a programului pe date de test i corectarea eventualelor erori. Prin depanare, aa cum afirma E. W. Dijkstra, putem evidenia doar prezena erorilor dar nu i absena lor. n schimb, demonstrarea faptului c un program este corect este mult mai valoroasa dect o mie de teste deoarece prin demonstraie se poate garanta c programul funcioneaz corect n orice situaie. -Trasarea (profiling), este procesul de execuie a unui program corect pe diferite date de test (bine alese.) cu scopul de a determina timpul de calcul i memoria necesar. Rezultatele obinute i aceast etap se pot compara, dup aceea, cu rezultatele obinute n etapa de analiz a algoritmului. Cnd avem de rezolvat o problem, este important s ne decidem c algoritm vom folosi pentru rezolvare. Rspunsul poate s depind de rnuli factori: dimensiunea exemplului de rezolvat, modul n care problema este prezentat, viteza i memoria disponibil a echipamentului de calcul i aa mai departe. S lum ca exemplu aritmetica elementar. S presupunem c avem de nmulit dou numere naturale folosind stilou i hrtie. Bineneles c vom fi imediat tentai s utilizm algoritmul cunoscut: nmulim fiecare cifr a nmulitului cu denmulitul, iar rezultatul este trecut pe linii, cu o poziie la stnga i la final se adun aceste coloane i se obine rezultatul. Acesta este algoritmul clasic de nmulire. 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. 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; - 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 printro 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 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. 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.

Fig.1.2.2. Algoritm pentru rezolvarea ecuaiei de gradul doi.

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 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.

Fig.1.2.3. Algoritm pentru calculul unei sume. 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. 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 [Bohm66] 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.

a) structura secvenial

b) structura alternativ Figura 1.3.1. Structurile elementare de calcul

c) structura repetitiv

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 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: CITETE D,T; FIE V:=D/T; TIPRETE V SFALGORITM 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 { A1: Calculeaz viteza } { D = Distana (spaiul) } { T = Timpul; V = Viteza } { v:= spaiu/timp }

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 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. { Algoritmul 2: Rezolvarea } { ecuaiei de gradul doi } { a,b,c = Coeficienii ecuaiei } { rdcini complexe }

{ rdcini reale }

10

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). 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

11

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 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. II. METODE DE PROIECTARE A ALGORITMILOR 2.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 subalgoritmilor apelai, conform metodelor prezentate n seciunile urmtoare. Ea se termin cu descrierea algoritmului principal i a subalgoritmilor menionai, dar i cu precizarea denumirilor i semnificaiilor variabilelor folosite; - verificarea algoritmului obinut. 2.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 subalgoritmi pentru rezolvarea lor. Urmeaz s considerm pe rnd fiecare subproblem n parte i s proiectm (n acelai mod) un subalgoritm pentru rezolvarea ei. n final, se va descrie subalgoritmul de rezolvare al fiecrei subprobleme, dar i interaciunile dintre aceti subalgoritmi i ordinea n care ei sunt folosii. Noiunea de modul va fi definit n seciunea urmtoare. Deocamdat nelegem prin modul orice subalgoritm 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. Astfel, n arborele de programare din fig.3.1.1 exist un algoritm principal (modulul PRINC), care apeleaz trei subalgoritmi (modulele CITDATE, CALCULE i TIPREZ). La rndul su, modulul CALCULE apeleaz trei subalgoritmi (modulele M1, M2 i M3). Fig.3.1.1. Arbore de programare 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. 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 subalgoritmul Quicksort, care va fi prezentat n seciunea 7.3. Metoda ascendent (bottom-up) pornete de la propoziiile limbajului i de la subalgoritmi existeni, pe care i asambleaz n ali subalgoritmi pentru a ajunge n final la algoritmul dorit. Cu alte cuvinte, n cazul metodei ascendente va fi scris mai nti

12

subalgoritmul apelat i apoi cel care apeleaz. Ca rezultat al proiectrii ascendente se ajunge la o mulime de subalgoritmi care se apeleaz ntre ei. Este important s se cunoasc care subalgoritm apeleaz pe care, lucru redat printr-o diagram de structur, ca i n cazul programrii descendente. Aceast metod are marele dezavantaj c erorile de integrare vor fi detectate trziu, abia n faza de integrare. Se poate ajunge abia acum la concluzia c unii subalgoritmi, 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. 2.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 subalgoritm 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 subalgoritm, un grup de subalgoritmi, sau un algoritm de sine stttor ce apeleaz ali subalgoritmi, 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 subalgoritmilor 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 subalgoritmilor 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. 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 subalgoritm este mult mai mare pentru texte scurte. n unele cri chiar se recomand a nu se folosi subalgoritmi mai mari dect 50 de propoziii. Sigur c o astfel de limit nu exist, dar se recomand descompunerea unui subalgoritm n ali subalgoritmi oricnd acest lucru este posibil n mod natural, deci aceti noi subalgoritmi rezolv subprobleme de sine stttoare, sau realizeaz funcii bine definite. 2.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;

13

- 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 BohmJacopini. 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 subalgoritm; - 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. 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. Referitor la faza de codificare ntr-un limbaj de programare a unui algoritm obinut n urma unei proiectri structurate se cere respectarea structurii acestui algoritm, ceea ce este posibil i uor de realizat dac limbajul de programare are structurile de calcul respective. n acest caz programul va fi o copie fidel a algoritmului proiectat. III. 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. 3.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 (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.

14

3.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. 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

15

const ntr-un numr de execuii a programului care s ne asigure c fiecare instruciune din program a fost executat cel puin odat. Ea nseamn mult mai puine execuii dect toate drumurile START-STOP. Exist date de test care ne duc pe un anumit drum fr a depista erori existente n instruciunile ntlnite i alte date de test care depisteaz aceste erori. nc un motiv pentru care se recomand o testare mixt. Ca ordine de folosire a datelor de test n timpul testrii, se recomand mai nti testarea dup specificaii i apoi testarea dup textul programului. Este necesar i testarea robusteei programului, care nseamn buna lui comportare la date de intrare intenionat greite, pentru care problema nu are sens. Unele programe intr n aceste condiii n ciclu infinit, altele se termin cu erori de execuie. Un program robust nu trebuie s fie afectat de datele de intrare eronate. Comportarea cea mai normal n astfel de situaii ar fi semnalarea unor mesaje de eroare corespunztoare. La un produs program complex testarea este o activitate mult mai complicat. Este necesar o testare separat a fiecrui modul n parte, o testare a interfeei dintre module i o testare a produsului n ansamblu (testarea de integrare). Testarea de integrare se refer la funcionarea programului realizat n ansamblu. Dup ce fiecare modul n parte a fost testat i corectat, deci n ipoteza c fiecare modul n parte este corect, e necesar s se verifice comportarea global a programului. n aceast etap gsirea erorilor, nlturarea cauzelor care le-a generat i corectarea lor, poate fi foarte dificil, mai ales atunci cnd ele provin dintr-o proiectare greit. Execuia unui program se poate termina anormal datorit apariiei unor erori ca: - mpriri la zero; - alte erori ce provoac depiri; - neconcordana ntre parametri actuali i formali; - depirea dimensiunii tablourilor. Dar chiar i la execuia normal a programului putem avea erori, unele foarte grave, obinnd rezultate greite. n ambele situaii urmeaz depanarea programului, adic descoperirea cauzei erorilor i nlturarea lor. 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. 3.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. 3.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);

16

- 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. 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. 3.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. 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:

17

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+NOTE i,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; - n definiii, pentru a descrie semnificaia notaiilor folosite (a variabilelor, constantelor, subalgoritmilor 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. IV. 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. 4.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;

18

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 subalgoritmi. O prim metod este cutarea secvenial, n care sunt examinate succesiv toate cheile. Subalgoritmul 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; 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. Subalgoritmul 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 subalgoritmul dat n continuare. Subalgoritmul 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 sfdac sf-BinarySearch

19

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 4.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. Subalgoritmul 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. Subalgoritmul BubbleSort (n,K) este: Repet Fie kod:=0; {Ipoteza "este ordine"} Pentru i:=2; n execut Dac ki-1 > ki atunci t := ki-1; ki-1 := ki; ki:=t; kod:=1 {N-a fost ordine!} sfdac sfpentru pncnd kod=0 sfrep {Ordonare} sf-BubbleSort

20

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. Subalgoritmul 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 : Subalgoritmul 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 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. 4.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: Subalgoritmul 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}

21

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 subalgoritmul PUNE(ind,val,k,Z) care pune n vectorul Z valoarea val i mrete indicele ind cu 1, subalgortim dat n continuare. Subalgoritmul PUNE(ind,val,k,Z) este: k:=k+1; zk:=val; ind:=ind+1 sf-PUNE Algoritmul MergeSort de sortare bazat pe interclasare se poate vedea n continuare. Algoritmul MergeSort este: Citete n; Pentru i:=1 ; n execut Citete Ki sfpentru Cheam SortInter (n,K); Pentru i:=1; n execut Tiprete Ki sfpentru sf-MergeSort Subalgoritmul SortInter(n, C) este: Cheam Ordon (1,n,C); sf-SortInter Subalgoritmul Ordon (St,Dr,A) este: {Sortare prin interclasare} {Adaug val} {n vectorul Z cu} {k componente i} {mrete ind cu 1}

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

Dac St < Dr atunci Fie m:=(St+Dr) Div 2; Cheam Ordon (St,m,A); Cheam Ordon (m+1,Dr,A); Cheam Inter (St,m, m+1,Dr); sfdac sf-Ordon Subalgoritmul 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 4.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.

22

La aceste interclasri, pentru a efectua un numr ct mai mic de operaii de transfer se recomand interclasarea coleciilor de dimensiuni minime, apoi din datele obinute din nou vor fi alese dou colecii de dimensiuni minime i aa mai departe pn se obine o singur colecie care va fi colecia cerut, adic sortat. Dup metodele de sortare extern folosite, se descriu trei procedee de sortare extern: - sortarea echilibrat; sortarea polifazic; 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.

23

Vous aimerez peut-être aussi