VALERIU LUPU

ALGORITMI. TEHNICI ŞI LIMBAJE DE PROGRAMARE

EDITURA UNIVERSITĂŢII “ŞTEFAN cel MARE” SUCEAVA 2007

3

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

4

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 Evoluţia 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 – Aplicaţii ...........................................................................................109 ....................................................................................................................................135

5

Aceasta înseamnă că fiecare pas din execuţia algoritmului dă rezultate bine determinate şi precizează în mod unic pasul următor. Termenul de program (programare) a suferit schimbări în scurta istorie a informaticii. Calculatoarele pot fi folosite pentru a rezolva probleme. la efectul execuţiei lui. Rezultatele obţinute fac parte dintr-un domeniu R. pornind de la aceeaşi informaţie admisibilă x∈D. Prin finitudine se înţelege că textul algoritmului este finit. chiar imposibilă fără a introduce şi alte noţiuni. Algoritmii au următoarele caracteristici: generalitate. vom observa că fiecare algoritm defineşte o funcţie matematică. din toate secţiunile următoare va reieşi foarte clar că un algoritm este scris pentru rezolvarea unei probleme. 6 . finitudine şi unicitate. problema s-ar putea să nu aibă sens pentru orice date iniţiale.limbajul schemelor logice. Prin program se înţelegea rezultatul scrierii unui algoritm într-un limbaj de programare. Deci un algoritm A nu rezolvă problema P cu nişte date de intrare. Din mai multe exemple se va observa însă că. oricare ar fi aceste date. În descrierea algoritmilor se folosesc mai multe limbaje de descriere. algoritmul de rezolvare a unui sistem liniar de n ecuaţii cu n necunoscute prin metoda lui Gauss. A) şi rezultate care se cer a fi găsite (date finale). Vom încerca în continuare o descriere a ceea ce se înţelege prin algoritm. Prin anii '60 problemele rezolvate cu ajutorul calculatorului erau simple şi se găseau algoritmi nu prea complicaţi pentru rezolvarea lor. transformările prin care se trece şi rezultatele obţinute sunt aceleaşi. Vom spune că datele pentru care problema P are sens fac parte din domeniul D al algoritmului A. ori de câte ori am executa algoritmul. Dar ce este un algoritm? O definiţie matematică. Evident. Cel mai vechi exemplu este algoritmul lui Euclid. astfel că executând algoritmul A cu datele de intrare x∈D vom obţine rezultatele r∈R. Fiecare propoziţie a limbajului precizează o anumită regulă de calcul. Vom spune că A(x)=r şi astfel algoritmul A defineşte o funcţie A : D ---> R . algoritm care determină cel mai mare divizor comun a două numere naturale. vom prezenta mai mulţi algoritmi. un astfel de limbaj este numit limbaj de descriere a algoritmilor. programare Apariţia primelor calculatoare electronice a constituit un salt uriaş în direcţia automatizării activităţii umane. Nu există astăzi domeniu de activitate în care calculatorul să nu îşi arate utilitatea[18]. Ne vom familiariza cu această noţiune prezentând mai multe exemple de algoritmi şi observând ce au ei în comun. Din cauza creşterii complexităţii problemelor. dintre care cele mai des folosite sunt: . există mai mulţi algoritmi. Altfel spus. Din cauză că este inventat special în acest scop. Oprindu-ne la semnificaţia algoritmului. program.CAPITOLUL I DESCRIEREA ALGORITMILOR 1. Prin unicitate se înţelege că toate transformările prin care trece informaţia iniţială pentru a obţine rezultatul r∈R sunt bine determinate de regulile algoritmului.1 Algoritm. o secvenţă finită de propoziţii ale unui limbaj. riguroasă. Pentru fiecare problemă P există date presupuse cunoscute (date iniţiale pentru algoritmul corespunzător. De asemenea. numai dacă pentru rezolvarea acestora se concep programe corespunzătoare de rezolvare. Vom constata că un algoritm este un text finit. astăzi pentru rezolvarea unei probleme adesea vom concepe un sistem de mai multe programe. rezolvă orice sistem liniar şi nu un singur sistem concret. Evident. Astfel. Mai mult. compus dintr-un număr finit de propoziţii. Prin generalitate se înţelege faptul că un algoritm este aplicabil pentru orice date iniţiale x∈D. cei mai mulţi fiind legaţi de probleme accesibile absolvenţilor de liceu. pentru rezolvarea aceleaşi probleme. este greu de dat. ci o rezolvă în general. numărul transformărilor ce trebuie aplicate unei informaţii admisibile x∈D pentru a obţine rezultatul final corespunzător este finit. aşa cum se va observa atunci când vom prezenta limbajul Pseudocod.

1.2. iar blocul Tipăreşte va preciza rezultatele obţinute (la execuţia pe calculator cere afişarea pe ecran a valorilor expresiilor din lista de ieşire). Blocurile de intrare/ieşire Citeşte şi Tipăreşte (Fig. Fig. precum şi alte rezultate intermediare necesare în rezolvarea problemei.1.2.2 Scheme logice Schema logică este un mijloc de descriere a algoritmilor prin reprezentare grafică. Ele permit precizarea datelor iniţiale cunoscute în problemă şi tipărirea rezultatelor cerute de problemă. o valoare. a şi 1.limbajul Pseudocod. Valorile pe care le poate lua variabila aparţin unei mulţimi D pe care o vom numi domeniul variabilei.1. Ea are un nume şi. Blocurile schemelor logice 7 .. În concluzie vom înţelege prin variabilă tripletul (nume. Descrierea unui algoritm prin schemă logică va începe cu un singur bloc Start şi se va termina cu cel puţin un bloc Stop.2. cât şi rezultatele dorite. unei variabile var i se atribuie valoarea calculată a unei expresii expr (Fig. iar ordinea lor de aplicare (succesiunea operaţiilor) este indicată prin săgeţi. Variabila defineşte o mărime care îşi poate schimba valoarea în timp.2. Este posibil ca variabila încă să nu fi primit valoare. În descrierea unui algoritm. c şi d) indică introducerea unor Date de intrare respectiv extragerea unor Rezultate finale. eventual. Regulile de calcul ale algoritmului sunt descrise prin blocuri (figuri geometrice) reprezentând operaţiile (paşii) algoritmului. 1. care se mai folosesc în manualele de liceu.1. 1. Întrucât variabila joacă un rol central în programare este bine să definim acest concept. Prezentăm însă şi schemele logice. Blocul Citeşte iniţializează variabilele din lista de intrare cu valori corespunzătoare. în ordinea indicată de săgeţi. Printr-o astfel de operaţie. Fiecărui tip de operaţie îi este consacrată o figură geometrică (un bloc tip) în interiorul căreia se va înscrie operaţia din pasul respectiv. Blocurile de atribuire (calcul) se utilizează în descrierea operaţiilor de atribuire (:=). intervin variabile care marchează atât datele cunoscute iniţial. valoare) unde valoare aparţine mulţimii D ∪ {nedefinit}. întrucât cu ajutorul lor vom preciza în continuare semantica propoziţiilor Pseudocod. situaţie în care vom spune că ea este neiniţializată. e). b) vor marca începutul respectiv sfârşitul unui algoritm dat printr-o schemă logică. deci şi într-o schemă logică.1.2. domeniul D.1. În ultima vreme schemele logice sunt tot mai puţin folosite în descrierea algoritmilor şi nu sunt deloc potrivite în cazul problemelor complexe. Prin execuţia unui algoritm descris printr-o schemă logică se înţelege efectuarea tuturor operaţiilor precizate prin blocurile schemei logice.1. În continuare vom folosi pentru descrierea algoritmilor limbajul Pseudocod care va fi definit în cele ce urmează.1. Blocurile delimitatoare Start şi Stop (Fig.

2. Va calcula apoi discriminantul d şi va continua în funcţie de valoarea lui d. 1. Partea care calculează suma S cerută are un bloc pentru iniţializarea 8 . Fig.2. Fig.1. Algoritm pentru rezolvarea ecuaţiei de gradul doi Fig.2. dacă din diverse motive s-au efectuat astfel de întreruperi (Fig. Metoda de rezolvare a ecuaţiei de gradul doi este cunoscută. Condiţia care se va înscrie în blocul de decizie logic va fi o expresie logică a cărei valoare poate fi una dintre valorile "adevărat" sau "fals".1. respectiv complexe.4ac. care precizează datele cunoscute în problemă.g).h).2. care poate fi negativă. corespunzătoare unor algoritmi pentru rezolvarea problemelor P1.2.2. Fig.2. Blocurile de conectare marchează întreruperile săgeţilor de legătură dintre blocuri.1. Să se calculeze suma elementelor pozitive ale unui şir de numere reale dat.2.2. Schema logică (dată în Fig.1.1. situaţie recunoscută după semnul discriminantului d = b2 .1 şi P1.1. Blocul de decizie aritmetic va hotărî ramura de continuare a algoritmului în funcţie de semnul valorii expresiei aritmetice înscrise în acest bloc. Ramificarea poate fi dublă (blocul logic. aşa cum se poate vedea în fig.f) sau triplă (blocul aritmetic. Să se rezolve ecuaţia de grad doi aX2+bX+c=0 (a.2. marcate prin variabilele a.2. b şi c. P1.1. înaintea blocului STOP.2. Ecuaţia poate avea rădăcini reale.2.b. Blocul de decizie logic indică ramura pe care se va continua execuţia algoritmului în funcţie de îndeplinirea (ramura Da) sau neîndeplinirea (ramura Nu) unei condiţii. Algoritmul de rezolvare a problemei va citi mai întâi datele problemei. P1.2.3) va conţine imediat după blocul START un bloc de citire.c∈R _i a≠ 0).2.3.1.Blocurile de decizie marchează punctele de ramificaţie ale algoritmului în etapa de decizie.1. apoi o parte care calculează suma cerută şi un bloc de tipărire a sumei găsite. Pentru exemplificare vom da în continuare două scheme logice. Algoritm pentru calculul unei sume. nulă sau pozitivă.1.

1 şi vor fi prezentate în continuare. Propoziţiile standard ale limbajului Pseudocod folosite în această lucrare. în acest capitol vom scrie cuvintele cheie cu litere mari.1. Pentru această parcurgere se foloseşte o variabilă contor i. Acestea sunt considerate elemente nefinisate din algoritm. după Djikstra). în textul algoritmului vom mai introduce propoziţii explicative. Deci limbajul Pseudocod are două tipuri de propoziţii: propoziţii standard. De asemenea. Pe lângă aceste propoziţii standard şi nestandard.1. Prin execuţia unui algoritm descris în Pseudocod se înţelege efectuarea operaţiilor precizate de propoziţiile algoritmului. deci cele în interiorul cărora se află alte propoziţii. Structura secvenţială (fig. Pentru a le distinge de celelalte propoziţii. asupra cărora trebuie să se revină şi le vom numi propoziţii nestandard. numite comentarii. propoziţiile nestandard sunt texte care descriu părţi ale algoritmului încă incomplet elaborate. care vor fi executate în ordinea întâlnirii lor în text. prin A. în etapele intermediare din obţinerea algoritmului vom folosi propoziţii curente din limba română.1. asupra cărora urmează să se revină. Menţionăm că şi propoziţiile simple se termină cu caracterul '.3. putând avea loc reveniri în orice punct din schema logică. Aşa cum se va arăta mai târziu. ale limbajului Pseudocod. care este iniţializată cu 1 şi creşte mereu cu 1 pentru a atinge valoarea n. În figura 1.3. Structurile elementare de calcul 9 .1. Schemele logice dau o reprezentare grafică a algoritmilor cu ajutorul unor blocuri de calcul.' în timp ce propoziţiile compuse. aşa cum se va vedea în cele ce urmează. Din acest motiv se poate obţine o schemă logică încâlcită. Pentru a deosebi aceste cuvinte de celelalte denumiri. a) structura secvenţială b) structura c) structura alternativă repetitivă Figura 1. Limbajul PSEUDOCOD Limbajul Pseudocod este un limbaj inventat în scopul proiectării algoritmilor şi este format din propoziţii asemănătoare propoziţiilor limbii române. B s-au notat subscheme logice.3.3. comentariile vor fi închise între acolade. Fiecare propoziţie standard începe cu un cuvânt cheie. care să conţină numai anumite structuri standard de calcul şi în care drumurile de la START la STOP să fie uşor de urmărit. asemenea oricărui text al limbii române. Ţinând seama că obţinerea unui algoritm pentru rezolvarea unei probleme nu este întotdeauna o sarcină simplă. care vor fi prezentate fiecare cu sintaxa şi semnificaţia (semantica) ei şi propoziţii nestandard. nefinisate. indicele ultimului număr dat. x2…xn şi adunarea celor pozitive la suma S. au un marcaj de sfârşit propriu. Rezultă importanţa compunerii unor scheme logice structurate (D-scheme. că în acest scop sunt folosite anumite metode pe care le vom descrie în capitolele următoare. Acesta va fi limbajul folosit de noi în proiectarea algoritmilor şi va fi definit în cele ce urmează. în ordinea citirii lor.3. Rolul lor va fi explicat puţin mai târziu. Execuţia urmează sensul indicat de săgeată.cu 0 a acestei sume. apoi blocuri pentru parcurgerea numerelor: x1. simple sau compuse. greu de urmărit. menţionăm că propoziţiile limbajului Pseudocod vor fi luate în seamă în ordinea întâlnirii lor în text. adică secvenţe de oricâte structuri construite conform celor trei reguli menţionate în continuare. construite de programator.a) este redată prin concatenarea propoziţiilor. care corespund structurilor de calcul folosite în construirea algoritmilor. corespund structurilor de calcul prezentate în figura 1. 1.

2. în cazul ind=1. care se va reflecta prin propoziţii REZULTATE.c este redată în Pseudocod prin propoziţia CÂT TIMP.x2.3. adică enunţarea riguroasă a acestora. ci doar faptul că ecuaţia nu are rădăcini reale.1.Propoziţiile simple din limbajul Pseudocod sunt CITEŞTE. Cunoaşterea acestora.1.2. care va fi reflectată printr-o propoziţie DATE şi cunoaşterea exactă a cerinţelor problemei. 0=complexe} x1. În etapa de 10 . unde listă conţine toate numele variabilelor a căror valoare iniţială este cunoscută. iar structura repetitivă din fig. Specificarea unei probleme este o activitate foarte importantă dar nu şi simplă.c.b.x2. adică nu avem scrisă specificarea problemei. { Coeficienţii ecuaţiei } REZULTATE x1. { Rădăcinile ecuaţiei } Această specificaţie este însă incompletă dacă ecuaţia nu are rădăcini reale. Evident. TIPAREŞTE. Deci pentru cunoaşterea unei probleme este necesară precizarea variabilelor care marchează date considerate cunoscute în problemă.3. Acum putem preciza mai exact ce înţelegem prin cunoaşterea completă a problemei de rezolvat. De exemplu. în dreapta acestui cuvânt se vor scrie acele variabile care marchează mărimile cunoscute în problemă. Structura alternativă (fig. în construcţia "listă" ce urmează după cuvântul REZULTATE fiind trecute numele variabilelor care marchează (conţin) rezultatele cerute în problemă. prin listă se înţelege o succesiune de elemente de acelaşi fel despărţite prin virgulă.3.3. Deci specificaţia corectă a problemei va fi DATE a. Bohm şi Jacopini au demonstrat că orice algoritm poate fi descris folosind numai aceste trei structuri de calcul. nu ne interesează valoarea rădăcinilor în acest caz.} {respectiv partea reală şi cea } {imaginară în cazul ind=0} Evident că specificarea problemei este o etapă importantă pentru găsirea unei metode de rezolvare şi apoi în proiectarea algoritmului corespunzător. prezentată în secţiunea 1.3. Propoziţia DATE se foloseşte pentru precizarea datelor iniţiale. prezentată în secţiunea 1. specificarea problemei.b.3. scrisă de un începător.c. {Un indicator: 1=rădăcini reale. Sau pur şi simplu. Deci în propoziţia DATE.1. pentru rezolvarea ecuaţiei de gradul al doilea.b) este redată în Pseudocod prin propoziţia DACĂ. Propoziţiile DATE şi REZULTATE sunt folosite în faza de specificare a problemelor. presupuse cunoscute. fie el ind. Variabilele prezente în aceste propoziţii au anumite semnificaţii. FIE şi apelul de subprogram. { Coeficienţii ecuaţiei } REZULTATE ind. Cu alte cuvinte avem nevoie de un mesaj care să ne indice această situaţie (vezi schema logică 1. x2 partea reală respectiv partea imaginară a rădăcinilor. scrierea lor explicită. Nu se poate rezolva o problemă dacă aceasta nu este bine cunoscută.2). o problemă este cunoscută atunci când se ştie care sunt datele cunoscute în problemă şi ce rezultate trebuiesc obţinute. În cazul în care rădăcinile sunt complexe putem nota prin x1.1 Algoritmi liniari Propoziţiile CITEŞTE şi TIPĂREŞTE sunt folosite pentru iniţializarea variabilelor de intrare cu datele cunoscute în problemă. poate fi: DATE a. { Rădăcinile ecuaţiei. Propoziţiile compuse corespund structurilor alternative şi repetitive.1. 1. deci a datelor considerate cunoscute în problemă (numite şi date de intrare) şi are sintaxa: DATE listă. formează ceea ce vom numi în continuare specificarea problemei. În general. sau de un indicator. Cunoaşte complet problema este prima regulă ce trebuie respectată pentru a obţine cât mai repede un algoritm corect pentru rezolvarea ei. Acest indicator va lua valoarea 1 dacă rădăcinile sunt reale şi valoarea 0 în caz contrar. respectiv pentru tipărirea (aflarea) rezultatelor obţinute. Pentru precizarea rezultatelor dorite se foloseşte propoziţia standard REZULTATE listă.

Pentru aflarea rezultatelor dorite. Atunci când vom scrie succesiv mai multe propoziţii de atribuire vom folosi cuvântul FIE numai în prima propoziţie. înmulţire şi împărţire (notate prin caracterele +. V = Viteza } CITEŞTE D. cunoscută din manualele de matematică din liceu şi construită cu cele patru operaţii: adunare. pe care calculatorul o va face prin tipărirea lor pe hârtie sau afişarea pe ecran. -. El s-a folosit cu gândul ca fiecare propoziţie să înceapă cu un cuvânt al limbii române care să reprezinte numele propoziţiei. în dreapta acestui cuvânt se vor scrie acele variabile care apar în propoziţia DATE în specificarea problemei. unde listă conţine toate numele variabilelor a căror valoare iniţială este cunoscută. Expresia din dreapta semnului de atribuire poate fi orice expresie algebrică simplă. De cele mai multe ori vom omite acest cuvânt. scădere. Se subînţelege că aceste variabile sunt iniţializate cu valorile cunoscute corespunzătoare. Evident că o expresie în care apar variabile care nu au valori nu poate fi calculată. Prin scrierea cuvântului FIE între paranteze drepte se indică posibilitatea omiterii acestui cuvânt din propoziţie. ALGORITMUL VITEZA ESTE: { A1: Calculează viteza } { D = Distanţa (spaţiul) } { T = Timpul. Blocului de atribuire dintr-o schemă logică îi corespunde în Pseudocod propoziţia standard [FIE] var := expresie . Propoziţia CITEŞTE se foloseşte pentru precizarea datelor iniţiale. specificate şi în propoziţia REZULTATE. O greşeală frecventă pe care o fac începătorii este folosirea variabilelor neiniţializate. Ele sunt de obicei rezultatele cerute în problemă. De asemenea. *. Deci în propoziţia CITEŞTE. Deci nu folosiţi variabile neiniţializate. Algoritmii care pot fi descrişi folosind numai propoziţiile prezentate mai sus se numesc algoritmi liniari. se foloseşte propoziţia standard TIPĂREŞTE listă .programare propriu-zisă acestor propoziţii le corespund într-un limbaj de programare instrucţiuni de intrare-ieşire. TIPĂREŞTE V SFALGORITM 11 . omiţându-l în celelalte. Pentru a marca începutul descrierii unui algoritm vom folosi propoziţia: ALGORITMUL nume ESTE: fără a avea o altă semnificaţie. { v:= spaţiu/timp } FIE V:=D/T. în construcţia listă ce urmează după cuvântul TIPĂREŞTE fiind trecute numele variabilelor a căror valori dorim să le aflăm. Ca exemplu de algoritm liniar prezentăm un algoritm ce determină viteza v cu care a mers un autovehicul ce a parcurs distanţa D în timpul T. ea nu este definită. Din cele scrise mai sus rezultă că o variabilă poate fi iniţializată atât prin atribuire (deci dacă este variabila din stânga semnului de atribuire :=) cât şi prin citire (când face parte din lista propoziţiei CITEŞTE).T. Această propoziţie este folosită pentru a indica un calcul algebric. al expresiei care urmează după simbolul de atribuire ":=" şi de atribuire a rezultatului obţinut variabilei var. deci a datelor considerate cunoscute în problemă (numite şi date de intrare) şi are sintaxa: CITEŞTE listă . respectiv /). prin cuvântul SFALGORITM vom marca sfârşitul unui algoritm.

Aceste calcule sunt redate de structura alternativă prezentată în figura 1. DACĂ i=vn ATUNCI An SFDACĂ . Ele cer mai întâi verificarea condiţiei scrise după cuvântul DACĂ. Ajungem uşor la algoritmul dat în continuare.3. x1:=. Indiferent care dintre secvenţele A sau B a fost executată. .b. FIE delta:=b*b.4*a*c.2 Algoritmi cu ramificaţii Foarte mulţi algoritmi execută anumite calcule în funcţie de satisfacerea unor condiţii. x2:=r/(a+a). . Am scris mai sus specificaţia acestei probleme şi am precizat semnificaţia variabilelor respective.b. ALTFEL ind:=1.x2. O generalizare a structurii alternative realizată de propoziţia DACĂ este structura selectivă: SELECTEAZĂ i DINTRE v1: A1. . Pe lângă aceste variabile. vn: An SFSELECTEAZĂ structură echivalentă cu următorul text Pseudocod: DACĂ i=v1 ATUNCI A1 ALTFEL DACĂ i=v2 ATUNCI A2 ALTFEL .delta).c = Coeficienţii ecuaţiei } { rădăcini complexe } { rădăcini reale } ..b. r . căreia îi corespunde propoziţia Pseudocod DACĂ cond ATUNCI A ALTFEL B SFDACĂ sau varianta redusă a ei. pentru rezolvarea problemei mai avem nevoie de două variabile auxiliare: delta . În caz că această condiţie este adevărată se va executa grupul de propoziţii A. . x1. dacă este prezentă ramura ALTFEL. DACĂ cond ATUNCI A SFDACĂ folosită în cazul în care grupul de propoziţii B este vid.1. DACĂ delta<0 ATUNCI ind:=0. r:=radical din delta. ALGORITMUL ECGRDOI ESTE: CITEŞTE a. SFDACĂ TIPĂREŞTE ind.pentru a reţine valoarea radicalului folosit în exprimarea rădăcinilor. x2:=(-b+r)/(a+a). Aceştia se numesc algoritmi cu ramificaţii.r)/(a+a).1. Ca exemplu vom scrie un algoritm pentru rezolvarea ecuaţiei de gradul al doilea.3. SFALGORITM 12 { Algoritmul 2: Rezolvarea } { ecuaţiei de gradul doi } { a. În cazul în care această condiţie este falsă se va executa grupul de propoziţii B.b/(a+a). v2: A2. r:=radical din (. Aceste propoziţii redau în Pseudocod structura alternativă de calcul.c. se va continua cu propoziţia următoare propoziţiei DACĂ. x1:=(-b. SFDACĂ SFDACĂ Cu propoziţiile prezentate până aici putem deja descrie destui algoritmi. .pentru a reţine discriminantul ecuaţiei..

Semnificaţia propoziţiei PENTRU este clară.p] EXECUTĂ A SFPENTRU Ea defineşte structura repetitivă predefinită. cu pasul p. Dacă ea este falsă execuţia propoziţiei se termină şi se continuă cu propoziţia care urmează după SFCÂT. ALGORITMUL Euclid ESTE: {A3: Cel mai mare divizor comun} CITEŞTE n1. O altă propoziţie care cere execuţia repetată a unei secvenţe A este propoziţia PENTRU c:=li .3 Algoritmi ciclici În rezolvarea multor probleme trebuie să efectuăm aceleaşi calcule de mai multe ori. Mai exact.3. această structură se mai numeşte structură repetitivă condiţionată anterior. 13 . putând să lipsească. Prin aceasta indicăm faptul că el este opţional. Alte calcule trebuiesc repetate în funcţie de satisfacerea unor condiţii. REPETĂ şi PENTRU. În acest scop în limbajul Pseudocod există trei propoziţii standard: CÂTTIMP.n2. Se subînţelege că nu trebuie să modificăm valorile contorului în nici o propoziţie din grupul A. încălcând semnificaţia propoziţiei PENTRU.1. pasul p este închis între paranteze drepte. De multe ori aceste expresii sunt variabile simple. Dacă de prima dată condiţia este falsă grupul A nu se va executa niciodată. în funcţie de condiţia "cond". dacă aceasta este adevărată se execută grupul A şi se revine la evaluarea condiţiei. Ca exemplu de algoritm în care se foloseşte această propoziţie dăm algoritmul lui Euclid pentru calculul celui mai mare divizor comun a două numere. pentru a calcula suma a două matrice va trebui să adunăm un element al primei matrice cu elementul de pe aceeaşi poziţie din a doua matrice. final:=lf . în sintaxa propoziţiei PENTRU. altfel se va repeta execuţia grupului de propoziţii A până când condiţia va deveni falsă. {Cele două numere a căror divizor se cere} FIE d:=n1. În cazul în care nu este prezent. sau să repetăm calcule asemănătoare. Ea cere repetarea grupului de propoziţii A pentru toate valorile contorului c cuprinse între valorile expresiilor li şi lf (calculate o singură dată înainte de începerea ciclului). Deoarece condiţia se verifică după prima execuţie a grupului A această structură este numită structura repetitivă condiţionată posterior. Va avea loc repetarea execuţiei lui A până când condiţia devine adevărată. prima execuţie a blocului A fiind necondiţionată. valoarea lui implicită este 1. d:=i. această adunare repetându-se pentru fiecare poziţie. nu recalcula limitele şi nu modifica variabila de ciclare (contorul) în interiorul unei structuri repetitive PENTRU). REPETĂ A c:=c+p PÂNĂCÂND (c>final şi p>0) sau (c<final şi p<0) SFREP Se observă că. De exemplu. CÂTTIMP i≠ 0 EXECUTĂ r:=d modulo i.1. Propoziţia CÂTTIMP are sintaxa CÂTTIMP cond EXECUTĂ A SFCÂT i cere execuţia repetată a grupului de propoziţii A. i:=n2. iar unii programatori modifică în A valorile acestor variabile. Deci. Ea reprezintă structura repetitivă prezentată în figura 1. i:=r SFCÂT TIPĂREŞTE d. cu un număr determinat de execuţii ale grupului de propoziţii A şi este echivalentă cu secvenţa c:=li .3.c.lf [. se evaluează condiţia "cond". { d= cel mai mare divizor comun al } SFALGORITM { numerelor n1 şi n2 } În descrierea multor algoritmi se întâlneşte structura repetitivă condiţionată posterior: REPETĂ A PÂNĂ CÂND cond SFREP structură echivalentă cu: CÂTTIMP not(cond) EXECUTĂ A SFCÂT Deci ea cere execuţia necondiţionată a lui A şi apoi verificarea condiţiei "cond". Din cauză că înainte de execuţia grupului A are loc verificarea condiţiei.

Să observăm, de asemenea, că prima execuţie a grupului A este obligatorie, abia după modificarea contorului verificându-se condiţia de continuare a execuţiei lui A. Ca exemplu, să descriem un algoritm care găseşte minimul şi maximul componentelor unui vector de numere reale. Vom nota prin X acest vector, deci X = (x1, x2, ... , xn) . Specificaţia problemei este următoarea: DATE n,(xi ,i=1,n); REZULTATE valmin,valmax; iar semnificaţia acestor variabile se înţelege din cele scrise mai sus. Pentru rezolvarea problemei vom examina pe rând cele n componente. Pentru a parcurge cele n componente avem nevoie de un contor care să precizeze poziţia la care am ajuns. Fie i acest contor. Uşor se ajunge la următorul algoritm: ALGORITMUL MAXMIN ESTE { Algoritmul 5: Calculul } { valorii minime şi maxime } CITEŞTE 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 TIPĂREŞTE valmin,valmax; SFALGORITM Un rol important în claritatea textului unui algoritm îl au denumirile alese pentru variabile. Ele trebuie să reflecte semnificaţia variabilelor respective. Deci alege denumiri sugestive pentru variabile, care să reflecte semnificaţia 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 execuţiei algoritmului, fiecare variabilă are o anumită valoare, sau este încă neiniţializată. Vom numi stare a algoritmului A cu variabilele menţionate vectorul s = ( s1,s2,...,sn ) format din valorile curente ale celor n variabile ale algoritmului. Este posibil ca variabila Xj să fie încă neiniţializată, deci să nu aibă valoare curentă, caz în care sj este nedefinită, lucru notat în continuare prin semnul întrebării '?'. Prin executarea unei anumite instrucţiuni unele variabile îşi schimbă valoarea, deci algoritmul îşi schimbă starea. Se numeşte calcul efectuat de algoritmul A o secvenţă de stări s0, s1, s2, ..., sm unde s0 este starea iniţială cu toate variabilele neiniţializate, iar sm este starea în care se ajunge după execuţia ultimei propoziţii din algoritm. 1.5 Rafinare în paşi 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 iniţial era neclar. Observaţia este adevărată mai ales în cazul problemelor complicate, dar şi pentru probleme mai simple în procesul de învăţământ. Este vorba de un proces de detaliere pas cu pas a specificaţiei problemei, proces denumit şi proiectare descendentă, sau rafinare în paşi succesivi. Algoritmul apare în mai multe versiuni succesive, fiecare versiune fiind o detaliere a versiunii precedente. În versiunile iniţiale apar propoziţii nestandard, clare pentru cititor, dar
14

neprecizate prin propoziţii standard. Urmează ca în versiunile următoare 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: amână pe mai târziu detaliile nesemnificative; concentrează-ţi atenţia 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 propoziţia standard SUBPROGRAMUL nume (lpf) ESTE: unde nume este numele SUBPROGRAMului definit, iar lpf este lista parametrilor formali. Aceştia sunt formaţi din variabilele care marchează datele de intrare (cele presupuse cunoscute) şi variabilele care marchează datele de ieşire (rezultatele obţinute de SUBPROGRAM). Această propoziţie este urmată de textul efectiv al SUBPROGRAMului, text care precizează calculele necesare rezolvării subproblemei corespunzătoare. Descrierea se va încheia cu cuvântul SFSUBPROGRAM sau SF-nume. Dăm ca exemplu un SUBPROGRAM cu numele MAXIM, care găseşte maximul dintre componentele vectorului X = (x1,x2, ..., xn). Datele cunoscute pentru acest SUBPROGRAM sunt vectorul X şi numărul n al componentelor vectorului X. Ca rezultat vom obţine maximul cerut, pe care-l vom nota cu max. Deci lista parametrilor formali conţine 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 funcţii în diferite puncte. Este necesar să definim funcţia printr-un SUBPROGRAM de tip funcţie. Pentru definirea unui SUBPROGRAM de tip funcţie se foloseşte un antet care precizează numele funcţiei şi variabilele de care depinde ea. SUBPROGRAMul are forma: FUNCŢIA nume(lpf) ESTE: {Antetul funcţiei} text {corpul funcţiei} SF-nume {marca de sfârşit} În corpul funcţiei trebuie să existe cel puţin o atribuire în care numele funcţiei apare în partea stângă, deci prin care funcţia primeşte o valoare. Dăm ca exemplu o funcţie numar : R --> {2,3,4,5}, definită matematic astfel: În Pseudocod descrierea este următoarea: FUNCŢIA 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

dăm în continuare un program pentru a calcula a câta zi din anul curent este ziua curentă (zi.NRZILE(i) furnizează numărul zilelor existente în luna i a unui an nebisect. fiind algoritmi de sine stătători. În încheiere menţionăm că subprogramele de tip funcţie se folosesc în scopul definirii funcţiilor. Folosirea unui SUBPROGRAM în cadrul unui algoritm se face apelând acest SUBPROGRAM prin propoziţia standard CHEAMĂ nume (lpa). cărora li se mai spune şi proceduri. ca şi în cazul funcţiilor.BISECT(an) adevărată dacă anul dintre paranteze este bisect. unde nume este numele SUBPROGRAMului apelat iar lpa este lista parametrilor actuali. Trebuie să existe o corespondenţă biunivocă între parametrii actuali şi cei formali folosiţi în definiţia funcţiei.Am văzut că definiţia unei funcţii constă dintr-un antet şi dintr-un bloc care va defini acţiunile prin care se calculează valoarea funcţiei. Şi în acest caz între lista parametrilor formali din definiţia SUBPROGRAMului şi lista parametrilor actuali din propoziţia de apel trebuie să existe o corespondenţă biunivocă. există două categorii de SUBPROGRAMi: de tip funcţie şi SUBPROGRAMi propriu-zişi. Mai exact. ci doar specificarea acestor SUBPROGRAMi. rolul variabilelor care se corespund este acelaşi. . În antet se precizează numele funcţiei şi lista parametrilor formali. Algoritmul este următorul: ALGORITMUL NUMĂRĂZILE ESTE: CITEŞTE zi. DACĂ luna>1 ATUNCI PENTRU i:=1. SFALGORITM Să observăm că în proiectarea acestui algoritm nu este necesar să cunoaştem textul SUBPROGRAMilor folosiţi. numele lor şi lista parametrilor formali. Deşi denumirile variabilelor din cele două liste pot să difere.an). Importanţa lor va fi subliniată prin toate exemplele care urmează în acest curs. Aceste două funcţii sunt: . FIE nr:=zi. aşa cum sunt cunoscute ele din matematică. Algoritmul corespunzător problemei C va folosi toate operaţiile necesare rezolvării problemei S. Ca exemplu de apelare a funcţiilor. Putem considera că în timpul execuţiei algoritmului cei doi parametri devin identici. 17 . Spunem că el va apela acest SUBPROGRAM. El foloseşte un subprogram de tip funcţie pentru a obţine numărul zilelor lunii cu numărul de ordine i şi un altul pentru a verifica dacă un an este bisect sau nu. La acest nivel accentul trebuie să cadă pe proiectarea algoritmului care apelează. În Pseudocod apelul unei funcţii se face scriind într-o expresie numele funcţiei urmat de lista parametrilor actuali. în timp ce SUBPROGRAMii de tip procedură se referă la rezolvarea unor probleme ce apar ca subprobleme. Luna-1 EXECUTĂ nr:=nr+NRZILE(i) SFPENTRU SFDACĂ DACĂ luna>2 ATUNCI DACĂ BISECT(an) ATUNCI nr:=nr+1 SFDACĂ SFDACĂ TIPĂREŞTE nr. an. Această listă conţine toate datele de intrare (cele cunoscute în subproblema corespunzătoare) şi toate rezultatele obţinute în SUBPROGRAM. subliniem că numărul parametrilor actuali trebuie să coincidă cu numărul parametrilor formali. să reprezinte aceeaşi structură de date. În concluzie. deci va folosi ca parte întregul SUBPROGRAM conceput pentru rezolvarea subproblemei S. trebuie să aibă aceeaşi semnificaţie. parametrul formal şi parametrul actual corespunzător trebuie să se refere la aceeaşi entitate. luna. Apelul unui SUBPROGRAM Am văzut că un SUBPROGRAM este dedicat rezolvării unei subprobleme S a unei probleme mai complexe C. Ca o primă verificare a respectării acestei corespondenţe.luna.

SUBPROGRAMUL SUMAPOL1(n.r. .n. O astfel de procedură se dă în continuare.. cea dată de polinomul Q. p1.r. S:=P. CHEAMĂ SUMAPOL1(m. . bn } C = { c1. deci au aceeaşi semnificaţie. S. SUBPROGRAMUL SUMAPOL(m. În rezolvarea acestei probleme se întâlnesc următoarele subprobleme: S1: Să se citească elementele unei mulţimi..Q..P. m.P.. conform specificaţiei acestora. Un polinom P(X) este dat prin gradul său.. de grad mai mic sau egal decât gradul polinomului S(X).r. a2. cp } Se cere să se tipărească în ordine crescătoare elementele fiecărei mulţimi.P. aşa cum se poate vedea în continuare.r. Subliniem că atribuirea v := u va fi corectă în cazul în care variabilele u şi v reprezintă aceleaşi obiecte matematice. unde P este un polinom de gradul m.S) trebuie să efectueze suma S(X) = P(X)+Q(X). . Pentru efectuarea ei este utilă o altă procedură care adună la suma S(X) un alt polinom. .. Alte exemple Ca un al doilea exemplu de definire şi folosire a SUBPROGRAMilor. precum şi a mulţimilor A U B. B U C.S) ALTFEL r:=m.T. . iar Q este un polinom cunoscut.Q. CHEAMĂ SUMAPOL1(n. Ca exemplu de apelare a unei proceduri vom scrie mai jos o procedură care efectuează suma a două polinoame. C U A. S3: Să se tipărească elementele unei mulţimi. T(X)..S) ESTE: {n ≤ r} {S(X):=S(X)+T(X)} PENTRU i:=0. iar Q este un polinom de gradul n.S) ESTE: {S(X):=P(X)+Q(X)} DACĂ m<n ATUNCI r:=n. permiţând atribuirea S:=Q. şi prin vectorul coeficienţilor P = (p0. Presupunând că pentru rezolvarea acestor subprobleme am conceput SUBPROGRAMii: 18 .urmând să se revină ulterior la proiectarea SUBPROGRAMilor apelaţi.. Procedura SUMAPOL(m. date.n EXECUTĂ si := si+ti SFPENTRU SF-SUMAPOL1 SUBPROGRAMul SUMAPOL apelează acest SUBPROGRAM.Q. am } B = { b1. Acest lucru este normal întrucât S notează un polinom. S:=Q. b2. S4: Să se ordoneze crescător elementele unei mulţimi. Lăsăm această descriere ca temă pentru cititor. să considerăm următoarea problemă: Se dau trei mulţimi de numere: A = { a1. va fi un polinom de gradul r calculat în SUBPROGRAM. . pm) (prin pi s-a notat coeficientul lui Xi).S) SFDACĂ SF-SUMAPOL Să observăm că în textul acestui SUBPROGRAM am extins semnificaţia propoziţiei de atribuire. Suma lor. prin atribuire S primeşte o valoare iniţială. S2: Să se efectueze reuniunea a două mulţimi. .r. În cazul de faţă este necesară descrierea funcţiilor NRZILE(i) şi BISECT(an).n.. c2.

R).n.B.i=1.k. algoritmul de rezolvare a problemei de mai sus este dat în continuare.R).C).R). Întrucât operaţiile respective se folosesc de mai multe ori (de 3 ori). REUNIUNE(m.m2.A).mn} SF-CITMUL SUBPROGRAMUL ORDON(n.M) ESTE: REPETĂ FIE ind:=0. TIPMUL(m. CHEAMĂ CITMUL(p.k.k.R).1 EXECUTĂ DACĂ mi>mi+1 ATUNCI FIE t := mi. CHEAMĂ TIPORDON(k. CHEAMĂ CITMUL(n.m.R) ESTE: { R := A U B } { k = numărul elementelor mulţimii R } FIE k:=m. mi+1:=t. PENTRU i:=1.A).A). mi:=mi+1.A. SUBPROGRAMUL CITMUL(n.n EXECUTĂ FIE ind:=0. am definit un SUBPROGRAM TIPORDON(m... care sunt specificaţi mai jos (la locul definirii lor) prin comentarii. {n=nr.C.A. {M=mulţimea cu elementele m1.B. {Ipoteza bj nu e in A} PENTRU i:=1.A. CHEAMĂ TIPORDON(k.R).n.n..R).B). R := A. CHEAMĂ REUNIUNE(p.CITMUL(m. SFDACĂ SFPENTRU PÂNĂCÂND ind=0 SFREP SF-ORDON {Ordonează crescător cele n} {elemente ale mulţimii M} {Cazul M este ordonată} {schimbă ordinea celor} {două elemente} {Cazul M nu era ordonată} SUBPROGRAMUL REUNIUNE(m.C.C).R).B. CHEAMĂ REUNIUNE(n. CHEAMĂ REUNIUNE(m.A).k.n.n).k. CHEAMĂ TIPORDON(n.p. elementelor mulţimii} CITEŞTE (mi.B.A). ALGORITMUL OPER-MULTIMI ESTE: { A6: SUBPROGRAMi } CHEAMĂ CITMUL(m.A) care ordonează mai întâi elementele mulţimii A şi apoi le tipăreşte.. PENTRU j:=1.m EXECUTĂ DACĂ bj=ai ATUNCI ind:=1 {bj este in A} SFDACĂ SFPENTRU 19 . CHEAMĂ TIPORDON(k.M) ESTE: {Citeşte n şi M} CITEŞTE n. ind:=1. CHEAMĂ TIPORDON(p.A. ORDON(m. SFALGORITM SUBPROGRAMii apelaţi mai sus sunt definiţi în continuare.B). CHEAMĂ TIPORDON(m.

. în care aceste numere devin ordonate descrescător. SF-TIPORDON { Tipăreşte cele n elemente } { ale mulţimii M } { Ordonează şi tipăreşte } { elementele mulţimii M } Tot ca exemplu de folosire a SUBPROGRAMilor.X. vectorul acestor valori. În rezolvarea acestei probleme este necesară găsirea ordinii în care trebuiesc tipăriţi elevii în funcţie de un anumit rezultat: nota la disciplina "j". Prima subproblemă se poate specifica astfel: Dându. Am identificat prin urmare două subprobleme independente. . Primii doi parametri marchează datele presupuse cunoscute. xn. Pentru rezolvarea ei vom da un SUBPROGRAM ORDINE în care intervin trei parametri formali: . SFDACĂ SFPENTRU PANÂCÂND ind=0 SFREP SF-ORDINE A doua subproblemă se poate specifica astfel: 20 . x2.M) ESTE: CHEAMĂ ORDON(n. t:=oi+1 . PENTRU i:=1. o2.X. găsiţi ordinea o1. iar al treilea.. pentru fiecare disciplină în parte doreşte lista primilor şase elevi.. vectorul indicilor care dau ordinea dorită} PENTRU i:=1. numărul valorilor existente.DACĂ ind=0 ATUNCI k:=k+1. rk:=bj SFDACĂ SFPENTRU SF-REUNIUNE SUBPROGRAMUL TIPMUL(n.n. ..M) ESTE: PENTRU i:=1. adică x[o1] ≥ x[o2] ≥ . vom scrie un algoritm pentru rezolvarea următoarei probleme: dirigintele unei clase de elevi doreşte să obţină un clasament al elevilor în funcţie de media generală. SUBPROGRAMUL ORDINE(n. vectorul indicilor care dau ordinea dorită. sau media generală.1 EXECUTĂ DACĂ x[oi] < x[oi+1] ATUNCI FIE ind:=1.. oi+1 :=oi. numărul valorilor existente} {X. oi :=t. n EXECUTĂ oi :=i SFPENTRU REPETĂ ind:=0... rezultatele calculate de SUBPROGRAM. . on.se numerele x1. x[on] . referitoare la: (1) aflarea ordinii în care trebuie tipărite n numere pentru a le obţine ordonate.M).O) ESTE: {n.O. vectorul acestor valori} {O.. CHEAMĂ TIPMUL(n. . (2) tipărirea elevilor clasei într-o anumită ordine.M). În plus.n EXECUTĂ TIPĂREŞTE mi SFPENTRU SF-TIPMUL SUBPROGRAMUL TIPORDON(n.n.

definim în continuare o funcţie care calculează recursiv valoarea n!.n. să se tipărească numele şi mediile primilor k elevi în ordinea specificată.Dându.n reprezintă numărul elevilor clasei. NOTE. Ca exemplu. Recursivitatea constă în faptul că în definiţia funcţiei Factorial de n se foloseşte aceeaşi funcţie Factorial dar de argument n-1.NUME. {numele elevilor} NOTEi. . . Se va folosi formula n! = n. i=1. SFPENTRU SF-ALGORITM Apel recursiv În exemplele date se observă că apelul unui subprogram se face după ce el a fost definit. dat în continuare. {al elevilor} NUMEi.m EXECUTĂ CHEAMĂ ORDINE(n.1) 21 . FUNCTIA Factorial(n) ESTE: DACĂ n=0 ATUNCI Factorial:=1 ALTFEL Factorial:= n*Factorial(n.MEDII este vectorul mediilor generale. on. Algoritmul se dă în continuare: ALGORITMUL CLASAMENT ESTE: { Algoritmul 7: Ordonare} CITEŞTE m..j.NOTE. SFPENTRU SF-TIPAR Variabilele folosite pentru problema dată sunt următoarele: . NOTEi. .k EXECUTĂ Tipăreşte datele elevului de rang oi.1)! în cazul n>0 şi faptul că 0!=1. NUME.(n. {a elevului i} PENTRU j:=1.. Este important ca numărul apelurilor să fie finit. SUBPROGRAMUL TIPAR(k.MEDII. rezolvă această problemă.NUME este vectorul care reţine numele elevilor: NUMEi este numele elevului cu numărul de ordine i.NOTE este matricea notelor elevilor. CHEAMĂ TIPAR(6.O). Într-un astfel de caz spunem că apelul este recursiv. {numărul disciplinelor şi} n. CHEAMĂ TIPAR(n.j este nota elevului cu numele NUMEi la disciplina cu numărul de ordine j. O) ESTE: PENTRU i:=1. iar SUBPROGRAMul respectiv este definit recursiv. j=1. a elevilor clasei.NUME. {notele elevilor} PENTRU i:=1. deci ca procedeul de calcul descris să se termine.j SFPENTRU FIE MEDIIi:=S/m SFPENTRU CHEAMĂ ORDINE(n.n EXECUTĂ { calculează media generală} FIE S:=0. Este însă posibil ca un SUBPROGRAM să se apeleze pe el însuşi. având n linii şi m coloane. Deci funcţia Factorial se apelează pe ea însăşi. .m este numărul disciplinelor la care elevii primesc note.m.O).O)..n. .m EXECUTĂ S:=S+NOTEi. PENTRU j:=1.O).se ordinea o1. SUBPROGRAMul TIPAR. i=1.j. numele şi mediile acestora.o2.j este coloana a j-a a matricei NOTE şi reprezintă notele elevilor la disciplina j.

b) ESTE: DACĂ a<b ATUNCI MAXIM2:=b ALTFEL MAXIM2:=a SFDACĂ SF-MAXIM2 Funcţia MAXIM..xn. FUNCŢIA MAXIM2(a..SFDACĂ SF-Factorial. care calculează maximul celor n numere este următoarea: FUNCŢIA MAXIM(n.x2..X).. Ea se bazează pe funcţia MAXIM2 care calculează maximul a două numere. descrisă în continuare. xn) SFDACĂ SF-MAXIM 22 . Tot ca exemplu de apel recursiv putem descrie o funcţie ce calculează maximul a n numere x1.X) ESTE: {Calculează maximul a n numere} {X=vectorul cu numerele date} DACĂ n=1 ATUNCI MAXIM:=x1 ALTFEL MAXIM:=MAXIM2( MAXIM(n-1.

La prima descompunere accentul trebuie pus pe algoritmul (modulul) principal nu asupra subproblemelor. Ea se termină cu descrierea algoritmului principal şi a SUBPROGRAMilor menţionaţi. Avantajul principal constă în faptul că ea permite programatorului să reducă complexitatea problemei. În elaborarea unui algoritm deosebim următoarele activităţi importante: – specificarea problemei. 23 . şi să amâne detaliile pentru mai târziu. dar şi cu precizarea denumirilor şi semnificaţiilor variabilelor folosite. eventual că avem deja scrişi SUBPROGRAMi pentru rezolvarea lor. În momentul în care descompunem problema în subprobleme nu ne gândim cum se vor rezolva subproblemele ci care sunt ele şi conexiunile dintre ele. Este vorba de un proces de detaliere pas cu pas a specificaţiei. Avantajele proiectării top-down (cunoscută şi sub denumirea "Divide et impera") sunt multiple. obţinerea algoritmului principal şi a tuturor SUBPROGRAMilor apelaţi. urmând să se revină asupra detaliilor în versiunile următoare (aşa cum s-a arătat în secţiunea 1.2 Proiectarea ascendentă şi proiectarea descendentă Există două metode generale de proiectare a algoritmilor. În final. – descrierea metodei alese pentru rezolvarea problemei. Ea constă în descompunerea problemei în subprobleme. La nivel micro se doreşte obţinerea unui modul în versiune finală.CAPITOLUL III METODE DE PROIECTARE A ALGORITMILOR 3. – verificarea algoritmului obţinut.5). Deocamdată înţelegem prin modul orice SUBPROGRAM sau algoritmul principal. – proiectarea propriu-zisă. Dacă ar fi necesar să le deosebim am spune că metoda top-down se referă la nivelul macro iar metoda rafinării succesive la nivel micro. Fiecărui modul îi corespunde în arborele de programare un nod. dar şi interacţiunile dintre aceşti SUBPROGRAMi şi ordinea în care ei sunt folosiţi. denumit proiectare descendentă. Într-o versiune intermediară pot fi prezente numai părţile importante ale acestuia. fiecare fiind o detaliere a versiunii precedente. care la rândul lor pot fi descompuse în subprobleme. pe care o descompune în părţi rezolvabile separat. De obicei aceste părţi sunt subprobleme independente. La nivel macro se doreşte descompunerea unei probleme complexe în subprobleme. Proiectarea descendentă (top-down) porneşte de la problema de rezolvat. Scopul urmărit este acelaşi: concentrarea atenţiei asupra părţilor importante ale momentului şi amânarea detaliilor pentru mai târziu. Noţiunea de modul va fi definită în secţiunea următoare. Algoritmul apare în diferite versiuni succesive. În multe cărţi metoda top-down este întâlnită şi sub denumirea stepwise-refinement. ai cărui descendenţi sunt toate modulele apelate direct. Nodul corespunzător algoritmului principal este chiar nodul rădăcină. conform metodelor prezentate în secţiunile următoare. La acest nivel nu ne interesează amănunte legate de rezolvarea subproblemelor. după ce aspectele importante au fost rezolvate. Legătura dintre module se prezintă cel mai bine sub forma unei diagrame numită arbore de programare.1 Elaborarea algoritmilor Prin elaborarea (proiectarea) unui algoritm înţelegem întreaga activitate depusă de la enunţarea problemei până la realizarea algoritmului corespunzător rezolvării acestei probleme. subproblemele în care a fost descompusă fiind mai simple. 3. se va descrie SUBPROGRAMul de rezolvare al fiecărei subprobleme. Urmează să considerăm pe rând fiecare subproblemă în parte şi să proiectăm (în acelaşi mod) un SUBPROGRAM pentru rezolvarea ei. presupunem că le ştim rezolva. a căror denumire provine din modul de abordare a rezolvării problemelor: metoda descendentă şi metoda ascendentă. adică rafinare în paşi succesivi.

De asemenea. Indiferent că privim modulul ca un singur SUBPROGRAM. pe care îi asamblează în alţi SUBPROGRAMi pentru a ajunge în final la algoritmul dorit. fie program. fie o unitate de program. Un astfel de procedeu este folosit de SUBPROGRAMul Quicksort. Metoda "Divide et Impera" poate fi folosită nu numai la împărţirea problemei în subprobleme ci şi la împărţirea datelor în grupe mai mici de date. Avantajele programării modulare sunt multiple.Proiectarea descendentă permite lucrul în echipe mari. în Pseudocod fiecare SUBPROGRAM şi algoritmul principal sunt considerate module. Astfel. Un modul poate fi format din mai multe submodule. Este însă important ca fiecare modul să-şi aibă rolul său bine precizat. Prin descompunerea problemei în mai multe subprobleme. Dar ce este un modul? Modulul este considerat o unitate structurală de sine stătătoare. Este evident că probabilitatea apariţiei erorilor în conceperea unui program creşte cu mărimea programului. 3. Ca rezultat al proiectării ascendente se ajunge la o mulţime de SUBPROGRAMi care se apelează între ei. La compilarea separată un grup de subprograme compilate deodată constituie un modul. dar cu posibilităţi de comunicare între ele. lucru redat printro diagramă de structură. Este important să se cunoască care SUBPROGRAM apelează pe care. Programarea modulară este strâns legată de programarea ascendentă şi de programarea descendentă. lucru confirmat şi de experienţa practică. deşi corecţi. 24 . abia în faza de integrare. un modul nu trebuie să fie influenţat de maniera în care se lucrează în interiorul altui modul. Fiecare subechipă nu cunoaşte decât subproblema pe care trebuie să o rezolve. Menţionăm în cele ce urmează câteva dintre ele. De altfel. Deci programarea modulară se referă în primul rând la proiectarea modulară a algoritmilor şi apoi la traducerea lor în limbajul de programare ales. Metoda ascendentă (bottom-up) porneşte de la propoziţiile limbajului şi de la SUBPROGRAMi existenţi. sau un algoritm de sine stătător ce apelează alţi SUBPROGRAMi. considerăm modulele relativ independente. dar acest modul poate fi considerat ca o mulţime de submodule din care este compus. o proiectare mixtă. El apare în mod natural în descompunerea top-down.3 Proiectarea modulară Prin proiectare (programare) modulară înţelegem metoda de proiectare (programare) a unui algoritm pentru rezolvarea unei probleme prin folosirea modulelor. Se poate ajunge abia acum la concluzia că unii SUBPROGRAMi. Orice modificare ulterioară în structura unui program. Această metodă are marele dezavantaj că erorile de integrare vor fi detectate târziu. Rezultă că programarea modulară se bazează pe descompunerea problemei în subprobleme şi proiectarea şi programarea separată a SUBPROGRAMilor corespunzători. fie subprogram. considerăm că într-o programare serioasă nu se poate ajunge la implementare fără a avea în prealabil algoritmii descrişi într-un limbaj de descriere (la noi Pseudocod). dacă funcţia pe care o realizează un modul M încă este necesară. În limbajele de programare cu structură de bloc UNIT-urile pot fi considerate module. testarea unui modul se poate face mult mai uşor decât testarea întregului algoritm. De cele mai multe ori nu se practică o proiectare ascendentă sau descendentă pură ci o combinare a lor. ţinând seama de specificul acestui limbaj. Astfel. Un modul poate conţine sau poate fi conţinut într-alt modul. ambele presupunând folosirea SUBPROGRAMilor pentru toate subproblemele întâlnite. în cazul metodei ascendente va fi scris mai întâi SUBPROGRAMul apelat şi apoi cel care apelează. ca şi în cazul programării descendente. acest modul trebuie să fie util şi folosit în continuare fără modificări. nu sunt utili. Descompunerea unei probleme complexe în subprobleme este un mijloc convenabil şi eficient de a reduce complexitatea (Principiul Divide et impera acţionează şi în programare). fiecare subproblemă poate fi dată spre rezolvare unei subechipe. Cu alte cuvinte. să realizeze o funcţie în cadrul întregului program. rezolvând o problemă mai simplă. un grup de SUBPROGRAMi.

iar în proiectarea algoritmilor se folosesc cele trei structuri de calcul definite de Bohm-Jacopini. cerând claritate şi ordine în scriere şi respectarea structurilor de calcul definite mai sus. Modulele se pot refolosi ori de câte ori avem nevoie de ele. Sunt cunoscute astăzi multe astfel de biblioteci de subprograme. sau realizează funcţii bine definite. programarea top-down. Sigur că o astfel de limită nu există. Reutilizabilitatea acestor subprograme este o proprietate foarte importantă în activitatea de programare. 3. deci aceşti noi SUBPROGRAMi rezolvă subprobleme de sine stătătoare. Alţi autori consideră programarea structurată nu ca o simplă metodă de programare ci ansamblul tuturor metodelor de programare cunoscute. în timpul proiectării algoritmului sau a implementării lui. Considerăm că programarea structurată se poate întâlni: – la nivel micro. este folosit aici în sens larg şi nu este identic cu cel de programare propriu-zisă.4 Programarea structurată Programarea structurată este un stil de programare apărut în urma experienţei primilor ani de activitate. Ca rezultat se va ajunge la un algoritm uşor de urmărit. dar şi la creşterea siguranţei în realizarea unui produs corect. are o singură intrare şi o singură ieşire şi sunt prezentate în figura 1. dar se recomandă descompunerea unui SUBPROGRAM în alţi SUBPROGRAMi oricând acest lucru este posibil în mod natural. Este vorba de întreaga activitate depusă pentru obţinerea unui program. Uneori. se ajunge la concluzia că proiectarea a fost incompletă sau că unele module sunt ineficiente. ea permiţând înlocuirea modulului în cauză cu altul mai performant. Una din activităţile importante în realizarea unui program este verificarea corectitudinii acestuia. Abilitatea omului de a înţelege şi analiza corectitudinea unui SUBPROGRAM este mult mai mare pentru texte scurte.Apoi. S-a ajuns astfel la munca în echipă. Fiecare din aceste structuri. organizarea muncii este făcută pe principiul echipei programatorului şef. ca parte dintr-o schemă logică. de unde ele se pot refolosi la nevoie. Knuth consideră programarea structurată ca fiind un mijloc de a face produsele program mai uşor de citit. – structura repetitivă. În unele cărţi chiar se recomandă a nu se folosi SUBPROGRAMi mai mari decât 50 de propoziţii. programarea structurată este definită ca fiind programarea în care abordarea este top-down. La nivel micro programarea structurată este cea în care autorul este atent la structura fiecărui modul în parte. 25 . Termenul programare.1.3. Bohm şi Jacopini au demonstrat că orice algoritm poate fi compus din numai trei structuri de calcul: – structura secvenţială. Ea duce la mărirea productivităţii în programare. privind elaborarea unui SUBPROGRAM. deci atât proiectarea algoritmului cât şi traducerea acestuia în limbajul de programare ales. folosit în titlul acestei secţiuni şi consacrat în literatura de specialitate. şi în această situaţie programarea modulară este avantajoasă. De asemenea. s-a ajuns la compilarea separată a subprogramelor şi la păstrarea subprogramelor obţinute în biblioteci de subprograme. – structura alternativă. faptul că trebuiesc proiectate mai multe subprograme pentru subproblemele întâlnite. Important este faptul că programarea structurată presupune o disciplină în activitatea de programare. sau bottom-up (ascendentă sau descendentă) au apărut înaintea programării structurate. – la nivel macro. privind dezvoltarea întregului produs informatic (algoritm). Ea cere respectarea unei discipline de programare şi folosirea riguroasă a câtorva structuri de calcul. clar şi corect. modalitate prin care se ajunge la scurtarea termenului de realizare a produsului program. Dar programarea modulară. permite munca mai multor programatori. Experienţa a arătat că modulele se pot verifica cu atât mai uşor cu cât sunt mai mici. Astfel.

În acest scop am definit limbajul Pseudocod. 26 . cerând ordine în întreaga activitate şi existenţa unei structuri clare a întregii aplicaţii. precizată prin diagrama de structură a aplicaţiei. Schemele logice obţinute dintr-o descriere în Pseudocod a unui algoritm. care are structurile de calcul menţionate. a programării modulare şi a celorlalte metode de programare.La nivel macro programarea structurată presupune practicarea proiectării top-down. conform semanticii propoziţiilor Pseudocod. se numesc D-scheme (de la Dijkstra) sau scheme logice structurate.

acest fapt este un indiciu că rezultatele obţinute în program nu sunt corecte. Această afirmaţie este însă falsă. Componentele vectorului X desemnează variabilele de intrare.Z). intră sau nu într-un ciclu infinit". Vom folosi predicatul R(X) pentru a preciza datele pentru care problema are sens. dacă spaţiul de memorie necesar programului este mai mare decât cantitatea de memorie disponibilă. Între rezultatele Z ale problemei şi datele iniţiale X (cunoscute în problemă) există anumite relaţii. Apare o altă regulă: fiecare variabilă să aibă semnificaţia ei şi să nu fie folosită în scopuri diferite.CAPITOLUL IV ANALIZA ALGORITMILOR O anumită problemă poate fi rezolvată cu ajutorul calculatorului numai dacă se găseşte un algoritm pentru rezolvarea ei. Ne interesează să analizăm un program din mai multe puncte de vedere: 1) Corectitudine. Se ştie că nu există un program care să rezolve "problema terminării programelor": "Scrieţi un program care să decidă dacă un algoritm oarecare.b') este fals. pe care le vom grupa în trei vectori X. Acesta este corect pentru acele valori a şi b ale vectorilor X şi Z pentru care rezultatele problemei sunt b în cazul când datele iniţiale sunt a şi este fals în caz contrar. Componentele vectorului Z sunt variabilele care reprezintă rezultatele cerute de problemă. De asemenea.1 Corectitudinea programelor Un program este corect dacă el satisface specificaţiile problemei. O problemă nu are sens pentru orice date de intrare. 4. sau cât timp de execuţie necesită. Chiar şi problemele pentru care există algoritmi corespunzători nu sunt neapărat rezolvabile cu calculatorul. Cu alte cuvinte. un program este corect dacă pentru acele date de intrare care satisfac specificaţiile problemei rezultatele obţinute în urma execuţiei sunt corecte. 27 . Y şi Z. programul poate fi inutil. programul nu poate fi executat. sau cantitatea de memorie necesară. care este dat calculatorului sub forma unui program. componentele vectorului Y sunt variabilele de lucru. 3) Posibilitate de îmbunătăţire. Pentru orice program P deosebim trei tipuri de variabile. Evident. Iar asta se poate întâmpla destul de uşor în cazul problemelor ce trebuiesc rezolvate în timp real (adică soluţia trebuie obţinută înaintea unui timp critic). Pentru acele valori ale lui X pentru care predicatul este adevărat problema are sens. pentru celelalte nu are sens să executăm programul P. dacă executând programul cu datele iniţiale a obţinem rezultatele b' şi R(a. din câte instrucţiuni este compus. s-ar putea crede că orice problemă este rezolvabilă. dat. 4) Alte calităţi pe care le are. R(X) se numeşte predicat de intrare sau precondiţie. Iată câteva motive pentru care este necesar să analizăm algoritmii pe care-i concepem pentru rezolvarea unei probleme. Vom reda aceste relaţii prin predicatul de ieşire R(X. Este posibil ca timpul necesar execuţiei acestor algoritmi. În sfârşit. Deci. deci datele presupuse cunoscute în problema rezolvată prin programul P. care notează diferitele rezultate intermediare necesare în program. Întrucât toate problemele practice pe care le întâlnim se pot rezolva cu ajutorul calculatorului. Nu ne interesează câtă memorie foloseşte acest program. 2) Eficienţă. dacă numărul calculelor ce trebuie efectuat este foarte mare. să nu permită folosirea lor în practică. numit şi postcondiţie.

La testarea după specificaţia problemei. performanţă. Acest lucru este făcut prin execuţia programului cu date de test pentru care se cunosc dinainte rezultatele (sau cel puţin se ştie ceva despre ele) şi se observă rezultatele obţinute în urma execuţiei. respectiv n2 ori le vom considera echivalente între ele. sau avem unele informaţii despre rezultate. Ar fi de dorit demonstrarea apriori a corectitudinii programului. Dintre toate drumurile echivalente între ele vom testa un singur drum. Numărul tuturor seturilor de date de intrare posibile este teoretic infinit chiar şi pentru probleme simple. În concluzie vom alege pentru fiecare drum un set de date de test. altfel am avea o infinitate de drumuri de testat. invizibile în specificaţie şi a căror testare este mai simplă. Dacă însă la o singură execuţie am depistat erori. corectarea lor a modificat textul algoritmului şi testarea trebuie reluată pe toate drumurile afectate de această schimbare. Această metodă de testare este adecvată problemelor simple. Totuşi. Stabilirea datelor de test se poate face cel puţin pe două căi: – ţinând seama de specificaţia problemei. Se recomandă stabilirea datelor de test ţinând seama de specificaţia asupra datelor de intrare şi de specificaţia asupra datelor de ieşire. o execuţie a programului înseamnă parcurgerea unui drum de la START la STOP în această schemă. Ar trebui să verificăm toate blocurile schemei logice şi mai ales toate drumurile de la START la STOP posibile. Cu toate că ea nu demonstrează corectitudinea programului. robusteţe. Testarea după textul programului ţine seama. numărul execuţiilor fiind egal cu numărul acestor drumuri. Considerând că algoritmul este descris printr-o schemă logică. Aşa cum va rezulta din cele ce urmează. primul lucru urmărit este corectitudinea rezultatelor obţinute în urma execuţiei programului cu datele de test folosite. testarea după specificaţia problemei rămâne o metodă utilă în testarea modulelor. nu şi un mijloc de a demonstra absenţa lor. 28 . Cu observaţia că în cazul a două drumuri ce diferă doar prin faptul că o anumită buclă se execută de n1. Dacă toate execuţiile au dat rezultate corecte programul se consideră testat. În privinţa aceasta dăm un citat din Dijkstra: Testarea programelor poate fi un mijloc eficient de a indica prezenţa erorilor.2 Testarea şi depanarea programelor Testarea programelor este activitatea prin care programatorul observă comportarea programului în urma execuţiei lui cu date de test. de instrucţiunile care trebuiesc executate. – ţinând seama de textul programului. Scopul testării programelor este depistarea şi eliminarea erorilor. testarea măreşte certitudinea corectitudinii lui şi este deocamdată singura metodă practică de certificare a programului. Însă problema noastră a fost descompusă în subprobleme mai mici. Corectitudinea rezultatelor în aceste execuţii nu demonstrează corectitudinea programului în general. Se pune problema alegerii datelor de test şi a numărului de execuţii ce trebuie făcute pentru a putea considera că programul nu are erori. Deci nu poate fi vorba de o testare exhaustivă. dar rezultatele cunoscute în prezent în această direcţie nu sunt aplicabile programelor complexe.4. dar din păcate. Testarea însă pune adeseori în evidenţă erori făcute în diferite faze ale programării. Evident. pentru a stabili datele de test. Dacă la această execuţie rezultatele obţinute sunt corecte probabil că textul algoritmului pe acest drum este corect. În cazul unei probleme complexe aplicarea ei este imposibilă datorită numărului foarte mare de cazuri posibile. cea mai bună cale este una mixtă. Privind programul ca o cutie neagră nu vom mai ţine seama de aceste subprobleme. siguranţă în funcţionare. Activitatea care urmăreşte descoperirea cauzelor erorilor şi înlăturarea lor se numeşte depanare. Dar se va urmări şi dacă programul are alte caracteristici ca: utilitate. Executând programul cu aceste date ar trebui să ajungem la rezultatele cunoscute. În cazul în care rezultatele obţinute în urma execuţiei nu sunt cele aşteptate se vor căuta şi elimina erorile. în care sunt combinate aceste două posibilităţi. care ar trebui testate. Este beneficiarul mulţumit de rezultatele care se obţin şi de forma sub care sunt prezentate? Sunt ele obţinute în timp util? Datele de test sunt date de intrare alese pentru variabilele de intrare pentru care se cunosc rezultatele. stabilirea datelor de test se face analizând specificaţia problemei.

aşa cum se va menţiona mai jos. testarea ar fi o activitate complexă. unele foarte grave. se recomandă mai întâi testarea după specificaţii şi apoi testarea după textul programului. – depăşirea dimensiunii tablourilor. ar trebui să existe. SFDACĂ grupul A este inaccesibil oricare ar fi valoarea lui n. – neconcordanţa între parametri actuali şi formali. pentru care problema nu are sens. care înseamnă buna lui comportare la date de intrare intenţionat greşite. În textul unui program există şi drumuri moarte. altele se termină cu erori de execuţie. poate fi foarte dificilă. ceea ce schimbă complet sensul textului Pseudocod de mai sus. În această etapă găsirea erorilor. Comportarea cea mai normală în astfel de situaţii ar fi semnalarea unor mesaje de eroare corespunzătoare. În acest caz apare problema alegerii acelei submulţimi din aceste date care să aibă şansa maximă de a depista erorile prezente în program. Ea înseamnă mult mai puţine execuţii decât toate drumurile START-STOP. în succesiunea de propoziţii Pseudocod DACĂ n<2 ATUNCI . . Testarea minimă care trebuie făcută constă într-un număr de execuţii a programului care să ne asigure că fiecare instrucţiune din program a fost executată cel puţin odată. deci nu putem găsi date de test corespunzătoare acestor drumuri. . Adeseori aceste drumuri scot în evidenţă erori prin simpla analiză a textului. La un produs program complex testarea este o activitate mult mai complicată. Un program robust nu trebuie să fie afectat de datele de intrare eronate. Din această cauză se recomandă o testare mixtă. mai ales atunci când ele provin dintr-o proiectare greşită. Încă un motiv pentru a practica programarea modulară. deci în ipoteza că fiecare modul în parte este corect. Stabilirea datelor de test după textul programului are şi unele dezavantaje. În primul rând. caz în care testarea se face asupra unor module mai mici şi asupra interfeţei dintre ele. înlăturarea cauzelor care lea generat şi corectarea lor. Încă un motiv pentru care se recomandă o testare mixtă. Este însă foarte frecventă eroarea de omisiune a unui caracter. programul poate fi incomplet şi să nu corespundă specificaţiilor. . Testarea de integrare se referă la funcţionarea programului realizat în ansamblu. o testare a interfeţei dintre module şi o testare a produsului în ansamblu (testarea de integrare). constând dintr-un număr foarte mare de execuţii. În ambele situaţii urmează depanarea programului. dar lipsesc drumuri care. conform specificaţiilor. Este necesară şi testarea robusteţei programului. Adesea este imposibil să se execute programul cu toate datele de test stabilite. în cazul nostru tastarea numărului 2 în loc de 20.Pentru un program complex. Unele programe intră în aceste condiţii în ciclu infinit. – alte erori ce provoacă depăşiri. Dar chiar şi la execuţia normală a programului putem avea erori. Execuţia unui program se poate termina anormal datorită apariţiei unor erori ca: – împărţiri la zero. Pe drumurile existente el este corect. . e necesar să se verifice comportarea globală a programului. Lipsa acestor drumuri este o greşeală gravă care nu va fi descoperită de datele de test care ne duc doar pe drumurile existente. Există date de test care ne duc pe un anumit drum fără a depista erori existente în instrucţiunile întâlnite şi alte date de test care depistează aceste erori. adică descoperirea cauzei erorilor şi înlăturarea lor. obţinând rezultate greşite. Astfel. pe care nu se poate merge oricare ar fi datele de intrare. deci pentru o schemă logică cu un număr foarte mare de drumuri START-STOP. Ca ordine de folosire a datelor de test în timpul testării. 29 . DACĂ n>3 ATUNCI A SFDACĂ . Este necesară o testare separată a fiecărui modul în parte. După ce fiecare modul în parte a fost testat şi corectat.

Cu siguranţă îi va arăta că o anumită variabilă ia alte valori decât cele la care se aşteaptă el. care va include textul programului. – viteza de lucru. Mai ales în locurile vecine cu instrucţiunile care au provocat eroarea şi pentru variabilele implicate în producerea ei. pot dezvălui programatorului cauza erorii. Adeseori se întâlnesc programe fără nici o altă documentaţie în afara textului propriu-zis al programului. astăzi acest factor a devenit mai puţin important. 4. pentru acele date de intrare pentru care numărul operaţiilor efectuate este maxim. în special pentru începători. Timpul necesar execuţiei unui program depinde de numărul operaţiilor ce trebuiesc executate. Dacă numărul execuţiilor posibile este finit atunci acest număr mediu este egal cu numărul operaţiilor efectuate în toate execuţiile. Iar comentariile prezente în program dau explicaţii suplimentare despre program. programul nu este însoţit de nici o documentaţie şi frecvent nu sunt folosite nici comentarii în textul programului. Observarea valorilor unei variabile. scrisă. Există însă un cel mai rău caz. apoi persoanele care-l vor folosi şi persoanele solicitate să facă întreţinerea acestuia. – datele de test folosite. a schimbărilor făcute în timpul execuţiei. Mai exact. deci se schimbă de la o execuţie la alta. putem vorbi de numărul mediu de operaţii efectuate într-o execuţie. Dacă în urmă cu două decenii volumul de memorie necesar rezolvării unei probleme era un factor important din cauza memoriei reduse existente la calculatoarele din acel timp. cu specificaţia ei şi rolul fiecărei variabile). Pentru fiecare algoritm va fi prezentată subproblema corespunzătoare. – specificaţia (vezi secţiunea 4. Recomandăm verificarea valorilor variabilelor imediat după obţinerea acestora.1). Este însă necesară o documentaţie completă. Aceştia sunt în primul rând persoanele care au realizat programul. Care dintre ei este mai bun? Evident. În acest caz vorbim de complexitate în cel mai rău caz. pe timpul testării unui program. Pentru aproape toate programele. – documentaţia de programare. deci timpul necesar rezolvării problemei. sunt utile semnalările oricăror semne de eroare. Calculatoarele actuale au memorie suficient de mare pentru marea majoritate a algoritmilor întâlniţi. Iar numărul operaţiilor efectuate depinde de datele de intrare.3 Complexitatea algoritmilor În această secţiune ne va interesa eficienţa unui algoritm. numărul execuţiilor posibile este infinit. 4. este inserarea în program a unor tipăriri auxiliare.O metodă utilă în depanarea programelor. ne interesează să comparăm între ei mai mulţi algoritmi care rezolvă aceeaşi problemă.4 Documentarea programelor În paralel cu elaborarea programului trebuie elaborată şi o documentaţie. De asemenea. Documentarea este activitatea de prezentare a programului celor care vor fi interesaţi să obţină informaţii despre el. Sunt însă foarte puţine programe cu această proprietate. care va conţine: – enunţul iniţial al problemei. – documentaţia de proiectare (metoda de rezolvare aleasă şi proiectarea algoritmilor folosiţi. – documentaţie privind exploatarea programului. Sigur că însăşi textul programului constituie o autodocumentare. 30 . În graba de a termina cât mai repede. cel puţin teoretic. Putem compara doi algoritmi în raport cu: – cantitatea de memorie necesară. vom compara numai algoritmi despre care ştim că sunt corecţi. De altfel. Aceasta va conţine toate deciziile luate în crearea programului. împărţit la numărul execuţiilor. – modificări făcute în timpul întreţinerii programului.

a structurilor din care este compus şi a rolului denumirilor şi părţilor sale. Este necesară şi o documentaţie de folosire a produsului realizat. şi o autodocumentaţie (funcţii HELP). 4. Calităţile pe care le poate avea un program sunt următoarele: Corectitudine = proprietatea programului de a respecta specificaţiile şi a da rezultate corecte. – algoritmul propriu-zis.5 Stil în programare Fiecare programator are stilul să propriu de concepere şi redactare a unui program. Portabilitate = posibilitatea de folosire a produsului program pe alte sisteme de calcul. pe lângă documentaţia scrisă. duce evident la creşterea productivităţii în realizarea noului produs. Referitor la autodocumentare. Reutilizabilitate = posibilitatea reutilizării întregului program sau a unor părţi din el în alte aplicaţii. iar programarea structurată duce la un program mai uşor de citit decât unul lipsit de orice structură. – datele de ieşire. Robusteţe = abilitatea de a recunoaşte situaţiile în care problema ce se rezolvă nu are sens şi de a se comporta în consecinţă (de exemplu. Cei care au dorit să refolosească programe scrise cu câteva luni în urmă înţeleg foarte bine diferenţa dintre un program însoţit de comentarii explicative şi un program fără nici o explicaţie. astfel încât programele elaborate să aibă anumite calităţi. chiar dacă este posibilă. Este însă necesar să se înţeleagă cât mai uşor ce funcţii realizează aceste componente şi cu ce performanţe. Este necesar ca aceste informaţii să se afle şi sub forma unor comentarii în textul programului. Comentariile sunt recomandate. Sigur că prima documentaţie a oricărui program este textul sursă propriu-zis. care constituie documentarea propriu-zisă a programului. Beneficiarul nu este interesat de modul în care a fost realizat programul ci de modul în care îl poate folosi. dar mai ales pe timpul întreţinerii şi modificărilor ulterioare. testate şi documentate. fiind un mijloc de autodocumentare a programului sursă.Menţionăm că cele mai recente produse realizate de firmele consacrate au. cât şi claritatea textului. Eficienţă = măsura în care sunt bine folosite resursele sistemului de calcul. Folosirea acestor componente existente. Este bine ca acest text să poată fi citit cât mai uşor. Aceasta trebuie să redea toate deciziile făcute în timpul proiectării. este utilă nu numai pe timpul elaborării programului. Pentru fiecare modul documentaţia va conţine: – numele acestuia. Claritate = uşurinţa citirii şi înţelegerii textului programului. – variabilele folosite şi semnificaţia lor. Compatibilitate = uşurinţa de combinare cu alte produse program. – funcţia realizată de modulul respectiv. Componente ale unui produs existent pot fi utile şi în realizarea altor produse. documentaţia va conţine şi textul final al programului. obţinută prin indentare şi grijă asupra structurii programului. O documentare completă a unui program poate fi utilă nu numai pentru folosirea şi întreţinerea programului. diferite de cel pe care a fost conceput. alegerea cu grijă a denumirii variabilelor. prin mesaje de eroare corespunzătoare). Uitarea acţionează asupra oricărei persoane şi. Este însă nevoie şi de o documentaţie însoţitoare scrisă. Extensibilitate = posibilitatea adaptării programului la unele schimbări în specificaţie. să prezinte diagrama de structură a întregului produs şi fiecare parte separat. Denumirea variabilei să fie astfel aleasă încât să redea cât mai bine semnificaţia ei. De asemenea. – datele de intrare. folosirea comentariilor. 31 . Este bine ca el să respecte anumite reguli generale de programare. descifrarea unui program cere timp şi nu este o sarcină prea uşoară.

O) SFALGORITM Considerăm că fiecare programator trebuie să respecte anumite reguli de scriere a programelor. j=1. Tot privind claritatea scrierii programului.O). perioada realizării lui şi numele programatorului. 2-4 instrucţiuni scurte de atribuire pot fi scrise pe acelaşi rând. CHEAMĂ TIPAR(n. PENTRU j:=1. recunoscând această situaţie şi semnalând-o. NUME.j. E bine ca un program ce se poate scrie pe o pagină. i=1.NUMEi. Ele au rolul de a explica cititorului anumite părţi din program. . i=1. O) SFPENTRU CHEAMĂ ORDINE(n.n EXECUTĂ {calculează media generală a elevului i} FIE S:=0. vizibile şi în text. NOTEi. dacă textul lui se poate citi şi înţelege. Gries sugerează următoarele reguli: . completând tot rândul asemeni textului unui roman. pe lângă aceste calităţi. Comentariile vor fi prezente: – în capul programului.n. PENTRU i:=1. dacă poate fi uşor întreţinut şi dacă este terminat la data fixată. stilul de programare este dat şi de corectitudinea şi robusteţea produselor realizate. Iar corectitudinea sau incorectitudinea programului este o consecinţă a modului în care programatorul a respectat regulile de programare (vezi capitolul 8) şi a experienţei obţinute în activitatea de programare. Evident.m. Am spus deja că în proiectarea algoritmilor folosim şi propoziţii nestandard care vor fi pe parcurs înlocuite cu propoziţii standard.n. Claritatea lui este mică.MEDII. Un alt mijloc de a mări claritatea textului unui program constă în inserarea comentariilor în text. începând toate în aceeaşi coloană. Comentariile sunt texte explicative închise între acolade. pentru a prezenta titlul şi scopul programului.instrucţiunile unei secvenţe se vor scrie aliniate. aflată cu 2-4 caractere la dreapta faţă de începutul instrucţiunii compuse. Programul trebuie să funcţioneze şi la introducerea unor date greşite (pentru care problema nu are sens).Un produs program este considerat de calitate dacă are calităţile de mai sus. Textul unui algoritm poate fi scris cuvânt după cuvânt. să nu fie întins pe două pagini ! Considerăm că nu există reguli de scriere obligatorii pentru toată lumea! Dar fiecare programator trebuie să aibă propriile lui reguli de scriere.NUME. Stilul unui programator este dat de măsura în care programul său are aceste calităţi şi de vizibilitatea lor.pe o linie pot fi scrise mai multe instrucţiuni. după cum urmează: PROGRAMUL CLASAMENT ESTE: DATE m.m EXECUTĂ S:=S+NOTEi.j SFPENTRU FIE MEDIIi:=S/M SFPENTRU PENTRU j:=1. cu gândul la claritatea textului.O). Privind claritatea algoritmului trebuie să observăm că indentarea (paragrafarea) este un alt mijloc de a mări claritatea scrierii. E bine ca aceste propoziţii să rămână în text sub formă de comentarii. Astfel. cu condiţia ca ele să aibă ceva comun. Acest lucru se recomandă în vederea unei scrieri compacte a programului. În unele cărţi sunt date mai multe reguli de indentare. CHEAMĂ TIPAR(n. se recomandă ca denumirile variabilelor să fie astfel alese încât să reflecte semnificaţia acestor variabile.m EXECUTĂ CHEAMĂ ORDINE(n. cu respectarea structurii lui. Astfel. . 32 .NOTEj. dacă lansat în execuţie dă rezultate corecte. În acelaşi timp rezultatele obţinute pentru date pentru care problema are sens trebuie să fie corecte.n.instrucţiunile unei structuri de calcul (instrucţiuni compuse) se vor scrie începând toate din aceeaşi coloană.

33 . pentru a explica rolul fiecărei părţi. pentru a descrie semnificaţia notaţiilor folosite (a variabilelor. pentru a descrie rolul acestora.– în definiţii. SUBPROGRAMilor etc). constantelor. – în dreapta unor instrucţiuni. – între părţile unui modul mai lung. Sperăm că prin exemplele date în acest material am prezentat un stil propriu de programare şi am convins cititorul de necesitatea formării propriului său stil. sau cazul în care se atinge acea instrucţiune.

Spunem că o colecţie de n articole este ordonat crescător după cheia C dacă C(i) ≤ C(j) pentru 1≤ i<j≤ n. Precondiţia: n∈N. În urma procesului de căutare va rezulta poziţia elementului căutat (dacă acesta există).n). ca de exemplu căutarea unui cuvânt în dicţionar sau căutarea unui număr în cartea de telefon. n≥ 1 şi k1 < k2 < . De obicei articolele sunt păstrate în ordinea crescătoare a cheilor. kn cheile corespunzătoare articolelor şi cu a cheia pe care o căutăm.p) este: {n∈N.. O primă metodă este căutarea secvenţială... Dacă datele pe care dorim să le ordonăm. < kn . Operaţiile de căutare şi sortare sunt executate frecvent de către oameni în viaţa de zi cu zi. Uneori este util să aflăm nu numai dacă există un articol cu cheia dorită ci şi să găsim în caz contrar locul în care ar trebui inserat un nou articol având cheia specificată. atunci procesul îl vom numi sortare externă. Pentru rezolvarea acestei probleme vom descrie mai mulţi SUBPROGRAMi. iar dacă datele se află într-un fişier (colecţie de date de acelaşi fel aflate pe suport extern). Rezultate p. < kn . k2.. Notând cu k1. Colecţia aceasta respectă ordinea alfabetică după câmpul de nume.n. Căutarea este mult simplificată dacă datele în care efectuăm această operaţie sunt sortate (ordonate. Deci problema căutării are următoarea specificare: Date a. SUBPROGRAMul CautSecv(a. Ele constituie o parte esenţială din numeroasele procese de prelucrare a datelor..n.. 34 . în care sunt examinate succesiv toate cheile. adică să le sortăm. Fiecare element al colecţiei de date se numeşte articol iar acesta la rândul său este compus din unul sau mai multe componente.. Sortarea datelor constă în rearanjarea colecţiei de date astfel încât un câmp al elementelor colecţiei să respecte o anumită ordine. aranjate) într-o anumită ordine (cuvintele în ordine alfabetică. problema revine la a găsi (dacă există) poziţia p cu proprietatea a = kp. < 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. . atunci procesul de rearanjare a colecţiei îl vom numi sortare internă. Vom căuta un articol după un câmp al acestuia pe care îl vom considera cheie de căutare. numerele în ordine crescătoare sau descrescătoare). n≥ 1 şi} {k1 < k2 < .CAPITOLUL V CLASE DE ALGORITMI Căutarea şi Sortarea sunt două dintre cele mai des întâlnite subprobleme în programare. i=1. astfel încât să se păstreze ordinea existentă. O cheie C este asociată fiecărui articol şi este de obicei unul dintre componente.K. Postcondiţia: (p=1 şi a ≤ k1) sau (p=n+1 şi a > kn) sau (1<p≤ n) şi (kp-1 < a ≤ kp). iar dacă C(i) ≥ C(j) atunci şirul este ordonat descrescător..1 Algoritmi de căutare În acest subcapitol vom studia câteva tehnici elementare de căutare şi vom presupune că datele se află în memoria internă.... deci vom presupune că k1 < k2 < .(ki. De exemplu în cartea de telefon fiecare element (abonat) are un câmp de nume. unul de adresă şi unul pentru numărul de telefon. într-un şir de articole... sunt în memoria internă. 5.

< 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. Tot atâtea comparări se vor efectua în n-1 din cele n+1 intervale în care se poate afla cheia căutată. < 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). prin înjumătăţiri succesive se micşorează volumul colecţiei rămase pentru căutare.K..n...n) sfdacă sfdacă sf-CautBin Funcţia BinarySearch (a.n. Cu alte cuvinte este posibil să înlocuim ciclul PENTRU cu un ciclu CÂTTIMP..p) este: {n∈N. Căutarea binară se poate realiza practic prin apelul funcţiei BinarySearch(a. Ajungem la un al doilea algoritm.K.Dr) este: Dacă St≥ Dr-1 atunci BinarySearch:=Dr altfel m:=(St+Dr) Div 2. Dacă a>k1 atunci Câttimp p≤ n şi a>kp executş p:=p+1 sfcât sfdacă sf-CautSecv O altă metodă.n.m) altfel BinarySearch:=BinarySearch(a.n. Atunci când a fost deja găsită cheia dorită este inutil a parcurge ciclul pentru celelalte valori ale lui i. care este mult mai eficientă.K. SUBPROGRAMul CautSucc(a.K..1.K. utilizează tehnica "divide et impera" privitor la date.m. deci complexitatea medie are acelaşi ordin de mărime ca şi complexitatea în cel mai rău caz. Dacă a≤ K[m] atunci BinarySearch:=BinarySearch(a.. dat în continuare. Fie p:=1. SUBPROGRAMul CautBin(a.n. În urma acestei verificări căutarea se continuă doar într-o jumătate a colecţiei. În acest mod. Se determină în ce relaţie se află cheia articolului aflat în mijlocul colecţiei cu cheia de căutare. Cele n chei împart axa reală în n+1 intervale. n≥ 1 şi} {k1 < k2 < .Dr) sfdacă 35 .n). n≥ 1 şi k1 < k2 < .Dacă a≤ k1 atunci p:=1 altfel Dacă a>kn atunci p:=n+1 altfel Pentru i:=2. Evident că în multe situaţii acest algoritm face calcule inutile.p) este: {n∈N.St. numită căutare binară.K.n. folosită în SUBPROGRAMul dat în continuare.K.n. 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 comparări. întrucât contorul i va lua toate valorile de la 2 la n. descrisă mai jos.St.1.

.. {K=(k1. Procesul de comparare se va încheia în momentul în care toate perechile de elemente consecutive sunt în relaţia de ordine dorită. Deci k1 ≤ k2 ≤ .K) este: {Se face o permutare a celor} {n componente ale vectorului K astfel} {ca k1 ≤ k2 ≤ ..n. după care acesta se va interschimba cu primul element. aşa cum se poate vedea în următoarea funcţie: Funcţia BinSeaNerec (a.. ele vor fi interschimbate. 36 .. ≤ kn } Pentru i:=1. A treia metodă care va fi prezentată. numită "BubbleSort".K. Se poate înlătura uşor recursivitatea. compară două câte două elemente consecutive iar în cazul în care acestea nu se află în relaţia dorită. SUBPROGRAMul Selectie(n. n-1 execută Fie ind:=i. n execută Dacă kj < kind atunci ind:=j sfdacă sfpentru Dacă i<ind atunci t:=ki. iar m reprezintă mijlocul acestui interval. Acest procedeu se repetă pentru subcolecţia rămasă. Deci specificarea problemei de sortare internă este următoarea: Date n. ki:=kind.St. Pentru j:=i+1. Se observă că funcţia BinarySearch se apelează recursiv. Din punct de vedere al complexităţii algoritmilor problema revine la ordonarea cheilor. până când mai rămâne doar elementul maxim..K.2 Sortare internă Prin sortare internă vom înţelege o rearanjare a unei colecţii aflate în memoria internă astfel încât cheile articolelor să fie ordonate crescător (eventual descrescător).Dr) este: Câttimp Dr-St>1 execută m:=(St+Dr) Div 2.+2+1=n(n-1)/2 indiferent de natura datelor.kn)} Precondiţia: ki∈R.. kind:=t sfdacă sfpentru sf-Selectie Se observă că numărul de comparări este: (n-1)+(n-2)+. i=1. O primă tehnică numită "Selecţie" se bazează pe următoarea idee: se determină poziţia elementului cu cheie de valoare minimă (respectiv maximă). ≤ kn.n Rezultate K'.sfdacă sf-BinarySearch În funcţia BinarySearch descrisă mai sus.k2. Dacă a≤ K[m] atunci Dr:=m altfel St:=m sfdacă sfcât BinSeaNerec:=Dr sf-BinSeaNerec 5... variabilele St şi Dr reprezintă capetele intervalului de căutare. dar ordonată crescător. Postcondiţia: K' este o permutare a lui K...

. Procedura QuickSort este prezentată în continuare : SUBPROGRAMul QuickSort (n.St. kSt+1 .. .1. în continuare va trebui doar să ordonăm subşirul kSt . Repetă Câttimp kj >= a şi (i<j) execută j:=j-1 sfcât ki:= kj.ki-1 prin apelul recursiv al procedurii QuickSort(n.K) este: Cheamă QuickSort(n. Câttimp ki ≤ a şi (i<j) execută i:=i+1 sfcât kj:= ki .i-1) sfdacă Dacă i+1 < Dr atunci Cheamă QuickSort(n. pentru st ≤ j < i < l ≤ dr (*) Odată realizat acest lucru.i-1) şi apoi subşirul ki+1..K. ..K. Şirul ce urmează a fi ordonat se împarte în două subşiruri care se ordonează.1. n execută Dacă ki-1 > ki atunci t := ki-1.St.Dr) va realiza ordonarea subşirului kSt. după care acestea se vor interclasa obţinându-se întregul şir ordonat...K. Metoda este prezentată sub forma unei proceduri care realizează ordonarea unui subşir precizat prin limita inferioară şi limita superioară a indicilor acestuia.K.St.Dr) este: Fie i:=St.K.. care va fi prezentată în continuare. kod:=1 sfdacă sfpentru pânăcând kod=0 sfrep sf-BubbleSort {Ipoteza "este ordine"} {N-a fost ordine!} {Ordonare} O metodă mai performantă de ordonare. şirul va fi rearanjat astfel încât următoarea condiţie să fie îndeplinită: kj ≤ ki ≤ kl ..K) este: Repetă Fie kod:=0. unde n reprezintă numărul de articole ale colecţiei date.Dr).Dr) sfdacă sf-QuickSort Un ultim algoritm care va fi prezentat se numeşte "Merge Sort" (sortare prin interclasare) şi se bazează pe tehnica "divide et impera". Dacă i este această poziţie.n).. kDr prin apelul QuickSort(i+1.. a:=ki. Apelul procedurii pentru ordonarea întregului şir este : QuickSort(n.K. ki:=t.St. Fiecare subşir se va ordona tot prin despărţirea lui în două subşiruri urmată de interclasare şi aşa mai departe până când 37 .SUBPROGRAMul BubbleSort (n.kSt+1. Desigur ordonarea acestor două subşiruri (prin apelul recursiv al procedurii) mai este necesară doar dacă acestea conţin cel puţin două elemente. ki-1 := ki. se numeşte "QuickSort" şi se bazează pe tehnica "divide et impera" după cum se poate observa în continuare.i+1. kDr. Acest subşir va fi rearanjat astfel încât kSt să ocupe poziţia lui finală (când şirul este ordonat). Pentru i:=2.K. Dacă St < i. pânăcând i=j sfrep Fie ki := a.n) sf-SortareRapidă Procedura QuickSort (n. j:=Dr. SUBPROGRAMul SortareRapidă (n.1 atunci Cheamă QuickSort(n.

y1.Z) este: k:=k+1. Cele m+n valori} {se depun în Z.k.val.xi. în plus. este ineficient şi. i=1. ordonate crescător (sau descrescător) după o cheie.k.. simultan cu generarea colecţiei cerute. nu este util în sortările externe (vezi secţiunea 5.Z) {numai în X} sfcât Câttimp (j<=n) execută {Există componente} Cheamă PUNE(j.3 Interclasare Fiind date două colecţii de date. j:=1..yj. ≤ yn} Rezultate k. n.Z) care pune în vectorul Z valoarea val şi măreşte indicele ind cu 1..z2... tot ordonate nedescrescător} Fie i:=1. Prin compararea a două elemente din listele de intrare se va decide care element va fi adăugat în lista de ieşire. zk) este o permutare a valorilor (x1.. 5.Z) este: {X are cele m} {componente ordonate nedescrescător} {La fel Y cu n componente.Z) {şi în Y} sfdacă sfcât Câttimp (i<=m) execută {Există componente} Cheamă PUNE(i. ≤ xm} şi {y1 ≤ y2 ≤ ..k. Precondiţia: {x1 ≤ x2 ≤ .Z) {şi în X} altfel Cheamă PUNE(j.. (xi.k..k.n). yn) O soluţie posibilă ar fi depunerea componentelor vectorului X şi a componentelor vectorului Y în vectorul Z... subalgortim dat în continuare.Y. (zi. .. i=1.ordonarea unui subşir se poate rezolva elementar fără a mai fi necesară despărţirea lui în alte două subşiruri (lungimea subşirului este cel mult 2). deşi corect. Câttimp (i<=m) şi (j<=n) execută {Există componente} Dacă xi≤ yj atunci Cheamă PUNE(i.n. zk:=val.yj. Acest algoritm. Ordonând apoi componentele vectorului Z obţinem soluţia dorită. realizând astfel a doua parte din postcondiţie..k.. Deci ne interesează un algoritm de rezolvare a problemei ce are următoarea specificare: Date m. SUBPROGRAMul PUNE(ind. Postcondiţia: {k=m+n} şi {z1≤ z2≤ . k:=0. xm.k. i=1. Acest lucru este realizat de următorul algoritm de interclasare: SUBPROGRAMul Interclasare(m.. Algoritmul corespunzător este prezentat în secţiunea următoare sub forma unei proceduri recursive care ordonează un subşir precizând limitele acestuia.X.. Este important ca la o singură trecere prin vectorii X şi Y să se obţină vectorul Z.Z) {numai în Y} sfcât sf-Interclasare Aici s-a folosit SUBPROGRAMul PUNE(ind.xi.k).m). ind:=ind+1 sf-PUNE 38 {Adaugă val} {în vectorul Z cu} {k componente şi} {măreşte ind cu 1} .. se cere să se obţină o colecţie care să fie de asemenea ordonată crescător (respectiv descrescător) după aceeaşi cheie şi care să fie formată din articolele colecţiilor date. (yi.4). Acest lucru se poate obţine direct (fără o sortare a colecţiei finale) prin parcurgerea secvenţială a celor două colecţii.val.≤ zk} şi (z1.

Algoritmul MergeSort de sortare bazat pe interclasare se poate vedea în continuare. Algoritmul MergeSort este: {Sortare prin interclasare} Citeşte n; Pentru i:=1 ; n execută Citeşte Ki sfpentru Cheamă SortInter (n,K); Pentru i:=1; n execută Tipăreşte 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; Câttimp (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ă sfcât Câttimp (s1<=d1) execută Cheamă PUNE(s1,cs1 ,k,A) sfcât Câttimp (s2<=d2) execută Cheamă PUNE(s2,cs2 ,k,A) sfcât C:=A sf-Inter 5.4 Sortare externă O problemă cu care ne confruntăm adesea este sortarea unei colecţii de date aflate pe un suport extern, de volum relativ mare faţă de memoria internă disponibilă. În această secţiune o astfel de colecţie de date o vom numi fişier. În acest caz nu este posibil transferul întregii colecţii î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 decât spaţiul de memorie internă de care dispunem, atunci colecţia se va împărţi în n subcolecţii ce vor fi transferate succesiv în memoria internă, se vor sorta pe rând şi vor fi stocate din nou pe suportul extern sortate. Din acest moment prin operaţii de interclasare două câte două se pot obţine colecţii de dimensiuni superioare până se obţine toată colecţia ordonată. La aceste interclasări, pentru a efectua un număr cât mai mic de operaţii de transfer se recomandă interclasarea colecţiilor de dimensiuni minime, apoi din datele obţinute din nou vor fi alese două colecţii de dimensiuni minime şi aşa mai departe până se obţine o singură colecţie care va fi colecţia 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 configuraţia calculatorului folosit, dar şi de suportul pe care se află fişierul de sortat şi fişierele intermediare create. Principial sortarea externă presupune parcurgerea a două etape importante: a) Divizarea fişierului de sortat F, în n fişiere H1, H2, ..., Hn, cu sortarea internă a acestora; b) Interclasarea acestor fişiere sortate pentru a ajunge la fişierul dorit G.

40

CAPITOLUL VI
EVOLUŢIA LIMBAJELOR DE PROGRAMARE Un limbaj de programare este un sistem de convenţii adoptate pentru realizarea unei comunicări – între programator şi calculator . Limbajele folosite pentru programarea unui calculator sunt extrem de asemănătoare limbajelor naturale . Ele sunt compuse din :  cuvinte (rezervate);  punctuaţie;  propoziţii şi fraze;  reguli sintactice etc. Aşa cum pentru însuşirea unei limbi străine trebuie învăţate cuvintele acesteia şi regulile cu care pot fi manevrate tot aşa pentru însuşirea 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 iniţial al istoriei calculatoarelor este, de obicei legat de numele matematicianului englez Charles Babbage. El a propus în anul 1830 o Maşină Analitică care a anticipat în mod fascinant structura calculatoarelor actuale. Ideile sale au devansat cu peste 100 de ani posibilităţiile tehnologice ale vremii sale. Înaintea a mai fost încercări în acest domeniu ale lui Leibnitz şi Pascal (sec al XVII-lea) . Următorul moment de referinţă este anul 1937, când Howard Aiken, de la Universitatea Harvard a propus Calculatorul cu secvenţă de Comandă Automată, bazat pe o combinaţie între ideile lui Babbage şi calculatoarele elertromecanice, produse de firma IBM. Construcţia 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 alcătuit 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 conţine circa 18.000 de tuburi electronice şi executa 5.000 de adunări pe secundă, având o memorie de 20 de numere reprezentate în zecimal. Programarea sa se realiza prin poziţionarea a circa 6.000 de comutatoare, cu mai multe poziţii. O semnificaţie 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ă soluţie a fost aleasă datorită vitezei reduse a fiecărei unităţi de calcul, în parte. La versiunea următoare s-a renunţat la această structură paralelă de calcul, deoarece s-a considerat că viteza unei unităţi de calcul, realizată cu circuite electronice, este suficientă . Soluţia prelucrării paralele a fost reluată ulterior după anii 80’ pentru mărirea performanţelor unui sistem de calcul; astfel în 1996 Firma INTEL a realizat un supercalculator ce foloseşte peste 7000 de procesoare PENTIUM utilizând tehnica „de calcul masiv” (utilizat pentru simularea testelor nucleare, în cercetări genetice, spaţiale, meteorologice). De remarcat că la realizarea primelor calculatoare, în calitate de consultant al echipei, a lucrat şi matematicianul John von Neumann, unul dintre matematicienii importanţi 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 căruia să se poată introduce un număr nelimitat de operanzi şi instrucţiuni .  Trebuie să posede o memorie, din care să se citească instrucţiunile şi operanzii şi în care să se poată memora rezultatele.  Trebuie să posede o secţiune de calcul, capabilă să efectueze operaţii aritmetice şi logice, asupra operanzilor din memorie.  Trebuie de asemenea să posede un mediu de ieşire, prin intermediul căruia un număr nelimitat de rezultate să poată fi obţinute de către utilizator.
41

preoţii mainframe-urilor s-au înfiorat.Aceasta era piaţa calculatoarelor în anii ´70: mainframe-uri şi minicalculatoare erau prezente în toate companiile şi principalele departamente. oameni care voiau să facă programe mai bune. mai rapide şi mai „elegante”. Acei hacker-i erau plini de entuziasm faţă de calculatoare. Astăzi. gama funcţiilor care pot fi realizate a crescut.Microprocesoarele au fost iniţial folosite drept controler . fondatorul şi preşedintele companiei Digital Research – primul producător al unui sistem de operare pentru microcalculatoare.Trebuie să aibă o unitate de comandă . fiecare utilizator poate să prelucreze date. dacă mai existase unul. care a dat faliment în 1970. Piaţa minicalculatoarelor a crescut repede. Clientul care i-a comandat lui Intel microprocesorul a fost o firmă japoneză. acesta era instalat. – cea mai mare companie în domeniul sistemelor de operare în reţea. au fost dezvoltate în acelaşi timp pentru mainframe-uri. destul de simple. cel care va deveni trambulina actualelor calculatoare personale.CP/M este prescurtat de la Controlul Programului/Microcalculatorului – cel mai sugestiv nume de produs. Ele erau accesibile şi proiectate pentru a putea suporta modificări ulterioare. compania este o divizie a lui Novell Inc. Minicalculatoarele au început să fie introduse în universităţi şi alte instituţii de învăţământ. cu ajutorul unui procedeu de împărţire a timpului de folosire a procesului numit time-sharing. erau bune. Acesta a fost momentul când DEC (Digital Equipment Corporation) a devenit a doua mare companie producătoare de calculatoare din lume. În anii 1960 a apărut un nou tip de calculatoare: minicalculatoarele. după aceasta Intel nu se putea hotărî dacă să lanseze sau nu circuitul pe piaţă. nu avea nevoie de aer condiţionat şi erau mult mai uşor de folosit (cel puţin după standardele acelor timpuri) faţă de mainframe-uri. Aceşti hackers nu sunt identici cu cei din zilele noastre. inclusiv Intel 8088. minicalculatoarele erau ieftine. curaţi şi bine îmbrăcaţi. Acest sistem de operare a fost. Z80. de până atunci. Acest sistem a fost introdus şi în tehnologia de realizare a mainframe-urilor. Totuşi. pentru că erau ieftine. Imediat ce departamentele puteau justifica nevoia minicalculatorului.Primele microprocesoare au fost. Pe scurt. în anul 1951. Primul calculator comercializat a fost UNIVAC (UNIversal Automatic Computer ) realizat pe structura calculatorului EDVAC. la 42 .  Apariţia calculatoarelor personale La mijlocul anilor ´70 a apărut o nouă tehnologie: miniprocesorul. în anul 1969. CP/M Primele succese ale pieţei au fost microprocesorul Intel 8080 şi noul sistem de operare numit CP/M-80 scris pentru acest cercuit. şi în 1974 existau mai mult de 19 tipuri de microprocesoare pe piaţă. CP/M-80 a fost creat în 1975 de Gary Kildall. după standardele actuale.Această dezvoltare a dus la apariţia unui nou personaj pe scena calculatoarelor. 8080. datorită cheltuielilor necesare. mai mici.dispozitive de control – pentru maşini de spălat veselă şi frigidere. Un minicalculator poate fi folosit simultan de mai mulţi utilizatori. cu componente disc mai puternice şi programe mai sofisticate. au eşuat în mărirea productivităţii personale (în creşterea eficienţei personalului. Deţinerea unui mainframe era problema corporaţiei. cu o nouă specie de programatori. Pentru sacinile pe care le puteau rezolva în moduri în care le rezolvau.În privinţa îmbunătăţirilor aduse programelor.Din rândurile lor s-au ridicat o parte din oameni care au făcut revoluţia calculatoarelor personale. să creeze programe sau să utilizeze. a fost proiectat pe patru biţi de către inginerul Marcian E. Acesta folosea multe tranzistoare conectate pe o pastilă de siliciu pentru a realiza un dispozitiv de calcul. capabilă să interpreteze instrucţiunile obţinute din memorie şi capabilă să selecteze diferite moduri de desfăşurare a activităţii calculatorului pe baza rezultatelor calculelor. devine cunoscut ca 4004. Au adus metode noi şi eficiente în birouri şi au făcut afacirele mai eficiente. Producătorii şi proiectanţii de calculatoare nu au pierdut ocazia dată de potenţial acestor dispozitive de a fi folosite drept calculatoare. nu a corporaţiilor). pentru că acesta nu necesita spaţii speciale sau specialişti necesari unui mainframe. ca şi când ar fi singurul utilizator. Sisteme sofisticate de time-sharing. L-au lansat. Aceste maşini erau mai ieftine. ceea ce a atras un grup de entuziaşti cunoscuţi sub numele de hackeri. În faţă ereziei. „Ted” Hoff de la Intel. Astfel. dar un departament putea avea propriul minicalculator. Minicalculatoarele au adus la înlocuirea programatorilor de mainframe. Primul microprocesor.

Restul este. extraordinar. a apărut în 1976. IBM PC a devenit un standard.m.Deşi microprocesorul care a stat la bază calculatorului IBM PC a fost produs în 1974. cu sistem de operare CP/M. aveai „ultimul strigăt” al modei calculatoarelor şi îl făceai verde de invidie pe orice pasionat. numită Microsoft. Această situaţie a motivat doi studenţi de la Harvard Business School să facă primul program de calcul tabelar: Visicalc. Un singur lucru le putea depăşi invidia şi cîştiga ura: să ai un disc şi o imprimată. Deşi povestea lui Visilac şi a calculatorului Apple II este bine cunoscută. încât oamenii au trecut peste orice pentru a-şi cumpăra un calculator personal. dar au descoperit ulterior că acestea erau folosite din plin de concurenţa. aducând puterea de calcul la îndemâna utilizatorilor. trebuia să scrii un program.d.La mijlocul anilor `70. istorie. 43 .acea dată. maşinile CP/M şi Apple. ambele necesitau o cheltuială exorbitantă. cu excepţia cazului în care priviziunele aveau importanţă pentru corporaţie şi aveai suficient timp la dispoziţie. binecunoscută ca avându-şi începuturile într-un garaj. Primul tip larg răspândit împreună cu microcalculatoarele aveau discuri de 14" (comparaţi-le cu cele de 3. fără amestecul lui IBM. care putea lucra cu mai multă memorie şi mai rapid decât predecesorii săi. cu 64 kilobiţi de RAM şi o pereche de unităţi de disc flexsibil de 8". această piaţă ar fi crescut mult mai încet şi mai fragmentat. şi o dată cu el un raft întreg de aplicaţii. Intel 8088 era un microprocesor pe 16 biţi. până la 128 kilobiţi de RAM şi utiliza un casetofon pentru a stoca date şi programe. Apple a fost fondată de legendarii Steve Jobs şi Steve Wozniack. Ei au păcălit bugetele departamentale cumpărându-le ca maşini de scris sau chiar plătind diferenţa din propriul buzunar. Calculatorul IBM PC a continuat tendinţa dată de Apple II. data de naştere a calculatorului IMB PC a fost creat de piaţă. Fanaticii mainframe-urilor erau probabil cei mai surprinşi când aflau ce se întâmplase. În aceste companii.Utilizatorii cumpărau Apple II doar pentru a rula Visicalc. Apple a încheiat o înţelegere cu realizatorii lui Visicalc pentru a obţine exclusivitatea programului pe Apple II. IBM avea bani şi poziţia pe piaţă astfel încât să facă calculatorul IBM PC acceptat în corporaţii. Deşi e uşor să critici IBM pentru greşelile. făcute în dezvoltarea pieţei calculatoarelor personale şi lipsa de receptivitate faţă de o piaţă care creştea mai rapid decât putea acoperi IBM.Apple II avea la bază un procesor Motorola 6502 (proiectat pe 8 biţi). să-l depanezi. Multe companii au avut reţineri în a urma tendinţa de introducere a calculatoarelor personale. pentru a realiza un sistem de operare. IBM a delegat o companie necunoscută. în realitate o serie de standarde care au adus la vânzarea de aproximativ 100 de milioane de calculatoare personale din 1981. merită să o spunem încă o dată. Dacă aveai un sistem 8080 sau Z80. puterea marketing-ului IBM a dus la succesul lui IBM PC. să verifici rezultatele. datorită acelor sisteme de microcalculatoare care au făcut posibilă existenţa calculatorului IBM PC.5" disponibile astăzi) şi un timp de acces suficient pentru o pauză de cafea.a. aşa cum o spun ei. calculatorul IBM PC a fost produs abia în 1981. care ofereau utilizatorilor. Apple Computer. dacă doreai să faci încercări de genul „şi dacă” calculând pe mainframe.000 de dolari în 1977 la puţin sub 48 de milioane în 1979. Centrul de Calcul era uluit când descoperea invazia calculatoarelor personale. şi este recunoscut drept compania care a pus bazele industriei calculatoarelor personale. pentru prima dată la un preţ rezonabil. Acestui program i se acordă meritul de a fi catapultat Apple de la un venit de 800. Centrul de Calcul pierdea un procent destul de mare din prelucrările de date ale companiei. de obicei. să încerci un set de date. Posibilitatea de a-şi îmbunătăţi şi mări productivitatea personală a fost o atracţie atât de mare. Era un procedeu cel puţin laborios şi nu foarte practic. putere de calcul accesibilă şi dedicata IBM preia controlul Calculatoarele despre care am vorbit. destul de multe. nu erau numite calculatoare personale – acesta nu a fost un termen recunoscut până în august 1981. să încerci un set de date mai complex s. Aparent peste noapte. pentru că arată motivele care au generat revoluţia calculatoarelor personale. Ceea ce era probabil cel mai tulburător pentru ei era că utilizatorii de calculatoare personale vorbeau despre informaţii şi nu doar despre coloane de date.Discurile acelor timpuri merită puţină atenţie. Teritoriul pe care credeau că îl stăpânesc era brusc invadat.

dar aşa cum veţi vedea. preţul perifericilor de calitate era exorbitant. Cum puteai să fii sigur că documentele cu care lucrai erau la zi. Comutatorul de date oferă utilizatorului o conexiune pe portul serial sau paralel. Distribuirea datelor prin companii. care nici nu se apropia de calitatea unei letter-quality. Orice persoană (datele ce vor vi imprimate) care se aşează prima coadă (comutatorul) ajunge prima la casier (imprimanta). O altă problemă era folosirea în comun a datelor. era o resursă preţioasă. Dacă o altă persoană folosea imprimata când doreai tu să o foloseşti. (Rapoartele standard consumau o „mică pădure” de hârtie.. numele acestui tip de partajare a datelor: „reţea sportivă”. Restul trebuia să aştepte până ce aceasta termină. de a schimba documentele electrice între calculatoare. Începutul conectării Pe timpul CP/M-ului. O imprimată matriceală. trebuia să iei dischetă. mai mult decât orice. De aici. Un comutator de date poate fi comparat cu o coadă la bancă.? Existau sute de probleme cu această reţea şi toate evidenţiau o singură soluţie: nevoia. Puteau realiza rapoarte despre ceea ce îi interesa. Dacă aveai nevoie de un document creat de altcineva. Corporaţiile aveau toate motivele să susţină noua tendinţă şi în acelaşi timp destule motive de îngrijorare pentru anarhia care se crea. 44 . cu pălăria în mână (metamorfic vorbind) la Centrul de Calcul. În momentul lansării calculatorului IBM PC preţurile scăzuseră. şi aveţi o problemă la care să meditaţi. şi singura. dacă ai fi cerut la Centrul de Calcul un raport. să ruleze programul de calcul tabelar şi să realizeze o duzină de scenarii.Utilizatorii au descoperit că puteau combina şi prelucra cum doresc datele. Astfel a apărut o nouă tendinţă: aceea de a a-ţi realiza singur calculele. cum veţi vedea. ca exemplu o imprimată. au trebuit să urmeze sau cel puţin să se obişnuiască cu valul tehnologiilor aduse de calculatoarelor personale. dacă diverse copii modificate de un număr oarecare de oamenii circulau pe diverse dischete? Cum poţi opri furtul documentelor? Cum poţi opri furtul documentelor? Şi dacă ultima versiune. perifericele calculatoarelor personale erau ca aurul: rare şi scumpe. care consuma 5 amperi şi făcea zgomot ca un avion care decola. Pe scurt. Combinaţi cu dorinţa de a schimba. Nu era practic ca fiecare calculator să aibă disc şi imprimată. absolută necesitate. Pe de altă parte.Deja nu mai exista nici o posibilitate pentru Centrul de Calcul de a schimba lucrurile. deşi fără ele productivitatea calculatoarelor personale era mai mică. 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. Atunci când utilizatorii doreau să facă simulări financiare de tipul „şi dacă”. a unui document se află pe o singură dischetă folosită de cineva drept suport pentru ceaşcă de cafea? Şi dacă. ei nu mai trebuiau să meargă. dar erau încă destul de mari. Puteau să-şi pornească calculatorul personal. când toţi utilizatorii doreau doar o pagină ). „Reţeaua sportivă” Acest tip de reţea a ridicat multe probleme. ţi-ar fi dat doar un raport standard aşa cum le genera mainframe-ul. de a folosi în comun discuri şi imprimate scumpe. Nevoia de a folosi în comun date şi periferice a stimula crearea primei reţele locale de calculatoare. în timpul în care Centrul de Calcul ar fi luat în considerare cererea lor. să-ţi pui pantofii de sport şi să alergi la acel microcalculator să-l iei. era tot atât de scump ca şi un calculator. Revoluţia calculatoarelor personale. a forţat Centrele de Calcul să-şi regândească rolul şi tehnologia pe care o foloseau.. trebuia să aştepţi până termina. De asemenea. Ele nu au avut cu adevărat de ales şi au devenit Servicii de gestiunea de informaţie (Management Information Service) sau IT (Information Tehnology) sau orice altceva care conţinea cuvântul informaţie. problema centrală a fost nevoia de a folosi în comunicatie. avea multe implicaţii şi exista marele risc de a scăpa totul de sub control. Calculatorul care nu mai are nevoie de periferic trebuie să trimită o secvenţă de caractere prin care spune de fapt „Am terminat”. Un disc de 14" şi 10MB. pe bază căreia primul utilizator care cere primeşte dreptul de folosi imprimanta.

Aplicaţiile de pe server au tendinţa să devie mai mari şi mai complexe şi au nevoie de mai multă memorie RAM.Aceste dispozitive. Deci. Clienţii trebuie doar să aibă suficientă putere de calcul pentru a rula partea frontală (front-end). acum învechită. Dezavantajele sistemelor client/server:  Complexitatea: nu este simplu. Aplicaţiile acestea pot fi descrise ca având doar client. care trebuia realizat de clienţi.  Performanţele pot fi îmbunătăţite uşor. de aici. deoarece o mai bună proiectare a serverului poate duce la o mai bună coordonare a utilizatorilor care doresc servicii în acelaşi timp şi. Utilizatorii nu pot vedea fişierele de date decât dacă li se dă acest drept în mod explicit. să configurezi şi să administrezi sisteme client/server. printr-o tehnică de comunicaţie oarecare. De exemplu. Singura parte care se putea afla în reţea. (Când sunt necesare performanţe mai mari. Funcţionarea reţelei Aplicaţia client/server Primele aplicaţii de reţea erau în majoritate programe integrate. iar serverul le va trimite doar rezultatele pe care le doresc. necesitau o linie dedicată între calculator şi comutator. de obicei. Un disc server era un calculator. „Aici servesc discuri” Prima încercare de a realiza ceea ce astăzi numim reţea locală (LAN) a fost tehnologie. Necesităţi: pentru a avea mulţi utilizatori. Avantajele sistemelor client/server sunt următoarele:  securitate mai bună. e suficient ca ele să trimită cereri către server. În ultimii ani au apărut un număr mare de sisteme de bază de date sofisticate care pun în reţea „motorul” de acces la baza de date care se află în parte frontală (front-end) utilizatorul. dacă ofereau o bază de date multiutilizator ele aveau şi partea frontală (front-end) de interacţiune cu utilizatorului şi „motorul” bazei de date (partea de program care lucra cu fişierele bazei de date) pe acelaşi PC. mai scump). era baza de date. performanţe mai bune. El rula un sistem de operare special care era proiectat astfel încât să poată permită accesul mai multor clienţi în acelaşi timp la disc şi la imprimată: acest sistem se numeşte sistem de operare pentru reţea (Network Operating System sau NOS). De asemenea. Creşte raportul calitate/preţ. serverul de bază de date trebuie să ruleze pe o maşină dedicată acelui server. În această configuraţie. şi imposibil dacă erau mai multe calculatoare. Alte aplicaţii client/server includ servere de poştă electronică. respectiv. sisteme de vizualizare pe calculator a imaginilor şi urmărire serviciilor de reţea. acolo 45 . serverul poate fi înlocuit cu un calculator personal mai performant şi. pe server. Pentru a reface performanţele. deoarece accesul la datele din baza de date server este indirect. era legat de un grup de calculatoare numit clienţi. Aceasta devenea dificil de realizat când calculatoarele erau răspândite pe o suprafaţă mare. deşi erau bune pentru imprimantă şi plotere (ele încă mai sunt folosite – câteva companii încă le mai oferă ). nu permiteau folosirea în comun a discurilor. mai există şi avantajul faptului că serverul poate deservi mai mulţi clienţi în acelaşi timp. căutare a înregistrărilor dorite între datele citite etc. este acum realizat de server. Întregul proces de sincronizare al accesului la baza de date. numim disc server. O dată cu îmbunătăţirea performanţelor datorită eliminării supraîncărcării reţelei cu transferuri mari de date. Serverul era o simplă „pompă” de date: trimitea utilizatorului date din fişierele aflate pe disc sau le primea şi le stoca pe disc. calculatorul client realiza toată prelucrarea datelor (citire. Acestea se numesc sisteme client/server. Bazele de date nu sunt singurele aplicaţii care pot fi realizate în sistem client/server. serverul din sistemele client/server are nevoie de un calculator scump.). Preţ: performanţele serverului scad o dată cu creşterea numărului de utilizatori. prin care. În cazul severelor de baze de date prin reţea pentru a găsi ce îi interesează. ceea ce face aplicaţiile mai simple şi întregul sistem mai eficient.

orarul grupului poate fi examinat şi poate fi găsit momentul când toţi membrii sunt disponibili. Fluxul muncii este concept atât de important în reţele. el manipulează cu elemente de nivel hardware.  Servicii de bibliotecă (pentru administrarea documentaţiilor aparţinând unui grup). Sistemul permite duplicarea şi sincronizarea mai multor copii de baze de date. Când vor să-şi coordoneze activităţile. port de intrare / ieşire etc. fizic. care funcţiona şi ca server de bază de date. Una dintre cele mai lăudate aplicaţii ale tehnologiilor de grup. încât multe dintre principalele companii producătoare de produse de reţea au investit în companii care dezvoltă tehnologii de bază pentru suportul fluxului muncii. concepte de nivel logic. este un sistem de baze de date cu poştă electronică. Problema cu aplicaţiile de grup este că e greu ca oamenii să se obişnuiască cu ea! („Poţi să duci un cal la apă. limba engleză …) . Mare parte a sistemelor care se ocupă de fluxul muncii se bazează pe formulare. Ideea este ca o dată ce reţeaua uneşte utilizatorii.unde cândva era un server dedicat general. aceştea pot fi rugaţi să va şedinţă (sau în organizaţiile mai autoritate li se ordonă). Lotus Notes.  Sisteme de control al versiunii (asemănătoare cu serviciul de bibliotecă. dar nu poţi să-l faci să bea. 46 . Aceste idei au fost aplicate la procese cum sunt planificate şi administrate proiectelor. open). Un limbaj de nivel scăzut este foarte apropiat de maşină. Un limbaj de nivel înalt sau foarte înalt manipulează cu concepte apropiate de limbajul natural. NIVELE ALE LIMBAJELOR DE PROGRAMARE “Nivelul” unui limbaj este apreciat prin poziţia pe care o ocupă pe scara constituită de limbajul recunoscut de microprocesor (limbaj maşină) şi limbajul natural al programatorului (limba română. ceea ce duce cel puţin la dublarea costului. locaţie de memorie. Tehnologii de grup Tehnologiile de grup (groupware) sunt un set de tehnologii care au scopul de a îmbunătăţi productivitatea a doi sau mai mulţi utilizatori care cooperează în realitate unor obiective comune. pe care apoi le transmit. Deoarece calculatoarele îmbunătăţesc dialogul între membrii grupului şi urmăresc progresele lor. Folosind poşta electronică. un grup de oameni care muncesc împreună într-o activitate comună sau pentru obiective comune poate fi mult mai eficient decât un grup de oameni care muncesc independent. nume de operaţie (sort.”). Ele au mecanisme pentru contabilizarea şi urmărirea tranzacţiilor şi raportarea stadiului muncii. deoarece calculatoarele sunt mai de încredere decât oamenii. dacă e posibil cu date suplimentarea din alte surse. Alte caracteristici ale aplicaţiei de grup:  Sisteme de informare (oferite în sisteme de poştă electronică cum ar fi cc: Mail). Teoretic. de exemplu să stabilească o întâlnire.  Baze de date folosite în comun. detaliile nu vor mai fi omise. writeln. dar cu facilităţi de control al arhivării şi găsirii diverselor versiuni de fişier. iar desfăşurarea poate fi foarte uşor de urmărit. la un număr oarecare de utilizatori. Ideea este că grupurile de utilizatori care sunt într-o reţea pot beneficia de automatizarea activităţilor de rutină. aceste sisteme sunt de obicei folosite pentru dezvoltarea programelor). celorlalţi membri. cum ar fi : registru. microprocesor. O altă direcţie principală a aplicaţiilor de grup este posibilitatea urmăririi fluxului muncii. variabile. acum avem un server dedicat general şi un server de baze de date dedicat. munca şi comunicările cu privire la ea pot fi automatizate pentru îmbunătăţirea fluxului muncii şi a oportunităţilor.  Sisteme de conducere a proiectelor. constante ( asemănătoare ca înţeles cu cele din matematică). Rolul lui Notes este de a răspândi informaţiile deţinute în bazele de date ale organizaţiilor. Planificarea în reţea permite unui grup dintr-o reţea să-şi facă orare pe reţea. Obiectivele vor fi mai rar uitate sau amânate. Ele primesc date de la o persoană. cum ar fi: colecţie de date.

dar ele sunt organizate logic în blocuri (grupuri de instrucţiuni) ce realizează o acţiune bine determinată. pe măsură ce limbajul are un nivel mai ridicat execuţia programului conceput cu ajutorul său va fi mai lentă. pe când cele nespecializate lasă în sarcina programatorului manevrarea nivelelor inferioare ale problemei. execuţia sa fiind ramificată la un anumit moment de timp. Limbaje orientate Din punctul de vedere al aplicabilităţii unui limbaj. Prin contrast limbajele neconcurente (majoritatea limbajelor) au o desfăşurare liniară. Deci din punct de vedere al reducerii timpului de realizare a unui program şi al siguranţei în funcţionare (absenţa erorilor de programare) este de preferat un limbaj de nivel cât mai ridicat (înalt sau foarte înalt). Prin contrast.Cu ajutorul unui limbaj de nivel înalt programatorul se face mult mai uşor înţeles de către calculator . Limbajele neprocedurale sunt concepute pentru a gândi un program la nivel de instrucţiune. Limbaje concurente Un limbaj concurent permite definirea de procese (prelucrări) paralele. fiind activ un singur proces la un moment dat. limbajele pot fi orientate pe o anumită problemă sau concepute pentru soluţionarea oricărui tip de problemă – limbaje de uz general sau altfel spus. deoarece acestea sunt detaşate de maşină. Uneori o singură limie de program scrisă cu un astfel de limbaj poate echivala cu sute de linii de program scrise în limbaj maşină. decât a unui program ce realizează aceleaşi operaţii dar este scris în limbaj de asamblare.executabil. Procesele concurente presupun în mod obligatoriu un sistem multi-tasking ce poate gestiona mai multe „sarcini” la un moment dat. neorientate pe o problemă. Deci. Un limbaj procedural oferă posibilitatea utilizării unui nivel ridicat de concepere a unui program şi duce la realizarea de programe coerente şi protejate la erori. Limbajele neprocedurale sunt încă preferate de unii utilizatori datorită timpului foarte scurt cât decurge învăţarea şi utlizarea lor. Limbajele orientate prezintă un grad înalt de specificitate pe când un limbaj neorientat reprezintă un cadru general ce permite introducerea de către utilizator a conceptelor şi prelucrărilor dorite. Cele specializate posedă deja integral suportul necesar şi permit programatorului să se concentreze la ansamblul problemei. pe când cele procedurale. adică posibilitatea transferării programelor pe un alt tip de maşină decât cea pe care au fost construite. Diferenţierile care se pot face pentru limbajele de nivel scăzut sunt următoarele: 47 . Din acest punct de vedere limbajul de asamblare este neportabil deoarece el este specific microprocesorului. În general un bloc are un punct de intrare şi un punct de ieşire – nu mai multe. Limbaje de nivel scăzut Această categorie de limbaje are un reprezentant autoritar şi anume: limbajul de asamblare. procedurale şi neprocedurale. se diferenţiază prin nivelul de organizare (structurare) a unui program. obligă programatorul să conceapă programe la nivel de bloc. Programele realizate pe un tip de maşină trebuie rescrise integral pentru noul tip de maşină . Între un astfel de program şi calculator se interpune compilatorul (sau interpretorul) care rezolvă corect transformarea fişierului-sursă în fişier . Limbaje procedurale – neprocedurale Cele două tipuri de limbaje. diferenţa esenţială dintre cele două tipuri de limbaje o constitue nivelul conceptual definit. În schimb. Într-un limbaj procedural (numit şi limbaj structurat) programele sunt scrise instrucţiune cu instrucţiune. Lucrurile stau altfel cu programele concepute cu ajutorul unui limbaj de nivel înalt. O altă diferenţă esenţială între cele două tipuri de limbaje o reprezintă portabilitatea. folosind un nou set de instrucţiuni – care deobicei diferă foarte mult. limbajele neprocedurale nu favorizează programatorul în a se desprinde de nivelul „instrucţiune” şi duc deseori la programe greu de controlat – mai ales în cazul programelor de dimensiuni mari.

Aspectul unui limbaj poate fi schimbat radical de mediul de programare oferit . date (structuri) definite de utilizator.  structuri de date dinamice. permite construirea de aplicaţii. funcţii trigonometrice. destinat începătorilor). din confruntarea cu probleme concrete ale programării.  după mediul de programare oferit. Din cauză că a cunoscut o largă răspândire. de uz general. QUICK BASIC. numere reale în dublă precizie. menţinându-se ca atare şi în prezent. TURBO BASIC. Limbajul PASCAL a introdus în versiunea sa iniţială noţiunea de programare structurată şi ulterior noţiunile de date (structuri) dinamice. – neorientat pe un anumit tip de problemă. începând cu pachete ce operează în mod linie şi culminând cu medii integrate în care toate operaţiile se pot declanşa de la un acelaşi pupitru de comandă .A. – este un limbaj nestructurat.  definirea de noi funcţii sau proceduri. Deşi nu poate fi considerat „depăşit” din punct de vedere conceptual (este un limbaj algoritmic – structurat) este neindicată folosirea lui datorită absenţei unor medii de programare performante şi pentru că tendinţa actuală îi este defavorabilă. dintre care se detaşează Turbo Asamblorul firmei Borland TASM. Iniţial reprezenta un limbaj orientat pe calcule ştiinţifice având definite concepte precum: matrice. Denumirea sa provine de la iniţialele cuvintelor Beginner’s Allpurpose Symbolic Instruction Code (Cod de instrucţiuni simbolice. instrucţiunile sale sunt cuvinte din limba engleză sau prescurtări ale acestora. PASCAL Conceptualizat în anul 1970 de către Niklaus Wirth. ceea ce îi permite să fie uşor învăţat. în semn de recunoaştere a meritelor sale în teoretizarea maşinilor de calcul. au fost implementate noi versiuni de Basic: GWBASIC. Fortran for Windows. În prezent standardul implementărilor PASCAL cuprinde următoarele elemente:  programare structurată de tip algoritmic. Regulile respectate de versiunile limbajului de asamblare sunt : – nouă versiune o include complet pe cea anterioară. datorită faptului că posedă o solidă bază conceptuală.  Limbaje de nivel înalt neorientate BASIC A fost creat în 1964 la Darmooth College (S. Creat după acumularea de cunoştiinţe temeinice în ştiinţa limbajelor formale.după tipul de maşină. limbajul PASCAL poartă numele matematicianului şi filosofului BLAISE PASCAL.U. 48 . VISUAL BASIC (Basic for Windows). – versiunea nouă oferă funcţii suplimentare şi le realizează pe cele vechi mai rapid. Versiunile ulterioare care au cunoscut o mare popularitate au extins posibilităţile limbajului trasformându-l într-un limbaj eficient. FORTRAN Limbajul Fortran este decanul de vârstă al limbajelor de largă folosinţă. În prezent există pentru IBM-PC două implementări mai importante ale limbajului: Microsoft Fortran. A apărut în 1956 şi îşi datorează numele prescurtării cuvintelor: FORmula TRANslation (Traducere de formule). de uz general.  tipuri de date definibile de către utilizator. limbajul PASCAL a constituit la vremea respectivă un limbaj modern.). Pentru limbajul de asamblare există mai multe implementări disponibile. Nu sunt luate în considerare decât aceste medii integrate (denumite generic medii Turbo). Are următoarele caracteristici fundamentale : – simplu de învăţat.

A. Combinaţia PASCAL + TURBO a reprezentat un succes imens în rândul programatorilor având ca singur rival cealaltă combinaţie: C+TURBO.  concizie deosebită a limbajului.  tipuri de date definibile de către utilizator. Limbajul C Acest limbaj de programare .  funcţii de apel servicii DOS.  definirea de noi funcţii. a fost creat în 1971 de către Dennis Ritchie şi Brian Kernigham pentru dezvoltarea sistemului de operare UNIX.  funcţii elementare de grafică 2D. Versiunile implementărilor limbajului ADA pe IBM-PC nu posedă tocmai acestă parte de concurenţă. ceea ce permite exploatarea portabilă a caracteristicilor intime unei maşini.  adresări indirecte ale datelor .  set complet de funcţii matematice.  rutine complete de intrare / ieşire.0.  posibilitatea definirii de overlay-uri pentru un program. TURBO PASCAL 5. Versiunile standard ale implementărilor PASCAL sunt cele oferite de Microsoft şi Borland.  rutine de conversie a datelor foarte evoluate. Principalele caracteristici ale limbajului sunt:  limbaj structurat de nivel înalt.  funcţii pentru realizarea de grafică elementară 2D. Deci. variabilelor ( pointer-i ). reducând limbajul la un simplu limbaj structurat de uz general.  Pentru versiunile standard ale implementărilor limbajului C există medii de programare de tip “TURBO” ce aparţin firmelor: Microsoft – produsul QUICK C şi firmei Borland – produsele TURBO C. ADA este un limbaj ultramodern din punct de vedere teoretic dar ineficient din punct de vedere practic pentru IBM-PC-uri.  posibilitatea inserării direct în sursă a instrucţiunilor în limbaj de asamblare.  set complet de funcţii matematice.S.  posedă concepte de nivel scăzut. Saltul calitativ este evident şi deschide un nou domeniu în programare … dar nu pentru IBM-PC. Limbajul ADA A fost creat special pentru a gestiona totalitatea aplicaţiilor dezvoltate şi utilizate de N.  recursivitate. Noutatea limbajului (de tip structurat. cu cel mai scurt nume .  recursivitate. algoritmic) o constitue concurenţa. adresări indirecte ale datelor.  gestionarea elaborată a datelor de tip dinamic. O explicaţie a acestei orientări e dată de faptul că o bază de date reprezintă o informaţie.5) datorită mediului de lucru performant (de tip “TURBO” ).  funcţii de conversie a datelor din ASCII în format intern şi invers. iar cel ce deţine informaţii complete şi rapide într-o anumită problemă este 49 . deci posibilitatea lansării de procese paralele (sincronizate interactiv în finalul execuţiei lor).  posibilitatea definirii de overlay-uri pentru program. Limbaje orientate pe gestiunea bazelor de date Necesităţile actuale în practica utilizării calculatoarelor se îndreaptă cu precădere spre gestionarea bazelor de date de mari dimensiuni.A. cu avantaj pentru cele din urmă (TURBO PASCAL 5.

datele sunt gestionate prin intermediul unei structuri.B.  interactivitate bună a sistemului.  limbaj de nivel foarte înalt .  preţ de cost redus faţă de cele relaţionale.D.D.  programare. la un nivel de organizare logică. Deci.D.  pot funcţiona pe un sistem de calcul ce nu implică resurse speciale. Această nouă concepţie permite definirea de structuri 1:n. Acestea nu mai sunt privite ca simple fişe izolate între ele ci pot fi analizate pe baza legăturilor (relaţiilor) ce există între ele.D. Avantajele unui S. Structurile de tip 1:n pot fi rezolvate şi cu ajutorul unui S. simplu de învăţat. dar întreaga gestiune a operaţiilor revine programatorului pe când un mediu relaţional furnizează din start servicii speciale. un mediu relaţional presupune ca cerinţă minimală posibilitatea manipulării datelor prin intermediul conexiunilor logice stabilite.  linie în tabel – echivalentul unei înregistrări clasice.G.G. Spre deosebire de S.  nivel superior de portabilitate a aplicaţiilor.B.  prelucrări (regăsiri) de date cu un înalt nivel de complexitate. O “înregistrare” poate conţine n valori pentru un “câmp” anumit nu una singură ca în cazul clasic. Avantajele unui S. organizată ierarhic. conectate prin valorile anumitor coloane.  definire ordine de returnare a datelor. deci efort de studiu redus.G.  baza de date – colecţie de înregistrări.G. S. datelor.  bază de date – o colecţie de tabele.indiscutabil cu un pas înaintea celorlalţi. Concurenţa din domeniul economic poate fi numită pe bună dreptate o bătălie informaţională. Prin intermediul său sunt permise următoarele operaţii:  regăsire date (conexate logic) ce îndeplinesc o anumită condiţie. El poate fi considerat un “BASIC” al bazelor de date.  redefinire conectări logice ale datelor. ci doar spaţiu de stocare extern suficient pentru problema dată.B.-urilor.  coloană în tabel – echivalentul unui câmp de tip clasic. 50 .G.-urile clasice.B. Un sistem de gestionare a bazelor de date (S.B. clasic sunt:  simplitate în manevrare.  exploatare. Pentru aceasta există definit (şi impus ca standard unanim recunoscut) limbajul de interogare SQL (Structured Query Language – limbaj de cereri structurate). La momentul apariţiei a constituit o adevărată revoluţie în domeniul S. clasic. -uri clasice dBASE III Cel mai răspândit sistem de gestiune a bazelor de date este dBASE.G. relaţional sunt următoarele:  tabel – structură fundamentală de “depozitare” a datelor. Noţiunile cu care operează un S.B.D.B.  înregistrare – mai multe câmpuri alcătuiesc împreună o înregistrare.D.D.B.D. Diferenţa esenţială constă în definirea unui nivel logic suplimentar între datele gestionate. Tendinţa modernă în exploatarea bazelor de date constă în deplasarea interesului către bazele de date relaţionale.) de tip clasic operează cu următorii termeni fundamentali:  câmp – o locaţie în care se poate memora o informaţie bine determinată. în diversele lui versiuni. relaţional sunt:  nivel logic superior (corelaţii. structuri 1:n ). Meritele sale principale care l-au impus atenţiei utilizatorilor şi programatorilor sunt :  foarte simplu de utilizat.G.G.

 limitări de lucru greu sau imposibil de atins (maxim 65535 caractere într-un câmp.  un limbaj intern (o versiune de PASCAL) cu care se prelucrează datele.D. Oracle este implementat pe majoritatea tipurilor de computere mari. Caracteristicile ce îl fac interesant sunt:  interactivitate bună.  posibilitate definire structuri 1:n.10 şi FOXBASE PRO se constitue în medii performante atât pentru programatori cât şi pentru utilizatori.B. Cele mai importante implementări ale sale sunt: dBASE III Plus şi dBASE IV.D. S. PARADOX 51 .  aplicaţiile create slab interactive. dar mai ales posibilitatea conectării la calculatoare puternice. sugestivă. Versiunile FOXBASE 2. datorită popularităţii sale şi pe de altă parte a calităţilor scăzute ale implementărilor originale furnizate de firma Ashton-Tate. COBOL A fost creat în 1950 şi reprezenta singura posibilitate de gestionare a unei baze de date.G.B. ISIS Este distribuit gratis de către UNESCO. Pe lângă faptul că posedă avantajele unui mediu de tip relaţional ORACLE este gândit ca un sistem exhaustiv pentru rezolvarea problemelor de utilizare sau programare.  imposibilitateta conectării cu un alt limbaj. COBOL este echivalentul FORTRAN-ului pentru sistemele de gestiune a bazelor de date (din punct de vedere istoric şi al performanţelor). număr nelimitat de câmpuri.  limbaj de programare cu lacune greu de surmontat (nu posedă salturi.  Dezavantajele principale ale dBASE-ului sunt:  viteză de lucru extrem de scăzută. –uri relaţionale ORACLE Se poate afirma fără teama de a greşi că ORACLE reprezintă cel mai performant S. Singurul avantaj real al COBOL-ului este portabilitatea sa ridicată. Limbajul este considerat greoi şi inflexibil. iar pentru crearea unui program foarte simplu e nevoie de scrierea unui adevărat eseu. de înregistrări).G. disponibil la momentul actual. ceea ce oferă portabilitatea aplicaţiilor. Dacă facem o comparaţie. Limbajul intern folosit este SQL Plus şi este permisă conectarea cu alte limbaje externe evoluate (orientate către C).  exploatare eficientă a spaţiului pe disc (memorarea câmpurilor în format variabil). poate funcţiona cu resurse extrem de restrânse. FOXBASE Sistemul dBASE a incintat firmele producătoare de soft. Putem menţiona:  viteză de lucru foarte bună. ceea ce îl face cu adevărat interesant.  adaptabilitate foarte bună. Au apărut noi implementări ale limbajului care au încercat să furnizeze unelte profesionale pe baza acestui suport conceptual. funcţii matematice reduse. erori de implementare). Reprezintă în primul rând un limbaj de programare special conceput pentru informatica de gestiune.  exploatare interactivă la nivel SQL.  suport de reţea locală.

prezentări). iar efortul necesar realizării lui este minim. cele folosite de spread-sheet-uri sunt special concepute pentru a fi folosite de nespecialişti (uşor de învăţat. La nivel de ansamblu. diagramă. Dezavantajele principale ale aplicaţiilor realizate cu ajutorul unui spread-sheet le constitue imposibilitatea depăşirii cadrului de „programare” oferit şi dificultatea de a realiza prelucrări foarte complexe .  sistem de gestiune a bazelor de date (pentru celulele unui tabel). Cele mai cunoscute şi răspândite produse de tip „calcul tabelar” sunt: LOTUS 1-2-3 Lotus 1-2-3.  tipărire de calitate (posibilitatae de a lucra cu mai multe tipuri de imprimante. Aplicaţiile de tip „tabelă de calcul” au fost concepute în ajutorul funcţionarilor. produs al firmei Lotus Development este în mod sigur cel mai răspândit produs din această categorie. LOTUS se preuintă ca o aplicaţie cu bună interactivitate. Un astfel de limbaj (de tip interpretor) se constituie într-un cadru general pentru rezolvarea problemelor funcţionarilor din diverse domenii de activitate. Însă aceste dezavantaje sunt mai mult teoretice deoarece nu este cazul de a realiza aplicaţii cu astfel de cerinţe folosind un spread-sheet.  un tabel este format din linii şi coloane. a acoperi cu un strat). În traducere directă aceasta ar însemna – pentru cazul de faţă – organizarea unei foi (a unui tabel). sheet-schemă. Limbaje orientate pe calcul tabelar Aplicaţiile împreună cu limbajele implementate pentru rezolvarea problemelor descrise în continuarea nu pot fi considerate medii de programare propriu-zise. foaie.  servicii şi auxiliare. desfăşurare. cu adevărat profesional.  intersecţia unei linii cu o coloană se cheamă celulă. Programele de calcul tabelar rezolvă în mod strălucit o problemă punctuală. uşor de utilizat). macroinstrucţiuni. pentru a prelua o parte imensă din rutina de lucru inerentă unor astfel de activităţi. Produsul obţinut are flexibilitate maximă. Iată cum funcţionează un program de tip spread-sheet:  elementul de lucru îl reprezintă un tabel.  în fiecare celulă poate exista una din entităţile următoare: text. 52 . la valorile care l-au generat).  funcţii de editare şi formatare a textului (editor de texte obişnuit). Datorită popularităţii sale el s-a constituit într-un adevărat standard (neoficial) pentru spread-sheet-uri. numere. exploatarea rezoluţiei unei imprimante laser. El îndeplineşte toate cerinţele unui produs cu adevărat modern şi performant şi anume:  interactivitate foarte bună.  viteză de lucru mare.D. Denumirea provine din limba engleză şi este o traducere pentru termenul „spread-sheet” (spreadîntindere. tabel. secvenţe de program.Reprezintă un S.  limbaj de programare evoluat (PAL – Paradox Application Language). Spre deosebire de limbajele de programare propriu-zise.G. fără a mai fi necesară intervenţia programatorului. set bogat de fonturi).  posibilitatea de lucru multi-tabel (mai multe tabelel simultan).B. O aplicaţie realizată cu un spread-sheet poate fi modificată şi adusă la zi direct de către utilizator. dotat cu compilator.  funcţii grafice (diagrame. Pe lângă aceste caracteristici specifice unui spread-sheet cerinţele minimale ale unui pachet de calcul tabelar includ:  posibilitatea „căutărilor inverse” (de la rezultatul unui calcul. formule.  tabelul este vizualizat pe ecran prin intermediul unei ferestre.

 posibilitatea definirii de macroinstrucţiuni. MATHLAB. Câteva specificaţii tehnice pentru EXCEL ar fi:  tabelă cu dimensiunea maximă de 1638 x 256 celule. Limbajul este capabil să opereze deducţiile (deciziile) necesare pentru a rezolva problema într-un caz particular ce apare în practică. EXCEL Produsul firmei Microsoft. De aici rezultă în mod direct unele din caracteristicile sale (utilizare mai comodă. 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 săi adăugând şi multe facilităţi proprii. computerizarea procesului de producţie. aceste limbaje descriu problema de rezolvat (în termenii deducţiilor logice) pe când limbajele de tip algoritmic descriu metoda de rezolvare a problemei. Modalitatea de programare este descriptivă şi are intenţia declarată de simulare a raţionamentului uman.0 Spread-sheet-ul QUATRO.  tabelele şi grafica pot exista pe foi distincte. funcţii grafice deosebit de puternice. În plus sunt oferite instrucţiuni absolut necesare pentru a controla un program.  conţine suport de funcţionare în reţea. MATHEMATICA.  se pot folosi maxim 4 fonturi la un moment dat. Aşadar. EXCEL este o aplicaţie care funcţionează sub Windows.  funcţioneauă după principiul WYSIWYG. Limbaje orientate pe programarea inteligenţei artificiale Acest tip de limbaje diferă esenţial de cele algoritmice. de integrare. 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. Expresiile manevrate pot conţine operaţii algebrice elementare.Reproşurile ce i se pot aduce sunt: meniurile (uneori stufoase şi nelogic ramificate) şi help-ul care nu totdeauna este la obiect. SYMNON. Domeniile de aplicabilitate pentru limbajele de programare a inteligenţei artificiale sunt cu predilecţie: realizarea de sisteme expert (programe ce înlocuiesc experţii umani). QUATRO PRO 2. 53 . În acest scop au fost create limbaje de programare care pot recunoaşte şi rezolva formule sau ecuaţii matematice complexe. operatori de derivare. operatori diferenţiali care sunt recunoscuţi de sistem ca atare.  nu posedă funcţie de salvare automată. meniuri foarte clare şi standardizate.  limbaj de programare puternic şi flexibil. MATHCAD. robotică. iar apoi se descrie în ce constă problema ca atare. tratarea limbajelor naturale. Cele mai importante produse de acest gen sunt REDUCE.  detectează prezenţa coprocesorului matematic şi face uz de facilităţile acestuia. Alte limbaje orientate Limbaje orientate pe calcul matematic simbolic Specialiştii din domeniul cercetării matematice au la dispoziţie unelte de lucru extrem de utile pentru eliminarea calculului matematic rutinier.  lăţimea maximă a unei coloane este de 255 caractere. viteză de lucru inferioară lui Quatro). Pentru rezolvarea unei probleme sunt furnizate seturile de reguli şi informaţii necesare.  lucrează cu memoria expandată.

Pascal.  Software: limbaje de nivel foarte înalt. IBM (apar mai multe versiuni) Generaţia a V-a (1991-2002) în curs de dezvolatare  Hardware: circuite integrate pe scară ultralargă ULSI (proiectare circuite integrate 3D).  Viteză de operare: 10. Această perioadă este marcată de apariţia internetului şi extinderea rapidă a acestei reţele mondiale. proiectele galiu-arsen.  Viteza: 30 de milioane de instrucţiuni/sec.  Software: limbaje concurente.  Calculatoare: o gamă foarte largă de calculatoare. programare funcţională. apar microprocesoarele de 16/32 biţi. alte soluţii arhitecturale noi (reţele neurale etc. sisteme expert evoluate. Generaţia a II–a (1957-1963) marcată de apariţia tranzistorului  Hardware: tranzistoare.  Caculatoare: INDEPENDENT. CORAL. cod maşină. primele programe pentru grafică şi baze de date . apoi pe scară medie şi largă. sisteme distribuite de calcul.  GENERAŢII DE CALCULATOARE Generaţia I (1946-1956) caracterizată prin:  Hardware: relee.  Viteza: 200. sute de Mocteţi până la Gocteţi. tuburi electronice. scara de integrare se referă la numărul de componente electronice pe unitatea de suprafaţă). prelucrare simbolică. baze de date relaţionale. UNIVAC. se perfecţioneaza limbajele de programare orientate pe obiect.).LISP (LISt Processing language) conceput în 1976 şi implementat pe PC-uri de firma Microsoft sub forma MuLISP. cablaj imprimat. NCR501.  Calculatoare: IBM 370.000 de operaţii/sec.000 de instrucţiuni/sec  Calculatoare: IBM 7040.  Memorie: 8÷10 Mocteţi.1981) caracterizată prin:  Hardware: circuite integrate (la început pe scară redusă. primele elemente optice (discurile optice).  Software: limbaj de nivel înalt ( Algol.  Software: programe cablate. IBM. programare orientată pe obiecte B. FELIX  Comunicaţii: Primele comunicaţii prin satelit. programare structurată LISP. acum apar şi sistemele de operare windows.  Software: Pachete de programe de largă utilizare. Fortan)  Memorie: 32 Kocteţi. Generaţia a III–a (1964. emisiile radio de ordinul GHz.  Memorie: 1÷2 Mocteţi . 54 . reţele de comunicare prin satelit. limbaj de asamblare. arhitecturi paralele. sisteme expert. cablaje imprimate multistrat. reţele globale pe fibră optică.000 de operaţii/sec. aparariţia primelor microprocesoare.  Viteza: 5. baze de cunoştiinţe.  Calulatoare: ENIAC.  Capacitate de memorie: 2 Kocteţi. Generaţia a IV-a (1982-1989) caracterizată prin:  Hardware: circuite integrate pe scară foarte mare (VLSI).  Viteza: 1G de instrucţiuni /sec – 3 G de instrucţiuni/sec  Comunicaţiile: au atins un nivel nemaiîntâlnit.. programe de realitate virtuală. transmisia de date prin fibră optică. discuri magnetice. sisteme de operare.  Memorie: de la zeci. memorii cu ferite.000.

– se desenează şi se denumesc obiectele ce urmează a fi afişate în forma respectivă. sau pot fi declanşate de către sistem. obiectele au un comportament predefinit care poate fi modificat de utilizator prin ataşare de cod corespunzător şi aceste obiecte răspund la evenimente declanşate fie ca urmare a acţiunii utilizatorului asupra obiectelor. Într-un mediu de programare vizual. casete cu listă. Rezumând putem spune că în programarea orientată spre obiecte şi dirijată de evenimente. fie declanşate de sistem. casete de validare. Acesta era modul clasic de realizare a aplicaţiilor şi sistemelor informatice şi are o serie de dezavantaje printre care: productivitate scăzută în realizarea programelor. fie ca urmare a execuţiei codului ataşat. Pentru lucrul cu obiecte conduse de evenimente se parcurg următoarele etape: – se creează o nouă formă căreia i se dă un nume.CAPITOLUL VII LIMBAJUL VISUAL BASIC 7. obiectele principale sunt formele şi controalele desenate în forme (formă = o fereastră) Aceste obiecte pot fi create prin selecţie şi depunere folosind barele de instrumente ale mediului respectiv. Spre exemplu. efort mare pentru realizarea programelor şi mai ales a interfeţelor etc. Majoritatea obiectelor vor răspunde unui anumit număr de evenimente generate de către utilizator printre care click-uri. cod ce se va executa atunci când are loc un anumit eveniment (spre exemplu în cazul butonului evenimentul este click). fiecare program fiind constituit dintr-o secvenţă de instrucţuni scrise într-un limbaj de programare. casete derulante combinate. o aplicaţie este constituită din unul sau mai multe programe care se vor executa într-o anumită ordine. 55 . Evenimentele se produc ca urmare a unei acţiuni a utilizatorului (ex. Spre exemplu când se execută click pe un buton acesta trece în poziţia apăsat şi apoi revine în poziţia normală. butoane radio (butoane de opţiune). evenimentul click corespunde apăsării butonului stâng al mouse-ului pe obiectul respectiv). Va rezulta o interfaţă grafică cu care interacţionează utilizatorul pentru a controla evoluţia programului. Limbajul Visual Basic pune la dispoziţia utilizatorului un mediu de dezvoltare care permite crearea de programe orientate spre obiecte şi conduse de evenimente. O aplicaţie Windows afişează unul sau mai multe ecrane care conţin obiecte cu care va interacţiona utilizatorul pentru a controla evoluţia programului. În programarea procedurală. tehnologie ce va fi prezentată în cele ce urmează în cadrul limbajului Visual Basic. Pentru a schimba comportamentul obiectului acestuia trebuie să-i ataşaţi cod de program (instrucţiuni) corespunzător. bara cu instrumente Visual Basic permite crearea unei varietăţi de obiecte printre care: forme. apăsări de taste sau trageri şi eliberări ale obiectului. Fiecare din aceste obiecte are un comportament predefinit.1 Programarea aplicaţiilor Windows Pentru realizarea unei aplicaţii pot fi avute în vedere două tehnologii de programare şi anume: – programare procedurală – programare orientată spre obiecte şi dirijată de evenimente. sau în urma execuţiei codului programului. butoane. a mediilor visuale de programare şi a sistemului de operare Windows a condus la apariţia şi dezvoltarea unei noi tehnologii de programare a aplicaţiilor windows şi anume programarea orientată pe obiecte şi dirijată de evenimente. Apariţia tehnologiei orientate obiect. etc. – se ataşează fiecărui obiect codul ce va fi executat ca răspuns la evenimente generate de utilizator sau de sistem. dublu click-uri.

Buton1. culoare. btn Txt 56 Exemplu frmForma1 cmdButon.fie forma frmForma1 şi variabila dColor în care memorăm culoarea de fond a formei dColor = frmForma1. Astfel în gramatica programării orientate spre obiecte : – obiectele sunt substantive.7. Deci proprietăţile descriu obiectele iar metodele definesc acţiunile obiectelor.). etc.2 Proprietăţi şi metode Un obiect este definit de un set de proprietăţi cum ar fi: dimensiune.Move 0. frm pentru formă. Este indicat ca utilizatorul să dea nume obiectelor (Name) utilizând următoarea convenţie: – un prefix format din 3 litere mici (ex.numele dat obiectului pentru a putea fi identificat de utilizator. Exemplu . dacă un buton radio este activ sau nu la un moment dat etc. dacă codul de program asociat conţine instrucţiuni care referă şi setează proprietăţi (ca în exemplul de mai sus în care schimbăm culoarea fondului formei). Denumirea obiectelor Orice obiect are proprietăţile: Name . – proprietăţile sunt adjective. O metodă este o procedură (succesiune de instrucţiuni) asociată unei anumite acţiuni a unui obiect. iar pe de altă parte proprietăţile reprezintă date iar metodele reprezintă cod (instrucţiuni). etc. cmd pentru buton de comandă. Spre deosebire de proprietăţi.pentru mutarea obiectului Buton1 în colţul din stânga sus al formei curente se apelează metoda Move şi se precizează coordonatele colţului din stânga sus: Buton1. Visal Basic dă nume implicite obiectelor.numele utilizat în scrierea codului Capture . comportament (ex. metodele pot fi executate numai în momentul execuţiei programului (eventual în momentul depanării programului utilizând facilitatea Debugger a programului Visual Basic). De asemenea fişa Properties poate fi vizualizată prin click dreapta şi selecţie Properties. – metodele sunt verbe. Spre exemplu în Visual Basic există o metodă Move asociată majorităţii obiectelor (permite mutarea obiectelor).BackColor (citeşte culoarea curentă şi o depune în dColor) frmForma1. poziţie pe ecran. Proprietate = Valoare Exemplu .). btnOK txtCaseta1 . etc. buton. însă în plus metodele pot necesita precizarea unor informaţii suplimentare. Proprietăţile pot fi modificate şi prin program în momentul execuţiei formei.) – un şir de caractere care identifică obiectul (ex.0 Stabilire proprietăţi şi executare metode Proprietăţile unui obiect pot fi setate în faza de proiectare (atunci când se desenează sau se modifică formele) utilizând fişa Properties a formei sau obiectului din formă (fişa este automat vizualizată la selecţia obiectului respectiv: forma.). În tabelul următor sunt prezentate convenţiile de denumire a obiectelor din Visual Basic: Obiect Formă Buton de comandă Casetă de text Prefix Frm cmd. Forma1. Utilizarea notaţiei cu punct pentru referirea proprietăţilor şi metodelor Referirea unei proprietăţi se face astfel: Obiect . Referirea metodelor se face asemănător cu referirea proprietăţilor.BackColor = QBColor (Blue) – stabileşte noua culoare de fond a formei la valoarea Blue. Ecran1.

Etichetarea liniilor O linie poate fi identificată:  printr-o etichetă: orice nume.orizontală .3 Instrucţiunile VBA Generalităţi Prefix hsb vsb Mnu Chk Lst Fra Img Opt Exemplu mnuMeniuPrinc optBO1 Există trei categorii de instrucţiuni Visual Basic:  instrucţiuni de declarare (prezentate la declararea variabilelor) prin care se denumesc şi se declară tipul pentru variabile.  instrucţiuni de atribuire (prezentate în continuare) prin care se atribuie valori variabilelor sau constantelor. sintaxa instrucţiunilor este verificată automat după ce se trece la instrucţiunea următoare (prin Enter). Două instrucţiuni pot fi scrise pe o aceeaşi linie dacă sunt separate cu caracterul ":". De exemplu.verticală Meniu Casetă de validare Casetă cu lista Cadru Imagine Buton de opţiune (radio) 7. crearea prin program a unui tabel într-un document Word: ActiveDocument. Identificatorii de linii pot fi utilizaţi în instrucţiuni de control. care respectă regulile generale. _ NumRows:=3. O linie de comentariu începe cu un apostrof (') sau cu cuvântul Rem urmat de un spaţiu. Comentarii Textele explicative (necesare documentării codului) pot fi introduse pe linii separate sau în continuarea liniei de cod.  instrucţiuni executabile (prezentate în continuare) care iniţiază acţiuni: execută metode sau proceduri. În mediul de dezvoltare VBA. _ NumColumns:= 3 unde.Range. Continuarea instrucţiunilor O instrucţiune poate să fie scrisă pe mai multe linii prin utilizarea caracterului de continuare a liniei "_" precedat de un spaţiu. desi codul astfel construit nu respectă regulile programării structurate. care începe în prima coloană a liniei şi se termină cu caracterul ":"  printr-un număr: orice combinaţie de cifre. 57 . controlează fluxul execuţiei codului. pe lângă continuarea liniilor se va remarca utilizarea argumentelor numite la apelul metodei de adăugare a unui nou tabel la colecţia de tabele a documentului. care începe în prima coloană a liniei şi este unic în modulul respectiv. constante şi proceduri.Obiect Bare de derulare .Tables.Add Range:=Selection.

rezultatul este Null.Comentariul de pe aceeaşi linie cu o instrucţiune se introduce printr-un apostrof urmat de comentariu. Single. Variant(Byte). O expresie Empty este considerată ca 0. Double sau Variant(Double). Dacă o expresie este Null. Integer. rezultatul este de tipul cel "mai precis" al operanzilor. operanzi numerici produc adunarea. Operatori În formarea expresiilor de diverse tipuri. Long. Integer sau Long. Variant (Integer). operanzii sunt rotunjiţi la întregi şi se obţine restul împărţirii. Dacă o expresie este Null. Deoarece operanzii pot fi orice expresie. pe categorii. Long. rezultatul este Null. Double. O expresie Empty este considerată ca 0. O expresie Empty este considerată ca 0. Dacă o expresie este Null. pentru o informare completă (de exemplu operanzi Variant) se va studia Help – +(operator). sau Variant(Long). Integer. Long. operanzii sunt rotunjiţi la Byte. în general. însoţiţi. operanzii pot fi doar numerici. ordinea crescătoare a "preciziei" fiind. Variant(Byte). ordinea de "precizie" fiind pentru adunare şi scădere: Byte. Pentru fixarea termenilor şi notaţiilor sunt totuşi prezentaţi. Long. O expresie Empty este considerată ca 0. Rezultatul este de tipul cel "mai precis" al operanzilor. rezultatul este. Single. Pentru excepţii se va studia Help – *(operator). Rezultatul este Byte. Rezultatul este Byte. înainte de împărţire. Currency. Dacă o expresie este Null. rezultatul este Null. Double. Currency şi Decimal. Variant (Integer). Pentru excepţii se va studia Help – / (operator). Byte. în general. sau Variant(Long). rezultatul este Null. Currency şi Decimal. Integer. Long. Integer. În cazul numeric. rezultatul este Null. Dacă o expresie este Null. / Împărţirea \ Împărţirea întreagă Mod Restul împărţirii + Adunarea numerică sau concatenarea şirurilor - Scăderea sau inversarea semnului 58 . iar operanzi şiruri produc concatenarea. Single. Integer. operatorii sunt cei utilizaţi aproape general în limbajele de programare de nivel înalt. Operatori aritmetici Operator ^ * Semnificaţie Ridicarea la putere Înmulţirea Observaţii rezultatul este Double sau Variant(Double) cu excepţia: dacă un operand este Null. O expresie Empty este considerată ca 0. pentru înmulţire. Double şi Decimal. rezultatul este tot Null rezultatul este dat de cel "mai precis" factor. ordinea de "precizie" fiind pentru adunare şi scădere: Byte. acolo unde este cazul de scurte explicaţii. Pentru excepţii se va studia Help – -(operator).

rezultatul este tot Null. compararea este insenzitivă la capitalizarea textului. Construcţia şablonului poate cuprinde caractere wildcard. <= (mai mic sau egal). Operatorul Is produce True dacă variabilele se referă la acelaşi obiect şi False în caz contrar. operanzii care nu sunt şiruri se convertesc la Variant(String). [?] etc. neegal). ordinea este determinată de setările locale ale sistemului. Operatorul Like compară două şiruri cu observaţia că al doilea tremen este un şablon. Pentru alte observaţii utile se va studia Help – Like operator. Operatori de concatenare Pentru combinarea şirurilor de caractere se pot utiliza operatorii & şi +. Paranteza dreapta va fi indicată singură: ]. liste de caractere. Prin urmare rezultatul este True dacă primul şir operand este format după şablon. În sintaxa expression1 & expression2 unde operanzii sunt expresii oarecare. Rezultatul este True (dacă este adevărată relaţia). determinată în Windows de codul de pagină. False în caz contrar. 59 . un domeniu de litere poate fi dat prin utilizarea cratimei. Înainte de concatenare. Atunci când un operand este Null. domenii de caractere: • un caracter oarecare • oricâte caractere (chiar nici unul) • # o cifră oarecare (0–9). False (dacă relaţia este neadevărată). ordinea este cea a reprezentării interne binare. Comportarea operatorului Like depinde de instrucţiunea Option Compare. Expresiile Null sau Empty sunt tratate ca şiruri de lungime zero (""). dacă ambii operanzi sunt Null. Null (dacă cel puţin un operand este Null). Operatorii de comparare sunt cei uzuali: < (mai mic). care poate fi: Option Compare Binary. = (egal). > (mai mare).Operatori de comparare Relaţiile care există între diferite tipuri de entităţi se pot evidenţia prin comparaţii având una dintre formele următoare: 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 relaţional object este un nume de obiect string este o expresie şir oarecare pattern este o expresie String sau un domeniu de caractere. dacă ambii operanzi sunt String de tip Variant(String) în celelalte cazuri Null. rezultatul este: de tip String. Pentru a utiliza în şablon caracterele speciale cu valoare de wildcard se vor utiliza construcţii de tip listă: [[]. Option Compare Text. • [charlist] oricare dintre caracterele enumerate în listă. >= (mai mare sau egal). <> (diferit. • [!charlist] orice caracter care nu este în listă Observaţie.

rezultatul este Null. Null cu True sau cu Null dă Null. Atribuirea valorilor de tip utilizator poate fi efectuată doar dacă ambii termeni au acelaşi tip definit. Observaţii. doar Variant care poate fi interpretat nuric poate fi atribuit unei variabile de tip numeric. Xor Instrucţiuni de atribuire Atribuirea se poate efectua prin instrucţiunea Let (pentru valori atribuite variabilelor şi proprietăţilor). uzuali în programare. în rest rezultatul este 1. Nu se poate utiliza Let (cu sau fără cuvântul Let) pentru legarea de obiecte la variabile obiect. La atribuirea valorilor numerice pot avea loc conversii la tipul numeric al variabilei. Null Imp True este True. Null cu False (sau Null) este Null. Prin operatorul Not se poate inversa bit cu bit valorile unei variabile. False Imp * este True. Eqv realizează şi compararea bit cu bit a două expresii numerice. Operatorul Or realizează şi o comparaţie bit cu bit a două expresii numerice poziţionând biţii corespunzători ai rezultatului după regulile lui Or logic. Null Imp False (sau Null) este Null. poziţionând cifrele binare ale rezultatului după regulile de calcul ale echivalenţei logice: 0 Eqv 0 este 1 etc. poziţionându-se corespunzător un rezultat numeric. negaţia logică Not Null este Null. 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. Este de remarcat forma posibilă (şi de fapt general utilizată) fără cuvântul Let. 60 . Lset şi Rset (pentru atribuiri speciale de şiruri sau tipuri definite de utilizator). Pentru alte situaţii se va utiliza instrucţiunea Lset. [Let] varname = expression unde varname este nume de variabilă sau de proprietate. atunci rezultatul este Null. Operatorul And realizează şi operaţia de conjuncţie bit cu bit pentru expresii numerice. echivalenţa logică Dacă o expresie este Null. disjuncţia exclusivă Dacă un operand este Null. Operatorul Imp realizează şi compararea bit cu bit a două expresii numerice. Operator Semnificaţie Observaţii And conjuncţia logică Null cu False dă False. poziţionând cifrele binare ale rezultatului după regulile de calcul ale implicaţiei logice: 1 Imp 0 este 0.Operatori logici Pentru operaţiile logice sunt utilizaţi următorii operatori. implicaţia logică True Imp Null este Null. Se va utiliza în această situaţie instrucţiunea Set. Eqv Imp Not Or disjuncţia logică Null Or True este True. Set (pentru atribuirea de obiecte la o variabilă de tip obiect). Instrucţiunea Let Atribuie valoarea unei expresii la o variabilă sau proprietate. Se poate efectua operaţia de sau exclusiv şi bit cu bit pentru două expresii numerice [b1+b2(mod 2)]. reciproc nu este valabil decât dacă valoarea expresiei Variant poate fi interpretată compatibilă cu tipul variabilei: orice Variant poate fi atribuit unei variabile de tip String (cu excepţia Null).

cu aliniere la stânga. caracterele din dreapta se pierd (sunt trunchiate). GoTo. Zona de memorie alocată celei de a doua variabile este copiată (aliniată la stânga) în zona de memorie a primei variabile. Sintaxa este LSet stringvar = string LSet varname1 = varname2 unde stringvar. 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). Instrucţiuni executabile Execuţia unui program are loc. string reprezintă variabila de tip String şi expresia de acelaşi tip implicate într-o atribuire de şiruri. utilizarea acestor comenzi nu produce programe foarte structurate (în sensul programării structurate) şi prin urmare. Sintaxa este RSet stringvar = string Caracterele rămase neocupate în variabilă sunt completate cu spaţii. Instrucţiuni de transfer (GoSub…Return. 61 . În general. Acest sens poate fi modificat. Transferul controlului la acest grup de instrucţiuni şi revenirea la locul apelului se poate efectua prin GoSub…Return cu sintaxa GoSub line . într-o oarecare măsură. în locul lor fiind preferate structuri mai evoluate sau similare altor limbaje de programare.. On…GoSub. line . Instrucţiunea RSet nu se poate utiliza (analog lui LSet) pentru tipuri definite de utilizator. varname2 sunt denumiri de variabile. On…GoTo) Această categorie cuprinde instrucţiunile prin care controlul execuţiei este transferat la o altă instrucţiune din procedură. Instrucţiunea LSet Copie. de tipuri definite de utilizator (vezi instrucţiunea Type) diferite.. instrucţiune cu instrucţiune. pentru o mai mare claritate a codului. Este evident că o asemenea structură simplă nu poate cuprinde toate aspectele programării şi din acest motiv necesitatea structurilor de control a fluxului execuţiei. Deoarece copierea este binară. Caracterele care rămân neocupate se completează cu spaţii. varname1. în lipsa oricărui control.. pot fi înlocuite cu alte structuri de programare. un şir de caractere (valoarea expresiei din dreapta) într-o variabila de tip String. un şir de caractere (valoarea expresiei din dreapta) într-o variabila de tip String. Return unde line este o etichetă de linie sau un număr de linie din aceeaşi procedură. OnError.. nenumite) identificată prin linia de început. Unele instrucţiuni au fost păstrate doar din motive de compatibilitate cu versiunile iniţiale ale limbajului. prima executată produce saltul la instrucţiunea care urmează celei mai recente instrucţiuni GoSub executate.Instrucţiunea LSet Copie. iar dacă zona de unde se copie este mai mare. de la stânga la dreapta şi de sus în jos. cu aliniere la dreapta. prin ordinea de precedenţă a operaţiilor în evaluarea expresiilor. GoSub…Return În cadrul unei proceduri un grup de instrucţiuni poate fi organizat ca o subrutină (similar unei proceduri on-line. Pot exista mai multe instrucţiuni Return.

GoTo Realizează tranferul controlului execuţiei la o linie din aceeaşi procedură. GoTo line unde line este o etichetă de linie sau un număr de linie din aceeaşi procedură. On Error Permite controlul erorilor prin transferul controlului la rutine de tratare. Observaţie. Este prezentată în secţiunea dedicată controlului erorilor. On…GoSub, On…GoTo 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ă având 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 aceeaşi procedură cu instrucţiunea. Dacă valoarea expresiei este negativă sau mai mare decât 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 decât numărul de elemente din listă, transferul se efectuează la linia care urmează instrucţiunea On...GoSub sau On...GoTo. Instrucţiuni de terminare sau oprire a programului (DoEvents, End, Exit, Stop) Terminarea execuţiei programului sau oprirea temporară (pauza) se pot realiza prin instrucţiunile enumerate aici. DoEvents Deşi nu este o instrucţiune VBA ci este o funcţie, includerea ei este naturală prin aceea că permite cedarea controlului către sistemul de operare, care poate astfel să funcţioneze în regim de multitasking. Acţiunea poate fi realizată şi prin alte tehnici (de exemplu utilizarea unui Timer etc.). Sintaxa este DoEvents( ) Funcţia 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. Observaţie. Pentru alte observaţii se va studia documentaţia comenzii DoEvents. End Termină execuţia unei proceduri (sub forma prezentată aici) sau indică sfârşitul codului unei structuri de tip bloc (cum ar fi End Function, End If etc., prezentate la structurile respective). Sintaxa, în ipostaza opririi execuţiei, este: End Prin această instrucţiune, care poate fi plasată oriunde în program, execuţia este terminată imediat, fără a se mai executa eventualele instrucţiuni scrise pentru tratarea unor evenimente specifice sfârşitului de program (Unload, Terminate etc.). Fişierele deschise prin Open sunt închise şi toate variabilele sunt eliberate. Obiectele create din modulele clasă sunt distruse, iar referinţele din alte aplicaţii la asemenea obiecte sunt invalidate. Memoria este eliberată.

62

Exit Prin instrucţiunea Exit, sub una din multiplele ei forme, se întrerupe o ramură de execuţie (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 instrucţiunea End. Stop Efectul instrucţiunii este dependent de modul de execuţiei a programului. Dacă se execută varianta compilată a programului (fişierul .exe) atunci instrucţiunea este similară instrucţiunii End (suspendă execuţia şi închide fişierele deschise). Dacă execuţia este din mediul VBA, atunci se suspendă execuţia programului, dar nu se închid fişierele deschise şi nu se şterge valoarea variabilelor. Execuţia poate fi reluată din punctul de suspendare. Stop Instrucţiunea 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 construcţiilor de tip bloc prezentate în această secţiune se poate repeta, în mod controlat, un grup de instrucţiuni. În cazul unui număr nedefinit de repetiţii, condiţia de oprire poate fi testată la începutul sau la sfârşitul unui ciclu, prin alegerea structurii adecvate. Do…Loop Se vor utiliza structuri Do…Loop pentru a executa un grup de instrucţiuni de un număr de ori nedefinit aprioric. Dacă se cunoaşte numărul de cicluri, se va utiliza structura For…Next. Înainte de continuare se va testa o condiţie (despre care se presupune că poate fi modificată în instrucţiunile executate). Diferitele variante posibile pentru Do…Loop diferă după momentul evaluării condiţiei ş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 adevăr True sau False. O condiţie care este Null se consideră False. statements sunt instrucţiounile care se repetă atâta timp (while) sau până când (until) condiţia devine True. Dacă decizia este de a nu continua ciclarea, atunci se va executa prima instrucţiune 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 condiţia din enunţ întrucât execuţia 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. Execuţia structurilor este explicată în tabelul următor Do While…Loop Testează condiţia la începutul buclei, execută bucla numai dacă rezultatul este True şi continuă astfel până când o nouă evaluare produce False. Testează condiţia la începutul buclei, execută bucla numai dacă rezultatul este False şi continuă astfel până când o nouă evaluare produce True. Se execută întotdeauna bucla o dată, se testează condiţia la sfârşitul buclei şi se repetă bucla atât timp cât condiţia este True. Oprirea este pe condiţie falsă. Se execută întotdeauna bucla o dată, se testează condiţia la sfârşitul buclei şi se repetă bucla atât timp cât condiţia este False. Oprirea este pe condiţie adevărată.

Do Until…Loop

Do…Loop While

Do…Loop Until

For…Next Atunci când se cunoaşte numărul de repetări ale unui bloc de instrucţiuni, se va folosi structura For…Next. Structura utilizează o variabilă contor, a cărei valoare se modifică la fiecare ciclu, oprirea fiind atunci când 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 (numără repetările), de tip numeric. Nu poate fi de tip Boolean sau element de tablou. start este valoarea iniţială 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 instrucţiunile care se repetă. Dacă nu se specifică, atunci singura acţiune este cea de modificare a contorului de un număr specificat de ori. Acţiunea este dictată de pasul de incrementare şi relaţia dintre valoarea iniţială şi cea finală. Instrucţiunile din corpul structurii se execută dacă counter <= end pentru step >= 0 sau counter >= end pentru step < 0. După ce toate instrucţiunile s-au executat, valoarea step este adăugată la valoarea contorului şi instrucţiunile se execută din nou după acelaşi test ca şi prima dată, sau bucla For…Next este terminată şi se execută prima instrucţiune de după linia Next. Specificarea numelui contorului în linia Next poate clarifica textul sursă, mai ales în cazul când există structuri For…Next îmbricate. Corpul unei bucle For…Next poate include (complet) o altă structură For…Next. În asemenea situaţii, structurile îmbricate trebuie să aibă variabile contor diferite.
64

Se defineşte element ca numind următorul element din grup. o variabilă generică de tip Object. Sintaxa While condition [statements] Wend Este recomandat să se utilizeze o structură Do…Loop în locul acestei structuri. Se testează dacă element este ultimul element din grup. O asemenea structură execută o serie de instrucţiuni pentru un obiect sau pentru o variabilă de tip utilizator. sau o variabilă obiect specifică pentru biblioteca de obiecte referită.Next pot fi îmbricate cu condiţia ca elementele utilizate la iterare să fie diferite. se transferă controlul la prima instrucţiune de după Next – se părăseşte bucla fără executarea instrucţiunilor). în timpul execuţiei.. În cazul modificărilor succesive ale mai multor proprietăţi ale aceluiaşi obiect. Este utilă atunci când nu se cunoaşte numărul de elemente sau dacă se modifică. Instrucţiunile Exit For sunt explicate la For…Next. construcţii foarte complexe atunci când se numesc proprietăţile unui obiect. Codul este simplificat prin utilizarea structurii With…End With. group este numele colecţiei de obiecte sau al tabloului. Buclele ForEach. repetarea zonei de calificare poate produce erori de scriere şi conduce la un text greu de citit. For Each…Next Similară structurii For…Next. While…Wend Execută un grup de instrucţiuni atât timp cât este adevărată o condiţie. Se execută instrucţiunile din corpul buclei For. Dacă se parcurge o colecţie de obiecte. Dacă răspunsul este afirmatif. structura For Each…Next repetă un grup de instrucţiuni pentru fiecare element dintr-o colecţie de obiecte sau dintr-un tablou (cu excepţia celor de un tip utilizator). statements este grupul de istrucţiuni executate pentru fiecare element. With Programarea orientată pe obiecte produce. Sintaxa este: For Each element In group [statements] [Exit For] [statements] Next [element] unde element este variabila utilizată pentru parcurgerea elementelor. Sintaxa este: With object [statements] 65 .Count. se părăseşte bucla.. datorită calificărilor succesive. Pentru ştergerea tuturor obiectelor dintr-o colecţie se va utiliza For…Next şi nu For Each… Next. Se repetă paşii 2 până la 4. Se va utiliza ca număr de obiecte colecţie. Pentru parcurgerea unui tablou. Observaţie. conţinutul colecţiei. Controlul execuţiei se transferă la prima instrucţiune de după linia Next. element poate fi doar o variabilă de tip Variant. atunci element poate fi Variant. Execuţia unei structuri For Each…Next este: Se defineşte element ca numind primul element din grup (dacă nu există nici un element.Instrucţiunile Exit For pot fi plasate oriunde în corpul unei bucle şi provoacă abandonarea ciclării.

diferite între ele. prin urmare.. elseifstatements sunt blocurile de instrucţiuni executate atunci când condiţiile corespunzătoare sunt True. deci calificările eventuale la acest obiect vor fi efectuate. chiar dacă prin jocul operanzilor şi operatorilor rezultatul poate fi precizat mai înainte (de exemplu OR cu primul operand True). Permiţând omiterea recalificărilor din referinţele la obiectul precizat. Switch(). un sistem de luare a deciziilor similar instrucţiunii If…Then…ElseIf. execută un grup de instrucţiuni ca răspuns la îndeplinirea unei condiţii (compusă sau nu din mai multe condiţii testate secvenţial). Select Case produce un un cod mai eficient şi mai inteligibil. Select Case Instrucţiunea Select Case se poate utiliza în locul unor instrucţiuni ElseIf multiple (dintr-o structură If…Then…ElseIf) atunci când se compară aceeaşi expresie cu mai multe valori. obiectul extern este mascat complet. Instrucţiunea Select Case furnizează. Pe lângă structurile prezentate. Sintaxa permite o mare varietate de forme: If condition Then [statements] [Else elsestatements] sau If condition Then [statements] [ElseIf condition-n Then [elseifstatements] . Structuri de decizie (If…Then…Else. La utilizarea primei forme. Select Case) Ramificarea firului execuţiei după rezultatul verificării unei condiţii este o necesitate frecventă în orice implementare. Într-un bloc With nu se poate schimba obiectul procesat. Verificarea condiţiilor implică evaluarea tuturor subexpresiilor.nume" este interpretată în instrucţiunile structurii drept "object.nume". [Case Else [elsestatements]] 66 .. [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). pe aceeaşi linie.. fără clauza Else. Iif(). Sintaxa este: Select Case testexpression [Case expressionlist-n [statements-n]] . expresie de forma TypeOf objectname Is objecttype. întâlnită de altfel în toate limbajele de programare. If…Then…Else O asemenea structură. elsestatements.End With unde object este numele unui obiect sau a unui tip definit de utilizator statements sunt instrucţiunile care se execută pentru entitatea precizată. statements.. se pot utiliza trei funcţii care realizează alegeri în mod liniarizat (pe o linie de cod): Choose(). separate de ":". evaluată True dacă objectname este de tipul obiect specificat în objecttype. este posibil să se scrie mai multe instrucţiuni. La plasarea unui bloc With în interiorul altui bloc With. orice construcţie de tipul ". Totuşi. Nu se recomandă saltul în şi dintr-un bloc With.

windowstyle este Variant (Integer) şi precizează stilul ferestrei în care se va executa programul (implicit este minimizat. în caz contrar etc. Apeluri de proceduri şi programe În această secţiune se prezintă doar funcţia Shell(). VbNormalFocus 1 Fereastra are focus-ul şi este dimensionată şi poziţionată normal. Valorile posibile pentru argumentul windowstyle sunt Constanta numită Valoarea Semnificaţia VbHide 0 Fereastra este ascunsă iar focus-ul este pe fereastra ascunsă. Dacă aceasta este situaţia şi nu este specificată o clauză Case Else. valoarea minimă fiind prima specificată.End Select unde testexpression este o expresie numerică sau şir. Sintaxa este Shell(pathname[.". VbMinimizedFocus 2 Fereastra este afişată ca o icoană (minimizată) dar are focus-ul. Fereastra activă curentă îşi păstrează s focus-ul. Instrucţiunile Select Case pot fi scufundate unele în altele. Control execuţiei trece apoi la instrucţiunea care urmează liniei finale End Select. Is comparisonoperator expression. statements-n reprezintă una sau mai multe instrucţiuni care se vor executa dacă testexpression este egală cu un element din expressionlist-n. sau până la End Select. Dacă testexpression se potriveşte cu un element dintr-o listă Case. VbNormalNoFocus 4 Fereastra este normală (restaurată la mărimea şi poziţia cea mai recentă) dar nu are focus-ul. cu focus. fără focus. a uneia sau mai multe expresii de forma: expression. argumentele necesare şi poate da calea completă (dacă este nevoie). Conţine numele programului care se execută. adică introduce instrucţiunile care se execută atunci când expresia de test nu se potriveşte nici unui element din listele clauzelor Else. atunci execuţia urmează cu prima instrucţiune de după End Select. Funcţia Shell() Execută un program executabil şi returnează un Variant(Double) reprezentând ID-ul de task al programului în caz de succes. elsestatements reprezintă una sau mai multe instrucţiuni care se vor executa dacă testexpression nu este egală cu nici un element din listele liniilor Case. VbMaximizedFocus 3 Fereastră maximizată.windowstyle]) unde pathname este Variant (String). în rest. cu focus). separată prin virgule. 67 . deoarece despre proceduri şi apelul lor s-a discutat în capitolul 1. Clauza Case Else are semnificaţia uzuală "altfel. Cuvântul To introduce un interval de valori. Se va utiliza Is cu operatori de comparare (exceptând Is şi Like) pentru a specifica un domeniu de valori. doar prima potrivire este considerată. VbMinimizedNoFocu 6 Fereastră minimizată. structurile interioare fiind complete (fiecare structură are End Select propriu. expression To expression. Fereastra activă curentă îşi păstrează focus-ul. se vor executa instrucţiunile care urmează această clauză Case până la următoarea clauză Case. Rezultă că dacă testexpression se regăseşte în mai multe liste. includerea este completă). expressionlist-n este lista. în caz contrar returnează zero.

deci nu există certitudinea că acest program se termină înainte de execuţia instrucţiunilor care urmează liniei Shell. 68 .Dacă funcţia Shell nu poate porni programul specificat se va semnala eroare. Programul pornit prin Shell se execută asincron.

care să înglobeze experienţa proprie. Divide et impera [Gries85]). 4. ci una foarte importantă şi adeseori chiar dificilă. Rafinarea în paşi succesivi. Este vorba de prezenţa unei variabile într-o expresie fără ca în prealabil această variabilă să fi primit valoare. Dar nu se poate rezolva o problemă dacă nu se cunoaşte această problemă. Evident. neverificând dacă o variabilă a fost iniţializată înaintea folosirii ei. să fie testat şi validat ţinând seama de această specificaţie. Programul realizat trebuie să fie portabil. Alte compilatoare iniţializează automat variabilele numerice cu valoarea zero. 3. care ar fi cea mai potrivită scopului urmărit? În paralel cu proiectarea algoritmului demonstrează corectitudinea lui. Aceste metode încurajează reutilizarea. Este o eroare foarte frecventă a programatorilor începători (dar nu numai a lor). folosirea unor componente existente (deci testate) măreşte gradul de fiabilitate a produselor soft realizate şi scurtează perioada de realizare a acestora. programează pe urmă. trebuie pusă în prim plan gândirea. 1. programarea structurată şi celelalte metode prezentate în acest curs. să fie construit având tot timpul în faţă această specificaţie. Verifică valoarea variabilei imediat după obţinerea acesteia. Orice încălcare a ei indică o eroare care trebuie înlăturată. majoritatea dintre ele prezente şi explicate în secţiunile anterioare. Este vorba de programarea Top-Down. Defineşte complet problema. Specificarea corectă şi completă a problemei nu este o sarcină trivială. reducând costul realizării programelor. Această indicaţie.c2 verifică respectarea acestei proprietăţi. Bottom-up şi mixtă. Începând cu scrierea specificaţiilor problemei. Programul trebuie să respecte această specificaţie. 2. De asemenea. verificarea trebuie făcută după calcul. să i se demonstreze corectitudinea în raport cu această specificaţie. Cu toate acestea nu e bine să ne bazăm pe o asemenea iniţializare ci să atribuim singuri valorile iniţiale corespunzătoare variabilelor. Destule compilatoare permit folosirea variabilelor neiniţializate. viteza de lucru va creşte prin folosirea lor. programarea modulară. sau alte metode ce vor fi asimilate ulterior.CAPITOLUL VIII REGULI IMPORTANTE PRIVIND ALEGEREA UNUI LIMBAJ DE PROGRAMARE Prezentăm în continuare mai multe reguli importante. Nu folosi variabile neiniţializate. să nu se bazeze pe specificul unui anumit compilator. Foloseşte deci bibliotecile de componente reutilizabile existente şi construieşte singur astfel de biblioteci. pare fără sens pentru unii cititori. Este specificaţia problemei corectă? Între metodele de rezolvare posibile. În primul caz. în al doilea caz se recomandă ca verificarea să urmeze imediat după citirea valorii respectivei variabile. Cunoaşte şi foloseşte metodele de programare. Gândeşte mai întâi. dacă o parte din SUBPROGRAMii necesari programului sunt deja scrişi şi verificaţi. Dacă o variabilă întreagă trebuie să ia valori într-un subdomeniu c 1. Verifică corectitudinea fiecărui pas înainte de a merge mai departe. 69 . Valoarea variabilei poate fi calculată sau introdusă de utilizator. foarte importantă în activitatea de programare.. 5.

). în primul rând se acordă atenţie aspectelor esenţiale. Dacă pentru proiectare se pot folosi oricare dintre metodele indicate. Urmează testarea fiecărui subprogram imediat după ce a fost scris (codificat). mult mai grav. Este adevărat că activitatea de testare necesită un anumit timp. Prin utilizarea acestor constante se măreşte gradul de generalitate a textului scris. evitându-se activităţi inutile de depanare. Evită artificiile. Acest lucru se potriveşte codificării bottomup şi sugerează o abordare sistematică a activităţii de codificare. uneori se ajunge chiar la introducerea unor erori. deoarece la fiecare nivel de detaliere se vor folosi numai componente testate deja. abordarea de jos în sus este esenţială. ci se câştigă timp. Amână pe mai târziu detaliile nesemnificative. Folosirea intensivă a constantelor simbolice este recomandată oriunde în textul sursă trebuie scris un număr (la declararea tablourilor. 70 .O bună programare modulară elimină legăturile între două module prin variabile globale. – facilitează detectarea erorilor. la precizarea limitelor de variaţie a unor variabile. Beneficiarii ţin foarte mult la forma rezultatelor şi. adeseori. Comunicarea între două module trebuie să se realizeze numai prin mecanismul parametrilor formaliactuali. Ea implică numai definiţia constantei. dar ea este utilă cel puţin din trei puncte de vedere: – scoate în evidenţă erorile provocate de proiectarea algoritmului sau codificarea neadecvată a acestuia. nu modificarea valorii concrete în toate instrucţiunile programului. Se recomandă ca fiecare modul să realizeze o activitate bine definită şi independentă de alt modul. În fiecare fază dă atenţie lucrurilor importante. începând cu modulul principal. 9. modificarea este mult mai uşoară (doar la locul definiţiei constantei) şi nu duce la erori. Verifică corectitudinea algoritmului şi programului în fiecare etapă a elaborării lor. deoarece dimensiunea problemei este mai mică. Sugerăm ca această testare să se facă independent de programul în care se va folosi subprogramul testat. Există însă situaţii în care prin anumite artificii se câştigă eficienţă în execuţie sau se face economie de memorie. 6. imposibil de eliminat altfel decât prin rescrierea modulului sau programului respectiv. este inutil să se piardă timp cu scrierea unor părţi de program pentru tipărirea rezultatelor şi a constata ulterior că rezultatele nu sunt cele dorite. sau nu sunt corecte. în caz contrar nu se recomandă folosirea lor. Detectarea şi eliminarea unei erori imediat după comiterea ei duce la creşterea vitezei de realizare a produsului. judecă programatorii după această formă. Dacă acest fapt este important atunci artificiile sunt binevenite. Foloseşte constante simbolice. iar în situaţia în care valoarea unei constante trebuie schimbată. câteodată. întrucât erorile semnalate în timpul testării sunt adeseori greu de descoperit şi. Se recomandă demonstrarea corectitudinii fiecărui algoritm folosit. Prin folosirea artificiilor în programare. 7. în codificare (şi testarea aferentă codificării). 8. E păcat de munca depusă dacă tipărirea rezultatelor lasă o impresie proastă asupra beneficiarului. în fapt nu se pierde timp cu scrierea unui program de test. De exemplu. etc. Nu uita însă că pentru beneficiar "Detaliile nesemnificative sunt semnificative". Această regulă stabileşte priorităţile de realizare a componentelor unui program. a prescurtărilor şi simplificărilor se pierde adesea din claritatea programului şi. În plus se poate pierde portabilitatea programului. ceea ce rămâne de testat la nivelul respectiv este gestiunea corectă a apelurilor respectivelor componente.

11. În situaţia când corpul conţine şi testarea condiţiei de continuare a ciclării. 14. chiar dacă demonstrarea corectitudinii algoritmului este validă. O astfel de practică poate duce la erori greu de detectat şi încalcă regulile programării structurate. Fiecare variabilă trebuie să aibă o semnificaţie proprie. – 10. care trebuie verificat. E clar că denumirea alesă redă semnificaţia variabilei. care să scoată cât mai bine în evidenţă structura programului şi funcţiile fiecărei părţi a acestuia. Cunoaşte şi respectă semnificaţia fiecărei variabile. E bine ca denumirea să reflecte această semnificaţie. mărind astfel claritatea textului programului. lungimea programului creşte şi citirea lui devine greoaie. Nu recalcula limitele şi nu modifica variabila de ciclare în interiorul unei structuri repetitive dată prin propoziţia Pseudocod PENTRU. Foloseşte variabile auxiliare numai acolo unde este strict necesar. Instrucţiunea Pseudocod PENTRU corespunde unui număr cunoscut de execuţii ale corpului ciclului. recomandăm a se folosi structurile REPETĂ sau CÂTTIMP şi nu PENTRU. Atunci când este necesară schimbarea variabilei de ciclare sau a limitelor se recomandă folosirea uneia din structurile repetitive REPETĂ sau CÂTTIMP. 13. pot duce la reducerea clarităţii programului. Nu uita să testezi programul chiar dacă ai demonstrat corectitudinea lui. O greşeală frecventă făcută de unii programatori constă în folosirea unei variabile în mai multe scopuri. de introducere (tastare) sau pot fi alte cauze care generează erori. acesteia i se ataşează un invariant. Prin scriere redă cât mai fidel structura programului. de constante. Folosirea necontrolată a mai multor variabile auxiliare. obţinuţi prin concatenarea mai multor cuvinte.obligă implementatorul să gândească încă o utilizare (cel puţin) a respectivului subprogram. Fiecare programator trebuie să aibă propriile reguli de scriere. 15. de cele mai multe ori. folosind identificatori lungi. iar în demonstrarea corectitudinii programului. Foloseşte denumiri sugestive pentru identificatorii utilizaţi în program. În demonstrarea corectitudinii algoritmului această semnificaţie se reflectă. 71 . Nu ieşi forţat din corpul unei structuri repetitive redată prin propoziţia Pseudocod PENTRU. programul poate conţine greşeli de codificare. ruperea unor expresii chiar lungi în subexpresii cu diferite denumiri. de subprograme) îşi are rolul şi semnificaţia lui într-un program. printr-un predicat invariant. Dar. Fiecare identificator (nume de variabilă. Fiecare variabilă are o semnificaţie. Şi o demonstraţie a corectitudinii unui program poate fi greşită. Importanţa indentării şi spaţierii pentru claritatea programului au fost arătate anterior. independentă de cea pentru care a fost iniţial conceput. 12. Unii programatori exagerează însă. dar claritatea textului scade. 16. de tip de date. Sunt cunoscute demonstraţii greşite pentru unele teoreme celebre din matematică.

un program bun va trebui să posede şi o componentă de asistenţă on-line (funcţie help). 18. Aşa cum s-a arătat în mai multe locuri din acest material. proiectarea algoritmilor. datele de test folosite). Foloseşte comentariile. care contribuie la asigurarea a ceea ce am numit interfaţă prietenoasă. Orice program sau modul trebuie să fie însoţit de comentarii explicative dacă dorim să-l refolosim şi nu trebuie să scriem programe care să nu poată fi refolosite. E bine ca aceste decizii să rămână consemnate împreună cu rezultatul final al fiecărei faze din viaţa programului (specificarea problemei. Vor rezulta documentaţii de analiză. programul propriu-zis. chiar dacă este vorba de propriu. proiectare. program scris în urmă cu câteva luni sau ani de zile. trebuind a fi actualizate ori de câte ori se produc modificări.17. Primele trei sunt necesare la întreţinerea aplicaţiei. Elaborează documentaţia programului în paralel cu realizarea lui. Este foarte greu să descifrăm un program lipsit de comentarii. 72 .4. iar ultima este necesară celor care exploatează aplicaţia. pe durata de viaţă a unui program se iau mai multe decizii. Rolul comentariilor a fost explicat în secţiunea 4. Pe lângă acestea. implementare şi exploatare. Minimum de comentarii într-un modul trebuie să conţină specificarea acestui modul şi semnificaţia fiecărei variabile.

şi Si sunt mulţimi finite având s elemente si xi € si . care sunt numite condiţii interne. Pentru fiecare problemă se dau relaţii între componentele vectorului x. vom urmări ca numerele să fie distincte.. Dacă mulţimile S1. timpul necesar de execuţie al algoritmului este k la n. Problemele rezolvate prin această metodă necesită timp mare de execuţie. Metoda backtracking evită această generare şi este mai eficientă.. Pot apărea următoarele situaţii : a) x[k] îndeplineşte condiţiile de continuare. 2) se presupun generate elementele x1…x[k-1]. x[n] nu se va ajunge la o soluţie rezultat. – metoda Branch and Bound.n}. atunci se notează cu „m” minimul cardinalelor mulţimilor S1…Sn si cu „M”. Generarea permutărilor se va face ţinând cont că orice permutare va fi alcătuită din elemente distincte ale mulţimii A. Elementele vectorului x.n. cu valori din S1. la generarea unei permutări. …. primesc pe rând valori în ordinea crescătoare a indicilor. 73 . Ea insa nu poate fi înlocuită cu alte variante de rezolvare mai rapide în situaţia în care se cere determinarea tuturor soluţiilor unei probleme. Daca s-a ajuns la soluţia finală (k = n) atunci se afişează soluţia obţinută. soluţiile posibile care satisfac condiţiile interne se numesc soluţii rezultat. unde S este mulţimea soluţiilor problemei şi S = S1 x S2 x… x Sn. de aceea este indicat sa se folosească metoda numai daca nu avem alt algoritm de rezolvare. 3.S2. se revine la elementul x[k-1] şi se reia algoritmul pentru o nouă valoare a acestuia. Metoda backtracking se aplică problemelor în care soluţia poate fi reprezentată sub forma unui vector – x = (x1. b) x[k] nu îndeplineşte condiţiile de continuare. Algoritmul se încheie când au fost luate in considerare toate elementele lui S1. x2. …xk.… xn) € S. Generarea permutărilor.. acest lucru înseamnă ca orice valori i-am atribui lui x[k+1]. Metoda backtracking are complexitatea exponenţială. Din acest motiv.S[k-1]. la pasul k. x[k-1]. Metoda backtracking construieşte un vector soluţie în mod progresiv începând cu prima componentă a vectorului şi mergând spre ultima cu eventuale reveniri asupra atribuirilor anterioare. La atribuirea valorii lui x[k] se verifica îndeplinirea unor condiţii de continuare referitoare la x1…x[k-1]. – metoda Backtracking. Daca nu se găseşte nici o valoare în S[k] care să îndeplinească condiţiile de continuare.…Sn au acelaşi număr k de elemente. S2. in cele mai multe cazuri fiind ineficientă. – metoda Divide et impera. Dintre acestea cel mai des utilizate sunt: – metoda Greedy. Să se genereze toate permutările mulţimii {1. Se încearcă următoarea valoare disponibila din S[k].. maximul. Sn nu au acelaşi număr de elemente. Se citeşte un număr natural n. x[k] va primi o valoare numai daca au fost atribuite valori elementelor x1.CAPITOLUL IX METODA BACKTRACKING La dispoziţia celor care rezolvă probleme cu ajutorul calculatorului există mai multe metode. Daca nu s-a ajuns la soluţia finală se trece la generarea elementului următor – x [k-1]. Dacă mulţimile S1. (¥)i = 1. 2. x[k+1]. Metoda se aplica astfel : 1) se alege prima valoare sin S1 si I se atribuie lui x1 . pentru generarea lui x[k] se alege primul element din S[k] disponibil si pentru valoarea aleasa se testează îndeplinirea condiţiilor de continuare. . Metoda de generare a tuturor soluţiilor posibile si apoi de determinare a soluţiilor rezultat prin verificarea îndeplinirii condiţiilor interne necesită foarte mult timp. Timpul de execuţie este situat în intervalul [m la n . x3.. M la n].. Daca aceste condiţii nu sunt îndeplinite.

întrucât nivelul 3 este completat corect. k If am_suc = True Then valid1 ev. st End If Else k = k .1 End If Wend 74 . 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. deoarece această valoare nu mai este întâlnită.  valoarea 1 din nivelul al 3-lea se regăseşte pe nivelul 1.Prezentăm algoritmul corespunzător 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. Programul sursa este urmatorul: Private Sub CommandButton14_Click() cit_n "n = ".  valoarea 3 pe nivelul al 3-lea nu e întâlnită pe nivelurile anterioare. Tipărim: 1 2 3 …… Algoritmul continuă până când stiva devine vidă.  încărcarea valorii 1 pe nivelul al 2-lea nu este posibilă. n back_perm End Sub Sub back_perm() Dim k As Integer k = 1 While k > 0 Do succesor am_suc.  valoarea 2 din nivelul al 3-lea se regăseşte pe nivelul al 2-lea. st. întrucât această valoare se găseşte şi pe nivelul 1 al stivei. st.  încărcarea valorii 2 pe nivelul al 2-lea este posibilă.

aşa cum va rezulta din exemplele." Next MsgBox b End Sub Sub succesor(am_suc As Boolean.ss(i) = st. o eventuală valoare reziduală se pierde: Pe un anumit nivel se retine..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. k As Integer) ev = True For i = 1 To k . însă este posibil. prezentate în lucrare. de regulă. Exemplificăm. o singură informaţie (literă sau cifră). Fie ST(i) un vector. O variabilă K indică în permanentă vârful stivei.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ă operaţiile de introducere şi scoatere a datelor se fac în vârful ei. vârful stivei va fi la nivelul 1 (k-1). ST(1). scoatem din stivă pe B (A nu poate fi scos).End Sub Sub valid1(ev As Boolean. iar atunci când scriem ceva în stivă. . Stivele se pot simula utilizând vectori.1 If (st.. stiva rămâne vidă A În mod practic la scoaterea unei variabile din stivă.ss(k) < n Then am_suc = True st. ST(n) pot reţine numai litere sau numai cifre.ss(k) = st. ST(2). modul de lucru cu stiva: A B A În stiva iniţial vidă se introduce litera A. în continuare. 75 . scade cu 1 valoarea variabilei ce indică vârful stivei. Întreaga teorie a recursivităţii se bazează pe structura de tip stivă. k As Integer) If st. etc. introducem în stivă litera B. să avem mai multe informaţii. caz în care avem de a face cu stive duble. scoatem din stivă pe A.ss(i)) + ". st As stiva.. deci k va lua valoarea 2. st As stiva. triple.

caz în care se reia algoritmul considerând generate elementele x1.x2 …. pentru fiecare element al acestuia...x2 ….Ak. ce aparţine lui A. La întâlnirea unei astfel de probleme. se va găsi pe primul nivel al stivei. An pot coincide.xn – dacă se constată că.xA.A2 …. . – presupunând generate elementele x1.. Tehnica Backtracking are la bază un principiu extrem de simplu: – se construieşte soluţia pas cu pas: x1.. caz în care caz în care se reia căutarea considerând generate elementele x1. pentru ca apoi să constatăm că nu am obţinut o permutare.1. iar aceasta se reia de la următorul element al mulţimii Ak rămas netestat.. primul element disponibil din mulţimea Ak+1.xk . xn pot fi la rândul lor vectori.. 2) A fost găsit. A2 …. suntem tentaţi să generăm toate elementele produsului cartezian A1.. caz în care se testează dacă s-a ajuns la soluţie si apar din nou două posibilităţi: . mai rapidă – x1 x2 ….. nu are rost să generăm produsul cartezian AxAx. xk .xn. x2 ….  nu le îndeplineşte caz în care se reia algoritmul considerând generate elementele x1. Concret: – se alege primul element x.. Am arătat că orice soluţie se generează sub formă de vector. se tipăreşte soluţia si se reia algoritmul considerând generate elementele x1. atunci când a fost găsită. algoritmul neavând nici o valoare practică.xk . aparţinând mulţimilor A1. În cazul în care se cere o sigură soluţie se poate forţa oprirea. – nu se dispune de o altă metodă de rezolvare. să testăm.s-a ajuns la soluţie. cu x1 € A1. xn € An – mulţimile A1.xk+1 .x2 …. nu avem cum să ajungem la soluţie. stiva (notată ST) va arăta astfel: 76 .x2 ….. x1 € A1. pentru o valoare aleasă..x2.. Algoritmii se termină atunci când nu există nici un element x1 € A1 netestat.An si fiecare element să fie testat dacă este soluţie.nu s-a ajuns la soluţie. dacă este sau nu permutare (nu are rost să generăm 1. se renunţă la acea valoare şi se reia căutarea din punctul în care am rămas.1. xk € Ak se va găsi pe nivelul k al stivei. În acest fel. (se caută în continuare. când de la a doua cifră 1 ne puteam da seama că cifrele nu sunt distincte). Rezolvând problema în acest mod. timpul de execuţie este atât de mare. rămase netestate... Astfel. un alt element al mulţimii Ak.Prezentarea tehnicii Backtracking Această tehnică se foloseşte în rezolvarea problemelor care îndeplinesc simultan următoarele condiţii: – soluţia lor poate fi pusă sub forma unui vector S=x1.1. se alege (dacă există) xk+1. x2 € A2 se va găsi pe al doilea nivel al stivei. . De exemplu. A2 ….. apar două posibilităţi: 1) Nu s-a găsit un astfel de element. rămas netestat).. dacă nu cunoaştem această tehnică. Observaţie: tehnica Backtracking are ca rezultat obţinerea tuturor soluţiilor problemei. x2 € A2 ….x2 …. iar elementele lor se consideră că se află într-o relaţie de ordine bine stabilită.. …. pentru ca apoi. caz în care se testează dacă acesta îndeplineşte anumite condiţii de continuare apărând astfel două posibilităţi:  îndeplineşte. încât poate fi considerat infinit. Vom considera că generarea soluţiilor se face intr-o stivă. iar elementul xk-1 se caută între elementele mulţimii A. An sunt mulţimi finite. A2 .xk. – A1. dacă dorim să generăm toate permutările unei mulţimi finite A. si se caută un prim element xk+2 € Ak.

xk … … x2 x1 ST Nivelul k+1 al stivei trebuie iniţializat (pentru a alege. k) . st... CALL init(1.2. astfel încât să nu se afle două dame pe aceeaşi linie.n}. tehnica backtracking trebuie aplicată numai în ultimă instanţă. Cu toate că există probleme pentru care nu se pot elabora alţi algoritmi mai eficienţi. se cer toate soluţiile de aranjare a n dame.k) then loop until (not as) or (as and ev) .. În situaţia în care am găsit elementul. Iniţializarea trebuie făcută cu o valoare aflată (în relaţia de ordine considerată. Acest test se face cu ajutorul procedurii VALID (EV. xn.. contrar (nu a rămas un element netestat) AS ia valoarea FALSE.st). Prezentăm în continuare rutina Backtracking: k:=1. if as then if solutie(k) then CALL tipar else k:=k+l... trebuie văzut dacă acesta îndeplineşte condiţiile de continuare (altfel spus. De exemplu.. Testul dacă s-a ajuns sau nu la soluţia finală se face cu ajutorul funcţiei SOLUTIE(k) iar o soluţie se tipăreşte cu ajutorul procedurii TIPAR. Odată ales un element. elementele mulţimii k+1 ). Găsirea următorului element al mulţimii Ak (element care a fost netestat) se face cu ajutorul procedurii SUCCESOR (AS. if as then CALLvalid(ev. Parametrul AS (am succesor) este o variabilă booleană. st ).st. orice nivel al stivei va lua valori de la 1 la n. while k>0 do CALL succesor (as. în ordine.ST. pentru mulţimea Ak+1 ) înaintea tuturor valorilor posibile din mulţime. Procedura de iniţializare o vom numi INIT şi va avea doi parametri: k (nivelul care trebuie iniţializat si ST (stiva)). Fiind dată o tablă de şah. acesta este pus în stivă şi AS ia valoarea TRUE. Iniţializarea unui nivel (oarecare) se face cu valoarea 0. else k:=k-1 wend Observaţie: Problemele rezolvate prin această metodă necesită un timp îndelungat. Exemplu: Presupunând că dispunem de o tablă de dimensiune 4x4. este bine să utilizăm metoda numai atunci când nu avem la dispoziţie un alt algoritm mai eficient. o soluţie ar fi următoarea: 77 . end.. dacă elementul este valid).K).K). pentru generarea permutărilor mulţimii {1. CALL init ( k. Din acest motiv. de dimensiune n.ST. coloană sau diagonală (dame să nu se atace reciproc).

observăm că nu este posibil să o plasăm nici în coloana 3.D D D D Observăm că o damă trebuie să fie plasată singură pe linie. D 78 D . coloana 1. Dama a doua nu mai poate avansa. Avansăm cu prima damă în coloana 2. D D Observăm că a treia damă nu poate fi plasată în linia 3. D A doua damă nu poate fi aşezată decât în coloana 3. D A doua damă nu poate fi aşezată decât în coloana 4. D D A treia damă nu poate fi plasată decât în coloana 2. nici în coloana 4. Încercăm atunci plasarea celei de-a doua dame în coloana 4. D D D În această situaţie dama a patra nu mai poate fi aşezată. deci o vom scoate de pe tablă. Încercând să avansăm cu dama a treia. Plasăm prima damă pe linia 1. deci şi ea este scoasă de pe tablă.

3 1 4 2 Exemplu: în tabla 4 x4 avem situaţia: D D D D sau situaţia 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) . în modul. În general ST(i)=k semnifică faptul că pe linia i dama ocupă poziţia k. D D D Acum este posibil să plasăm a patra damă în coloana 3 si astfel am obţinut o soluţie a problemei.Dama a treia se aşează în prima coloană. Două dame se găsesc pe aceeaşi diagonală dacă si numai dacă este îndeplinită condiţia: |st(i)-st(j)| =|i-j| ( diferenţa. Exemplu pentru soluţia găsită avem vectorul ST ce poate fi asimilat unei stive. D D D D Algoritmul continuă în acest mod până când trebuie scoasă de pe tablă prima damă.st(3)| = |1 – 3| = 2 |i – j| = |1 – 3| = 2 . între linii si coloane este aceeaşi). Pentru reprezentarea unei soluţii putem folosi un vector cu n componente (având în vedere că pe fiecare linie se găseşte o singură damă).

în caz contrar. – Am coborât în stivă mutând dama de pe linia 2 şi coloana 3 în coloana 4.tipăreşte o soluţie.ss(k) + 1 Else am_suc = False End If 80 . înseamnă că lucrăm conform strategiei backtracking. k As Integer) If st. însă acest lucru nu este posibil. st As stiva. ev As Boolean Type stiva ss(100) As Integer End Type Global st As stiva Sub init(k As Integer. verificând dacă nu avem două dame pe aceeaşi linie (st(k)=st(i)). Iată algoritmul. am_suc As Boolean. – Nu se poate plasa dama 3 în coloana 1. – Damele de pe 2-3 se găsesc pe aceeaşi coloană. conform strategiei generate de backtracking: – În prima poziţie a stivei se încarcă valoarea 1. st As stiva) st. rezultă că o soluţie este sub formă de permutare. variabilei EV i se atribuie TRUE.validează valoarea pusă pe nivelul k al stivei. Aceasta presupune ca imediat ce am găsit două dame care se atacă. acest lucru nefiind posibil întrucât avem doua dame pe aceeaşi coloană.ss(k) = st. TIPAR . O primă idee ne conduce la generarea tuturor permutărilor si la extragerea soluţiilor pentru problema ca două dame să nu fie plasate în aceeaşi diagonală. în caz contrar. SOLUTIE . A proceda astfel. atribuie variabilei EV valoarea FALSE. Subprogramele prezentate in limbajul Visual Basic sunt descrise mai jos: Global n As Integer.măreşte cu 1 valoarea aflată pe nivelul k al stivei în situaţia în care aceasta este mai mică decât n şi atribuie variabilei EV valoarea TRUE.verifică dacă stiva a fost completată până la nivelul n inclusiv. – Linia 2 se încearcă aşezarea damei în coloana 1. Semnificaţia procedurilor utilizate este următoarea: INIT . VALID .ss(k) = 0 End Sub Sub succesor(am_suc As Boolean.ss(k) < n Then am_suc = True st.|i – j| = |1 – 3| = 2 Întrucât doua dame nu se pot găsi în aceeaşi coloană. Algoritmul se încheie atunci când stiva este vidă. – În linia 2 se încearcă aşezarea damei în coloana 2 . să reluăm căutarea. întrucât în liniile 1-3 damele ocupa acelaşi coloană.nivelul k al stivei este iniţializat cu 0. pentru că damele se găsesc pe aceiaşi diagonală (|st(1)-st(2)|=|1-2|). SUCCESOR . – Şi această încercare eşuează întrucât damele de pe 2 şi 3 sunt pe aceeaşi diagonală. – Damele de pe 2-3 se găsesc pe aceeaşi diagonală. – Aşezarea damei 2 în coloana 3 este posibilă. cu semnificaţia că în linia unu se aşează prima damă în coloană. sau dacă nu avem două dame pe aceeaşi diagonală (st(k)-st(i)=|k-i|)caz în care variabilei EV i se atribuie FALSE.

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. st.End Sub Sub valid(ev As Boolean." Next MsgBox b End Sub Sub back() Dim k As Integer k = 1 While k > 0 Do succesor am_suc. ib_title) back End Sub 81 . st As stiva.1 End If Wend End Sub Sub Button2_Click() n = InputBox("n=". b As String b = " " For i = 1 To n b = b + "(" + Str$(i) + ".ss(i) = st.ss(k)) Or (Abs(st. k If am_suc = True Then valid ev. st End If Else k = k .ss(i) .ss(i)) + ")." + Str$(st.st. st.1 If (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. k As Integer) ev = True For i = 1 To k .

3). Se dau mulţimile de mai jos şi se cere produsul cartezian al lor. k1} A2 = {1. 3. 2). 1). a back_prod_cart End Sub Sub cit_n(mes As String. 1). (2. (1. Vom admite că şi aceasta este backtracking. (1. 1. 3. n. kn} Exemplu: A1 = {1. 2). 3. dar „degenerat”. 2. 2. 3} A1 × A2 × A3 = {(1. n cit_date "a". (1. a tipar " multimile sunt : ". a As vector) For i = 1 To n a. motiv pentru care procedura valid nu face altceva decât să atribuie variabilei ev valoarea TRUE. 2. A1 = {1. 1). (2. …. …. 3)}. 3. 2). b) Limita superioară pe nivelul k al stivei este dată de A(k). (1. k2. 2. 1. 2. 1). 2. se folosesc stiva ST şi un vector A ce reţine numerele k1. 2). y) 82 . Private Sub CommandButton16_Click() Dim a As vector cit_n "n=". 3. n. 3. 3. 3). 1). (2. nnn As Integer) Do nnn = InputBox(mes.v(i) = InputBox(mes + "(" + Str$(i) + ")=". 1). n As Integer. (2. 1. 2). 1. 2. 1. (2. (2. 2. Utilizăm metoda backtracking. 3). 2. k2} ……………………… An = {1. uşor modificată din următoarele motive: a) Orice element aflat la nivelul k al stivei este valid. 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 Observaţii: Algoritmul prezentat aici este de tip backtracking? Întrebarea are sens pentru că este absent mecanismul de întoarcere. 3). …kn. (2. y) Loop Until n > 0 And n < 100 End Sub Sub cit_date(mes As String. 3. (1. 2} A2 = {1. …. 2). 2. (1.Produsul cartezian a n mulţimi. 3). Pentru rezolvare. (1. (2. (2. 1. 3} A3 = {1. (1. 2. 3.

k If am_suc = True Then valid_prod ev. 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 As stiva.Next End Sub Sub tipar(mes sir = "" For i = 1 To sir = sir + Next MsgBox mes + End Sub As String.v(i)) + ". st.ss(k) = 0 End Sub 83 .1 End If Wend End Sub Sub valid_prod(ev As Boolean. a As vector) n Str$(a." " " + sir Sub back_prod_cart() Dim k As Integer k = 1 init k. 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. st. n As Integer. st While k > 0 Do succesor_prod am_suc.ss(k) < a. st End If Else k = k .ss(k) + 1 Else am_suc = False End If End Sub Sub init(k As Integer. k As Integer) If st.ss(k) = st. st As stiva) st.v(k) Then am_suc = True st.

Private Sub CommandButton17_Click() cit_n "n = ". – elementele plasate pe diverse niveluri trebuie să fie distincte.1 End If Wend End Sub Sub valid1(ev As Boolean.Generarea aranjamentelor. cu deosebirea că aici stipa are înălţimea p.ss(i) = st. p back_aranj End Sub Sub back_aranj() Dim k As Integer k = 1 init k. st While k > 0 Do succesor am_suc. Se citesc n şi p. b As String b = " " For i = 1 To p b = b + Str$(st. st End If Else k = k .ss(k)) Then ev = False End If Next End Sub Sub tipar_rr() Dim i As Integer. st As stiva. – fiecare nivel ia valori între 1 şi n. 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. k If am_suc = True Then valid1 ev. st. k As Integer) ev = True For i = 1 To k . st.1 If (st. Să se genereze toate aranjamentele de n luate câte p.ss(i)) + ". Algoritmul este asemănător cu cel de la permutări." Next MsgBox b End Sub 84 . n cit_n "p = ". Din analiza problemei rezultă următoarele: – stiva are înălţimea p.

2.ss(k) = 0 End Sub Generarea combinărilor. …. 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 As stiva) st.ss(k) < n Then am_suc = True st. st. n≥ p. 3. – pentru a evita repetiţia elementele se aşează în ordine crescătoare: pe nivelul k se va afla o valoare mai mare decât pe nivelul k-1 şi mai mică sau egală cu n-p+k. Se cere să se genereze toate submulţimile cu p elemente ale mulţimii {1. Se citesc n şi p numere naturale. st End If Else k = k . st As stiva. k As Integer) If st.1 End If Wend 85 . n cit_n "p = ". Private Sub CommandButton18_Click() cit_n "n = ". st While k > 0 Do succesor_c am_suc. k If am_suc = True Then valid_c ev. n}. Pentru rezolvarea problemei trebuie ţinut cont de următoarele: – stiva are înălţimea p. – elementele aflate pe niveluri diferite ale stivei trebuie să fie distincte.ss(k) + 1 Else am_suc = False End If End Sub Sub init(k As Integer.ss(k) = st. st. p back_comb End Sub Sub back_comb() Dim k As Integer k = 1 init k.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.

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. st As stiva.ss(i)) + " " Next MsgBox b End Sub Problema comis-voiajorului. iar la întoarcere să revină în oraşul 1.ss(k)) Then ev = False End If Next If k > 1 Then If st.ss(k . notat 1. el se află într-unul dintre ele.End Sub Sub succesor_c(am_suc As Boolean.ss(k) < st.p + k Then am_suc = True st.ss(i) = st. st As stiva. precum şi drumurile existente între ele. se cere să se tipărească toate drumurile posibile pe care le poate efectua comis – voiajorul.1 If (st. 86 . Cunoscând legăturile existente între oraşe. k As Integer) If st. Iniţial. Exemplu: În figura alăturată sunt simbolizate cele 6 oraşe.ss(k) = st.ss(k) < n . k As Integer) Dim i As Integer ev = True For i = 1 To k . Un comis voiajor trebuie să viziteze un număr n de oraşe.ss(k) + 1 Else am_suc = False End If End Sub Sub valid_c(ev As Boolean. Comis – voiajorul doreşte să nu treacă de două ori prin acelaşi oraş. b As String b = " " For i = 1 To n b = b + "Tara = " + Str$(i) + ". culoarea " + Str$(st.

1.j ∈{1. – dacă succesorul se găseşte la nivelul n. Din acest motiv este bine să utilizăm metoda atunci numai atunci când nu mai avem la dispoziţie un alt algoritm mai eficient 87 . deci oraşul 3 este acceptat. De la oraşul 2 la oraşul 3 se găseşte drum. 2. între 2 şi n. 3. Observaţii: 1. 4. este considerat valid dacă sunt îndeplinite următoarele condiţii: – nu s-a mai trecut prin oraşul simbolizat de succesor. – există drum între oraşul aflat la nivelul k-1 şi cel aflat la nivelul k. caz în care algoritmul se încheie. Algoritmul continuă în acest mod până se ajunge din nou la nivelul 1. 6. 3. deci se va urca în stivă. ….j) = A(j. 5. 2. 5. altfel Se observă că A(i. prin oraşul 3 nu s-a mai trecut. 2. Un succesor. aflat pe nivelul k al stivei. deci acesta nu se regăseşte în stivă.i). Legăturile existente între oraşe sunt date în matricea An. 6. Pentru rezolvarea problemei folosim stiva st. 1. 4. Prezentăm în continuare modul de rezolvare a problemei. 1. 3. 3. 3. 1. n} – matricea este simetrică.j) = 0 . Problemele rezolvate prin această metodă necesită un timp îndelungat de execuţie. 1. 1. 5. 1. 6. deci nu este acceptat. oricare ar fi i. 6. 5. Elementele matricei A pot fi 0 sau 1 (matricea este binară). 2. să existe drum de la el la oraşul 1. 2 1 2 2 1 3 2 1 De la oraşul 1 la oraşul 2 există drum.n. 2. dacă există drum între oraşele i şi j.voiajorul are următoarele posibilităţi de parcurgere: 1.2 3 1 4 6 5 Comis . la baza stivei (nivelul 1) se încarcă numărul 1. Oraşul 2 se mai găseşte în stivă. 4. 4. 1. A(i.

st. Rezolvarea iterativă încalcă principiul stivei atunci când verificăm condiţiile de continuare. st As stiva. De exemplu. vizitat " + Str$(st.m(i.ss(k)) And (mat. Consider că o structură trebuie folosită ca atare atunci când este strict necesar.1 If (st. k As Integer) ev = True For i = 1 To k . chiar şi segmentul de stivă al calculatorului poate fi accesat oriunde.ss(k) < n Then am_suc = True st. k) = 1) Then ev = False End If Next End Sub Sub tipar_comis() Dim i As Integer. Sub back_comis() Dim k As Integer k = 1 init k. pentru că accesăm orice nivel al stivei. k If am_suc = True Then valid_col ev. 3.ss(i) = st.2. k As Integer) If st. b As String b = " " For i = 1 To n b = b + "Tara = " + Str$(i) + ". st. deci backtracking este indicată.ss(k) = st.ss(i)) + " " Next MsgBox b 88 . 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.ss(k) + 1 Else am_suc = False End If End Sub Sub valid_comis(ev As Boolean. Asta nu înseamnă că acolo nu se utilizează din plin „mecanismul” stivei. st While k > 0 Do succesor_col am_suc. sau atunci când tipărim soluţia găsită. Menţionăm că nu există probleme pentru care nu se cunosc algoritmi eficienţi de rezolvare. st As stiva. st End If Else k = k .1 End If Wend End Sub Sub succesor_comis(am_suc As Boolean.

astfel încât două ţări de frontieră comună să fie colorate diferit. se cer toate soluţiile de colorare a hărţii. altfel Matricea A este simetrică.j) = 0 . Pentru rezolvarea problemei se utilizează stiva st. Sub back_col() Dim k As Integer k = 1 init k. vom considera următoarea hartă unde ţările sunt numerotate cu cifre cuprinse între 1 şi 5: 1 4 3 5 2 Figura 9. Rezolvare: Pentru exemplificare. utilizând cel mult patru culori.1 Harta ţărilor O soluţie a acestei probleme este următoarea: ţ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.End Sub PROBLEMA COLORĂRII HĂRŢILOR Enunţ: Fiind dată o hartă cu n ţări. k If am_suc = True Then valid_col ev. A(i.n 1. 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 . st. Este demonstrat faptul că sunt suficiente numai patru culori pentru ca orice hartă să poată fi colorată. st. unde nivelul k al stivei simbolizează ţara k. dacă ţara i se învecinează cu ţara j. Stiva are înălţimea n şi pe fiecare nivel ia valori între 1 şi 4. st While k > 0 Do succesor_col am_suc. iar st[k] culoarea ataşată ţării k.

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

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

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

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

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

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

fara sa-i pese de viitor si fara sa se razgandeasca. procedura alege cel mai bun candidat la momentul respectiv. daca avem trei clienti cu t1 = 5. sunt posibile sase ordini de servire. Timpul de servire necesar fiecarui client este cunoscut in prealabil: pentru clientul i este necesar un timp ti. se pot gasi contraexemple pentru care algoritmul nu gaseste solutia optima. daca un candidat este exclus din solutie. clientul 3 asteapta pana sunt serviti clientii 1. 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. Acest mod de lucru necesita insa foarte mult timp. Un algoritm greedy nu duce deci intotdeauna la solutia optima. el nu va mai fi niciodata reconsiderat. clientul 2 asteapta pana este servit clientul 1 si apoi este servit. sau la o solutie. elementele problemei sunt:  candidatii: multimea initiala de monezi de 1. ca si in afaceri. De exemplu. 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. Daca un candidat este inclus in solutie. 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 . Functia select este de obicei derivata din functia obiectiv. 2 si apoi este servit. 1 ≤ i ≤ n. In primul caz. Timpul total de asteptare a celor trei clienti este 38. 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. Sa presupunem ca dorim sa dam restul unui client. uneori aceste doua functii sunt chiar identice. el ramane acolo. In acest caz. presupunand ca exista si monezi de 12 unitati sau ca unele din tipurile de monezi lipsesc din multimea initiala de candidati. 5. pompa de benzina etc) trebuie sa satisfaca cererile a n clienti. Evident. un algoritm greedy actioneaza simplist. o astfel de metoda poate da rezultate foarte bune tocmai datorita simplitatii ei.Este de inteles acum de ce un astfel de algoritm se numeste “lacom” (am putea sa-i spunem si “nechibzuit”).3 Minimizarea timpului mediu de asteptare O singura statie de servire (procesor. clientul 1 este servit primul. si 25 unitati. La fiecare pas. Totusi. solutia optima se poate gasi incercand toate combinarile posibile de monezi. urmand ca pentru fiecare caz in parte sa determinam daca obtinem sau nu solutia optima. sau nu gaseste nici o solutie cu toate ca exista solutie. 11. Este doar un principiu general. folosind un numar cat mai mic de monezi. Un exemplu simplu de algoritm greedy este algoritmul folosit pentru rezolvarea urmatoarei probleme. Asemenea unui intreprinzator rudimentar care urmareste castigul imediat in dauna celui de perspectiva. t2 = 10. t3 = 3.

q3 = 10. Figura 11. S3 de lungimi q1 = 30.1 Reprezentarea strategiilor de interclasare. Numerotam varfurile in 97 . q3 = 20.. Generalizand.. Problema consta in determinarea ordinii optime in care trebuie efectuate aceste interclasari. Daca servirea are loc in ordinea I. astfel incat numarul total al deplasarilor sa fie cat mai mic. Ne propunem sa obtinem sirul S ordonat crescator. Problema poate fi generalizata pentru un sistem cu mai multe statii de servire.. n}. Sn. . Daca interclasarea are loc prin deplasarea elementelor din cele doua siruri in noul sir rezultat. Obtinem o noua ordine de servire J. q2 = 10. Atasam fiecarei strategii de interclasare cate un arbore binar in care valoarea fiecarui varf este data de lungimea sirului pe care il reprezinta. Daca il interclasam pe S3 cu S2. cu alte cuvinte.. corespunzand celor 5 interclasari care definesc strategia respectiva. 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.1. Daca interclasam pe S1 cu S2. Vom demonstra ca acest algoritm este optim. 2. care este de preferat deoarece Prin metoda greedy obtinem deci intotdeauna planificarea optima a clientilor. continand exact elementele din cele n siruri. fiecare sir Si. numarul total al deplasarilor este (10+20)+(30+30)=90. q2 = 20. avem Presupunem acum ca I este astfel incat putem gasi doi intregi a < b cu Interschimbam pe ia cu ib in I.. q6 = 10. iar rezultatul il interclasam cu S1. . clientul care a fost servit al b-lea va fi servit acum al a-lea si invers. Fie I = (i1 i2 . S2. Daca sirurile S1. S6 au lungimile q1 = 30. S2.. S2. 1 ≤ i ≤ n. fiind format din qi elemente ordonate crescator (vom numi qi lungimea lui Si).Algoritmul greedy este foarte simplu: la fiecare pas se selecteaza clientul cu timpul minim de servire din multimea de clienti ramasa. atunci numarul deplasarilor este #S1 + #S2. q5 = 50. in) o permutare oarecare a intregilor {1. Fie sirurile S1. q4 = 30. corespunzand celor 6 siruri initiale si 5 varfuri neterminale... Vom realiza acest lucru prin interclasari succesive de cate doua siruri.. adica nu este indiferent in ce ordine se fac interclasarile. Exemplul de mai jos ne arata ca problema astfel formulata nu este banala. .. iar rezultatul il interclasam cu S3. sa consideram acum n siruri S1. numarul total al deplasarilor este (30+20)+(50+10)=110. Observam ca fiecare arbore are 6 varfuri terminale. doua astfel de strategii de interclasare sunt reprezentate prin arborii din Figura 11..

Presupunem ca proprietatea este adevarata pentru n–1 siruri. . Definim.. Fie B' arborele obtinut din B schimband intre ele varfurile q1 si qj..1b si consta in a interclasa mereu cele mai scurte doua siruri disponibile la momentul respectiv. Cei doi fii ai acestui varf sunt atunci doua varfuri terminale qj si qk.. Cum A se obtine din A' atasand la varful q1+q2 fiii q1 si q2.1 Prin metoda greedy se obtine intotdeauna interclasarea optima a n siruri ordonate. de lungimi q1. qn. In arborele B. Deoarece B are lungimea externa ponderata minima. qn.felul urmator: varful terminal i. rezulta ca L(B') = L(B). Atunci. iar B' se obtine in acelasi mod din B". Pentru n = 1. pentru un arbore oarecare A de acest tip. S2. .2 Numerotarea varfurilor arborilor din Figura 11. avem L(B") = L(A'). Rezulta ca si B" are lungimea externa ponderata minima. numerotate de la 1 la n. Sn. Arborele B' are lungimea externa ponderata minima si L(B') = L(B") + q1+q2... iar varfurile neterminale se numeroteaza de la 7 la 11 in ordinea obtinerii interclasarilor respective (Figura 11. Interclasand sirurile S1. q3. Eliminand din B' varfurile q1 si q2. fie un varf neterminal de adancime maxima. Se observa ca numarul total de deplasari de elemente pentru strategia corespunzatoare lui A este chiar L(A). qn. . In arborele A apare subarborele reprezentand prima interclasare facuta conform strategiei greedy. numerotate de la n+1 la 2n–1. 1 ≤ i ≤ 6. 98 ... Proprietatea 11.. Demonstratie: Demonstram prin inductie. Evident.. Fie A arborele strategiei greedy de interclasare a n siruri de lungime q1 ≤ q2 ≤ . conform ipotezei inductiei.. si n–1 varfuri neterminale. obtinem pentru fiecare strategie cate un arbore binar cu n varfuri terminale. Fie B un arbore cu lungimea externa ponderata minima..1 Strategia greedy apare in Figura 11. q3. q2.2). . Solutia optima a problemei noastre este atunci arborele (strategia) pentru care lungimea externa ponderata este minima. L(B') ≤ L(B).. unde A' este arborele strategiei greedy de interclasare a sirurilor de lungime q1+q2. respectiv q2 si qk. qn. lungimea externa ponderata: unde ai este adancimea varfului i. rezulta ca L(A) = L(B') = L(B). corespunzator unei strategii optime de interclasare a celor n siruri... Proprietatea este deci adevarata pentru orice n. va corespunde sirului Si. proprietatea este verificata. Figura 11. deci strategia cu arborele de lungime externa ponderata minima. obtinem un arbore B" cu n–1 varfuri terminale q1+q2.

Algoritmul interopt va construi arborele strategiei greedy. Fie un text compus din urmatoarele litere (in paranteze figureaza frecventele lor de aparitie): S (10). si cele mai lungi coduri. i) => H {insereaza in min-heap} LU[i] ← Q[i]. 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 . iar q este lungimea sirului pe care il reprezinta. T} (45 = 9) Multimea {P. P (4). Etichetam muchia stanga cu 1 si muchia dreapta cu 0. obtinand arborele 99 . la baza codului Morse. Fiecare element al min-heap-ului este o pereche (q. Aceasta metoda. DR[i] ← k. j) <= H {extrage radacina lui H} (r. O (9).La scrierea algoritmului care genereaza arborele strategiei greedy de interclasare vom folosi un min-heap. i) => H {insereaza in min-heap} In cazul cel mai nefavorabil. descoperita de Huffman (1952) foloseste o strategie greedy si se numeste codificarea Huffman. k) <= H {extrage radacina lui H} ST[i] ← j. Valoarea fiecarui varf este data de frecventa pe care o reprezinta. 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. 1 ≤ i ≤ n} H ← min-heap vid for i ← 1 to n do (Q[i]. {P. T (5) Conform metodei greedy. T} semnifica evenimentul reuniune a celor doua evenimente independente corespunzatoare aparitiei literelor P si T. ST[i] ← 0. Acest principiu sta. Continuam procesul. Timpul total pentru interopt este deci in O(n log n). Pentru situatia in care codificarea este binara. celor mai putin frecvente caractere. Restul operatiilor necesita un timp constant. celor mai frecvente caractere. LU[i] ← s+r (LU[i]. exista o metoda eleganta pentru a obtine codul respectiv. Rearanjam tabelul de frecvente: S (10). O vom descrie pe baza unui exemplu. de exemplu. Proprietatea de minheap se refera la valoarea lui q. construim un arbore binar fuzionand cele doua litere cu frecventele cele mai mici. operatiile de inserare in min-heap si de extragere din min-heap necesita un timp in ordinul lui log n. i) unde i este numarul unui varf din arborele strategiei de interclasare. O (9). I (29). 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. DR[i] ← 0 for i ← n+1 to 2n–1 do (s. I (29).. n]) {construieste arborele strategiei greedy de interclasare a sirurilor de lungimi Q[i] = qi.

alegerea varfurilor care sunt fuzionate la fiecare pas putandu-se face dupa diverse criterii. Aceasta problema se mai numeste si problema conectarii oraselor cu cost minim. .In final. Lungimea externa ponderata a unui arbore de codificare este: Figura 11. avand numeroase aplicatii... Cautam deci o submultime A de cost total minim. O (100). Pentru a obtine codificarea binara a literei P.3 Arborele de codificare Huffman. fn. unde ai este adincimea varfului terminal corespunzator literei i. M> un graf neorientat conex.. Fiecare muchie are un cost nenegativ (sau o lungime nenegativa).. . Codificarea cea mai compacta a unui text corespunde deci arborelui de codificare de lungime externa ponderata minima. unde V este multimea varfurilor si M este multimea muchiilor. f2. T (1010) Pentru un text format din n litere care apar cu frecventele f1.3. ajungem la arborele din Figura 11.4 Arbori parţiali de cost minim Fie G = <V. Se poate demonstra ca arborele de codificare Huffman minimizeaza lungimea externa ponderata pentru toti arborii de codificare cu varfurile terminale avand valorile f1. 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. f2... prin care se obtine o codificare binara a textului. un arbore de codificare este un arbore binar cu varfurile terminale avand valorile f1.. P (1011). in care fiecare varf terminal corespunde unei litere din text. astfel incat toate varfurile din V sa ramina conectate atunci cand sunt folosite doar muchii din A. f2. nu am pierdut nimic din generalitate. 100 . concentrandu-ne atentia asupra acestei categorii de coduri. 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. Codul Morse nu face parte din aceasta categorie. . Prin strategia greedy se obtine deci intotdeauna codificarea binara cea mai compacta a unui text. Procedam similar si pentru restul literelor: S (11). Codificarea cea mai compacta a unui sir de caractere poate fi intotdeauna obtinuta printr-un cod de tip prefix. O astfel de codificare este de tip prefix. 11. fn. Un arbore de codificare nu trebuie in mod necesar sa fie construit dupa metoda greedy a lui Huffman. I (0). Se observa ca lungimea externa ponderata este egala cu numarul total de caractere din codificarea textului considerat. iar suma lungimilor muchiilor din A sa fie cat mai mica. Deci.. fn. Problema este sa gasim o submultime A ⊆ M..

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

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

4.  O(m) pentru restul operatiilor. rezulta O(m log m) ⊆ O(m log n). la fiecare pas. presupunand ca se folosesc procedurile find3 si merge3. algoritmul lui Kruskal necesita un timp in O(m log n). 7} U {1} {1. este ilustrata in Tabelul 11. In acest algoritm. 4} {1. 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. 3. La sfarsit. pentru exemplul din Figura 11. pentru cazul cel mai nefavorabil. M>) {initializare} A ←ø {va contine muchiile arborelui partial de cost minim} U ← {un varf oarecare din V} {bucla greedy} while U ≠ V do 103 . Mai mult. A va contine aceleasi muchii ca si in cazul algoritmului lui Kruskal. pe care o puteti demonstra folosind Proprietatea 11. 5} {1. 6} {1. 4. se obtine arborele partial de cost minim al grafului G. Algoritmul lui Prim Cel de-al doilea algoritm greedy pentru determinarea arborelui partial de cost minim al unui graf se datoreaza lui Prim (1957).4a.2 Algoritmul lui Prim aplicat grafului din Figura 11. numarul de operatii pentru cazul cel mai nefavorabil este in:  O(m log m) pentru a sorta muchiile. in care initializarea se face intr-un timp in O(m). 2} {4. A> al lui G. A> al lui G. care va fi radacina.Pentru un graf cu n varfuri si m muchii. 4. 5. 2. 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. graful fiind conex. 2. 7} Tabelul 11. dand nastere unui nou arbore partial de cost minim (deci. Functionarea algoritmului. Pentru cazul cel mai nefavorabil. pina cand va atinge toate varfurile din V. In astfel de situatii. 2. 2. 6. Deoarece m ≤ n(n–1)/2. Faptul ca algoritmul functioneaza intotdeauna corect este exprimat de urmatoarea proprietate. 4} {7. function Prim-formal(G = <V. O alta varianta este sa pastram muchiile intr-un min-heap. sortand in mod inutil si aceste muchii.4 In algoritmul lui Prim. 3} {1.2. adica pina cand U = V. 2.2. din n-1 ≤ m rezulta si O(m log n) ⊆ O(m log m). In final. iar multimea A a muchiilor este vida. exact una dintre extremitatile acestei muchii este un varf in arborele precedent). 1} {3. 2} {1. Deoarece O(lg* n) ⊆ O(log n) si n-1 ≤ m. Deci.4a. Obtinem astfel un nou algoritm. deci O(m log m) = O(m log n).  Cele cel mult 2m operatii find3 si n–1 operatii merge3 necesita un timp in O((2m+n1) lg* n). Initial. Arborele partial de cost minim creste “natural”.  O(n) pentru a initializa cele n multimi disjuncte. <U. 3. algoritmul vechi pierde timp. 1} {5. 4} {6. A> formeaza un arbore partial de cost minim pentru subgraful <U. care se adauga la arborele precedent. Descrierea formala a algoritmului este data in continuare. Proprietatea 11. Pasul initializare 1 2 3 4 5 6 Muchia considerata — {2. iar fiecare din cele n–1 extrageri ale unei muchii minime se face intr-un timp in O(log m) = O(log n). se alege o muchie de cost minim. la fiecare pas. 5. cu cate o ramura. ordinul timpului ramane acelasi cu cel al vechiului algoritm. multimea U a varfurilor acestui arbore contine un singur varf oarecare din V. acest timp este si in O(m log n). 3. 3.

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

.5. Figura 11.5 Un graf orientat. Pasul initializare 1 2 3 v — 5 4 3 C {2. toate varfurile din graf sunt in S. Solutia se va construi in tabloul D[2 . bucla greedy se repeta de doar n-2 ori. cu L[i. n. si ca matricea L da lungimea fiecarei muchii. 20. sunt in S.3.. Presupunem. un tablou D contine lungimea celui mai scurt drum special catre fiecare varf al grafului.3 Algoritmul lui Dijkstra aplicat grafului din Figura 11. 3. atunci D[i] da lungimea celui mai scurt drum de la sursa catre i. n]. Observam ca D nu se schimba daca mai efectuam o iteratie pentru a-l scoate si pe {2} din C. 3.. 30. Algoritmul este: function Dijkstra(L[1 . . de asemenea.algoritmului. daca un varf i i) este in S. 100. 2. pentru simplificare. ca varfurile sunt numerotate. 10] [50. La terminarea algoritmului. 5} {2. Dupa ce adaugam un nou varf v la S.. toate varfurile grafului. 30. Se poate demonstra urmatoarea proprietate: Proprietatea 11. w]) return D Pentru graful din Figura 11. rezulta ca algoritmul lui Dijkstra functioneaza corect. cu exceptia unuia. ... D[v]+L[v. ii) nu este in S. daca muchia (i. Cand algoritmul se termina. 10] [40.. n}. 20. 4. n} {S = V \C exista doar implicit} for i ← 2 to n do D[i] ← L[1. 10] Tabelul 11. Din proprietatea precedenta. 3} {2} D [50. n]) {initializare} C ← {2. 20.. In algoritmul lui Dijkstra. i] {bucla greedy} repeat n–2 times v ← varful din C care minimizeaza D[v] C ← C \ {v} {si. 105 . deci toate drumurile de la sursa catre celelalte varfuri sunt speciale si valorile din D reprezinta solutia problemei. V = {1. 3. j] = + ∞ . S ← S ∪ {v}} for fiecare w ∈ C do D[w] ← min(D[w]. 30. 1 . varful 1 fiind sursa. atunci D[i] da lungimea celui mai scurt drum special de la sursa catre i.5. implicit. pasii algoritmului sunt prezentati in Tabelul 11.5. cel mai scurt drum special catre v va fi. De aceea. 30. 4} {2.. 10] [35. j) nu exista. cel mai scurt dintre toate drumurile catre v.

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

in cadrul unor sali de clasa. care nu este in mod necesar solutia optima a problemei. despre care nu se poate demonstra ca furnizeaza solutia optima. De exemplu. de fapt. mai putem colora tot in rosu varfurile 3 si 4. toti algoritmii care gasesc solutia optima sunt exponentiali.2 Problema comis-voiajorului Se cunosc distantele dintre mai multe orase. prin metoda greedy. practic. Cautam un ciclu de lungime minima. Daca fiecarui varf ii corespunde o tara. adica un graf care poate fi desenat in plan fara ca doua muchii sa se intersecteze. Problema colorarii unui graf poate fi interpretata si in contextul planificarii unor activitati. principiul care sta la baza metodei greedy. 3. Celebritatea problemei consta in faptul ca. care sa se inchida in varful initial si care sa treaca prin toate varfurile grafului. iar doua varfuri adiacente reprezinta tari cu frontiera comuna. dar este simplu si eficient. ne-au fost suficiente doua culori. 11. apoi consideram varfurile ramase. Folosim urmatorul algoritm greedy: alegem o culoare si un varf arbitrar de pornire. se putea demonstra ca pentru o harta oarecare este nevoie de cel mult 5 culori. iar muchiile unesc activitatile incompatibile. varfurile grafului reprezinta activitati. atunci se obtine o colorare cu trei culori. Cand nici un varf nu mai poate fi colorat. Mai putem colora cu albastru si varful 5. deci. astfel incat doua tari cu frontiera comuna sa fie colorate diferit. sa presupunem ca dorim sa executam simultan o multime de activitati.6. sunt exponentiali. Daca in graful din Figura 11.1 Colorarea unui graf Fie G = <V. care rezolva optim aceasta problema. Rezulta ca. De ce suntem atunci interesati intr-o astfel de rezolvare? Toti algoritmii cunoscuti. 4. repetand procedeul. este un algoritm euristic. In acest caz. fara a schimba culoarea.6. M> un graf neorientat. Un algoritm greedy. Problema poate fi reprezentata printr-un graf neorientat. in toate exemplele intalnite. 107 . nu obtinem decat o solutie euristica. ale carui varfuri trebuie colorate astfel incat oricare doua varfuri adiacente sa fie colorate diferit. Algoritmul greedy euristic propus furnizeaza doar o solutie “acceptabila”. atunci hartii ii corespunde un graf planar. colorarea s-a putut face cu cel mult 4 culori. incercand sa le coloram. Si pentru aceasta problema. Aceasta in timp ce. schimbam culoarea si varful de start. in care oricare doua varfuri diferite ale grafului sunt unite intre ele printr-o muchie. nu pot fi folositi pentru cazuri mari. Deci. Vom da doua exemple de utilizare a algoritmilor greedy euristici.6 Un graf care va fi colorat. Numarul minim de culori necesare pentru a colora graful corespunde numarului minim de sali necesare. de lungime nenegativa. Daca coloram varfurile in ordinea 1. Un comis-voiajor pleaca dintr-un oras si doreste sa se intoarca in acelasi oras. colorandu-l in albastru. 2. Problema este de a minimiza lungimea drumului parcurs. Apoi. 5. Problema este de a obtine o colorare cu un numar minim de culori. Figura 11. schimbam culoarea si pornim cu varful 2. teoretic.6 pornim cu varful 1 si il coloram in rosu. 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. 11.Regasim. dupa ce a vizitat fiecare din celelalte orase exact o data.

{3. 5. 1) de lungime 58. 4. muchiile se aleg in ordinea: {1. 6}. {2. 2. 2}. pentru sase orase a caror matrice a distantelor este data in Tabelul 11.Conform strategiei greedy. 4. {1. De exemplu. care completeaza ciclul) • nu exista inca doua muchii deja selectate. 1) are lungimea 56. 6. 5. 5}.4. 6} si se obtine ciclul (1. {4. 5}. 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. deoarece ciclul (1. 3}. Algoritmul greedy nu a gasit ciclul optim. 3. 108 . vom construi ciclul pas cu pas. 2. 3.4 Matricea distantelor pentru problema comis-voiajorului. {4. 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. 6.

CAPITOLUL XII STUDII DE CAZ – APLICAŢII 109 .

j As Integer cit_n "n = ". y) Loop Until n > 0 And n < 100 End Sub 3. i As Integer. Două numere sunt gemene dacă sunt ambele prime şi diferenţa dintre cel mai mare şi cel mai mic este 2. Citirea unui vector cu n componente Sub cit_date(mes As String. a As vector) For i = 1 To n 110 ." + Str$(i + 2) + ")" + Chr(13) End If Next End Sub 2. Să se determine toate numerele perechile de numere gemene pana la o anumita valoare n. n As Integer. Să se citească o valoare naturala n cu valori cuprinse intre 1 şi 100.1. p As Integer. Sub cit_n(mes As String. n As Integer. nnn As Integer) Do nnn = InputBox(mes. Private Sub CommandButton1_Click() Dim rad As Integer. 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) + ".

a back_prod_cart End Sub 7. a tipar " multimile sunt : ". Generarea produsului cartezian a n mulţimi utilizând metoda backtracking Private Sub CommandButton16_Click() Dim a As vector cit_n "n=".v(i)) + ". y) Next End Sub 4. n cit_n "p = ". n back End Sub 9. Generarea permutărilor utilizănd metoda backtracking Private Sub CommandButton14_Click() cit_n "n = ". Generarea partiţiilor unei mulţimi utilizănd metoda backtracking Private Sub CommandButton19_Click() 111 ." " " + sir 5. n cit_date "a". p back_comb End Sub 10. n. n cit_n "p = ". n As Integer. a As vector) n Str$(a. Tipărirea unui tablou cu n componente Sub tipar(mes sir = "" For i = 1 To sir = sir + Next MsgBox mes + End Sub As String. Generarea combinărilor (de n luate câte m) utilizănd metoda backtracking Private Sub CommandButton18_Click() cit_n "n = ". Generarea permutărilor utilizănd metoda backtracking Private Sub CommandButton17_Click() cit_n "n = ". p back_aranj End Sub 8. n back_perm End Sub 6. n. “Problema celor n dame” utilizănd metoda backtracking Private Sub CommandButton15_Click() cit_n "n = ".v(i) = InputBox(mes + "(" + Str$(i) + ")=".a.

v(p) = a. a tipar "sirul dat este : ". q As Integer.v(i) <= a. a As vector) Dim b As vector.v(p) a.v(q) = m End If End Sub 13. a divimp 1.v(pp) = x Then l = False MsgBox "numarul x = " + Str$(x) + " se afla printre elementele vectorului a" End If If a. Sortarea “Merge-Sort” utilizând metoda “Divide et impera” Sub interc(p As Integer. n cit_date "a". a As vector) Dim m As Integer If a. n.v(i) 112 . Căutarea binară utilizând metoda “Divide et Impera” pentru sortarea unui şir de numere Private Sub CommandButton2_Click() Dim n As Integer. n. a x = InputBox(" x = ". k As Integer i = p j = m + 1 k = 1 While (i <= m) And (j <= q) If a.cit_n "n=". q As Integer. n. y) st = 1 dr = n l = True While st <= dr And l = True pp = (st + dr) / 2 If a. m As Integer.v(q) a. x As Integer.1 End If Wend If l = True Then MsgBox "numarul x = " + Str$(x) + " nu se fala in sir " End If End Sub 12. n back_partitii End Sub 11. n.v(j) Then b.v(pp) < x Then st = pp + 1 Else dr = p . a As vector cit_n "n = ".v(q) Then m = a. a 'MsgBox "Sirul a sortat este" tipar "Sirul a sortat este". j. i.v(p) > a.v(k) = a. Realizarea unei subrutine pentru sortarea rapidă “Quicksort” Sub sort(p As Integer.

p) <= 1 Then sort p. i) = mat. n. a Else m = Int((p + q) / 2) divimp p.v(j) j = j + 1 k = k + 1 End If Wend If i <= m Then For j = i To m b.m(j. q.v(j) k = k + 1 Next Else For i = j To q b. j) Next Next back_col End Sub 113 . a End If End Sub 15. q. Sortarea rapidă utilizând metoda “Divide et impera” Sub divimp(p As Integer. Problema colorării hărţilor utilizând metoda backtracking Private Sub CommandButton20_Click() Dim mat As matrice cit_n " n = ".v(i) = b. mat For i = 1 To n For j = 1 To n mat. q As Integer.v(i) k = k + 1 Next End If k = 1 For i = p To q a.v(k) k = k + 1 Next End Sub 14. a As vector) Dim m As Integer If (q .v(k) = a.m(i.i = i + 1 k = k + 1 Else b. n. a interc p. m. n cit_mat "a". a divimp m + 1. m. n.v(k) = a. q. mat tipar_mat "a". n.v(k) = a.

v(j) Then k = k + 1 c. x As Integer. b divimp 1. n cit_date "a". k. m. Sortarea Shell-Sort utilizând metoda Greedy Private Sub CommandButton4_Click() Dim n As Integer.v(l) Next End If If j <= m Then For l = j To m k = k + 1 c. k As Integer. m.v(i) i = i + 1 j = j + 1 Else k = k + 1 c. n. b tipar "sirul dat este : ".v(j) j = j + 1 End If End If Wend If i <= n Then For l = i To n k = k + 1 c. a tipar "sirul dat este : ". m cit_date "a".v(k) = a.v(k) = b.v(i) i = i + 1 Else If a. a 'MsgBox "Sirul a sortat este" tipar "Sirul a sortat este". b i = 1 j = 1 k = 0 While i <= n And j <= m If a.v(j) Then k = k + 1 c. n. Interclasarea a 2 şiruri ordonate crescător Private Sub CommandButton3_Click() Dim n As Integer. b As vector. m.v(k) = b.16. b 'MsgBox "Sirul a sortat este" tipar "Sirul b sortat este". a divimp 1.v(k) = a. k As Integer.v(i) < b. c As vector cit_n "n = ". n.v(k) = a. m As Integer. m. a cit_n "m = ".v(l) Next End If tipar "A U B = ". n.v(i) = b. a As vector 114 . a As vector. c End Sub 17.

n.v(i + k) a. j) = InputBox(mes + "(" + Str$(i) + ". m cit_mat "a". m As Integer. Citirea si scrierea unei matrici pe ecran Private Sub CommandButton5_Click() Dim n As Integer. n. n As Integer. j)) + " " Next sir = sir + Chr(10) Next MsgBox sir 115 . m As Integer. n. Scrierea unei matrici pe ecran Sub tipar_mat(mes As String." + Str$(j) + ")=". a As matrice) For i = 1 To n For j = 1 To m a. m As Integer. a End Sub 19. n As Integer. n.cit_n "n = ". a As matrice) sir = mes + Chr(10) For i = 1 To n For j = 1 To m sir = sir + Str$(a. p As Integer. c As matrice cit_n "n = ".v(i) a.v(i + k) Then x = a. Citirea unei matrici de pe dispozitivul de intrare Sub cit_mat(mes As String.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". a As matrice. a tipar_mat "a". b As matrice.v(i) = a.v(i) > a. a End Sub 18. m. a k = n Do k = k / 2 Do b = 1 For i = 1 To n .m(i. n. a tipar "sirul dat este : ". m. n cit_date "a". n cit_n "m = ". y) Next Next End Sub 20.k If a.m(i.

m(i.m(i. p 'cit_n "m = ". c As matrice) For i = 1 To n For j = 1 To p c. a tipar_mat "a". p. b As matrice. a. b tipar_mat "m". Programul principal pentru adunarea a două matrici Private Sub CommandButton7_Click() Dim n As Integer. j) Next Next Next End Sub 22. p. a 'cit_n "p = ". b As matrice. n cit_n "m = ". j) Next Next 116 . j) = a. m. n. p As Integer. n. c As matrice cit_n "n = ". b prod_mat n.m(i. m As Integer. n cit_n "m = ". m As Integer.m(i. k) * b. n. m. j) + a. m.m(k. m cit_mat "a". p. c tipar_mat "a+b=".m(i. m. m As Integer. n.End Sub 21. c As matrice) For i = 1 To n For j = 1 To m c. a. m. a As matrice. n. p As Integer. a As matrice. b tipar_mat "b". j) = 0 For k = 1 To m c. m. m. a As matrice. b ad_mat n. n. c End Sub Sub prod_mat(n As Integer. m cit_mat "a". p 'cit_n "m = ". b. m. n. m.m(i. c tipar_mat "axb=". a cit_n "p = ". m cit_mat "b". m. Subrutina pentru adunarea a două matrici Sub ad_mat(n As Integer. j) + b. j) = c. p As Integer. b As matrice. a tipar_mat "a". m As Integer. c End Sub 23. b. n. m cit_mat "b". m. p. b As matrice. Produsul a două matrici Private Sub CommandButton6_Click() Dim n As Integer.m(i. c As matrice cit_n "n = ". a As matrice.

m cit_mat "a". n. c As matrice. b As matrice. k 'cit_n "m = ".31.31. n. a As matrice. b tipar_mat "b". j) Next Next End Sub 26. m As Integer. Subrutina pentru adunarea a două matrici Sub scad_mat(n As Integer. m 'cit_mat "b". b scad_mat n. m cit_mat "b". n. n. n.31. a As matrice. a As matrice. a. b putere_mat n. c End Sub 27.m(i. k As Integer. c As matrice) For i = 1 To n For j = 1 To m c.m(i. n.b. k. k As Integer 'Sub scad_mat(n As Integer. m. m.30. c1 As matrice For i = 1 To n For j = 1 To n 117 . n. j) . a cit_n "putere = ". c tipar_mat "a^p=".30. p As Integer. c As matrice) 'const t as vector ={0. n cit_n "m = ".30. n. m. m As Integer. a. j) = a. m cit_mat "a". c End Sub 25. n. a As matrice. m As Integer. m. a As matrice. n. m. n. n. b As matrice. m. Subprogramul pentru ridicarea unei matrici la o putere p Sub putere_mat(n As Integer. Programul principal pentru scăderea a două matrici Private Sub CommandButton8_Click() Dim n As Integer. c As matrice) Dim b As matrice.30} cit_n "n = ".28. Programul principal pentru ridicarea unei matrici la o putere p Private Sub CommandButton9_Click() Dim n As Integer.31. b. a tipar_mat "a".End Sub 24.31. c As matrice cit_n "n = ". n.30. a 'cit_n "p = ". b As matrice. m As Integer. b As matrice. p As Integer.m(i. m. b 'tipar_mat "b". p 'cit_n "m = ".31. a tipar_mat "a". n 'cit_n "m = ". m. c tipar_mat "a-b=".

m(i.m(i.ss(k) + 1 Else am_suc = False End If End Sub 30. n.m(i. k As Integer) If st.ss(k) = st.m(i.ss(k) < n Then am_suc = True st. st As stiva. j) = 0 c1. j) = 0 Next Next End Sub 28. j) = 0 Next Next Wend For i = 1 To n For j = 1 To n c. i) = 1 Next 'Next While k > 0 If k Mod 2 = 1 Then prod_mat n. b k = Int(k / 2) For i = 1 To n For j = 1 To n a.m(i.p + k Then 118 .m(i. Subrutina successor pentru “problema celor n dame” Sub succesor(am_suc As Boolean. j) = 0 Next Next For i = 1 To n c.m(i. j) = 0 Next Next prod_mat n. n. n.m(i.c.ss(k) < n . a. j) 'c1. j) 'c1. st As stiva) st. Subrutina successor pentru generarea combinărilor Sub succesor_c(am_suc As Boolean. j) = b. k As Integer) If st.ss(k) = 0 End Sub 29. c End If For i = 1 To n For j = 1 To n c1.m(i. c1. j) = c. st As stiva. i) = 1 c1.m(i.m(i. j) 'c1. Subrutina de iniţializare a stivei pentru metoda backtracking Sub init(k As Integer. j) = c1.m(i. n.m(i. a. a.

k As Integer) If st. k As Integer) ev = True For i = 1 To k .am_suc = True st. Subrutina succesor pentru problema “produsului cartezian a n mulţimi” utilizând metoda backtracking Sub succesor_prod(am_suc As Boolean.ss(i) = st.v(k) Then am_suc = True st. st As stiva.st.ss(i) .ss(k)) Or (Abs(st.1 If (st. Subrutina successor pentru colorarea hărţilor Sub succesor_col(am_suc As Boolean.ss(k) + 1 Else am_suc = False End If End Sub 31. k As Integer) ev = True For i = 1 To k .ss(k) < 4 Then am_suc = True st.1 119 . k As Integer) Dim i As Integer ev = True For i = 1 To k . Subrutina valid pentru “problema celor n dame” Sub valid(ev As Boolean.ss(k) + 1 Else am_suc = False End If End Sub 32.ss(k)) And (mat. k As Integer) If st.1 If (st.ss(i) = st. st As stiva. st As stiva.ss(k) + 1 Else am_suc = False End If End Sub 33.m(i.ss(k) = st.ss(k) < a. k) = 1) Then ev = False End If Next End Sub Sub valid_c(ev As Boolean.ss(k) = st.ss(k)) = Abs(k i)) Then ev = False End If Next End Sub 34.ss(k) = st. st As stiva. st As stiva. Subrutina valid pentru colorarea hărţilor Sub valid_col(ev As Boolean.

" + Str$(st. culoarea " + Str$(st." Next MsgBox b End Sub 39. Subrutina tipărire pentru “colorarea hărţilor” Sub tipar_col() Dim i As Integer.ss(i)) + ").If (st. b As String b = " " For i = 1 To n b = b + "(" + Str$(i) + ". Subrutina tipărire pentru “problema celor n dame” Sub tiparr() Dim i As Integer. Subrutina soluţie pentru generarea permutărilor Function solutie(k As Integer) As Boolean If k = n Then solutie = True Else solutie = False End If End Function 37.1) Then ev = False End If End If End Sub 35. st As stiva. k As Integer) ev = True End Sub 36. Subrutina soluţie pentru generarea aranjamentelor sau combinărilor Function solutie1(k As Integer) As Boolean If k = p Then solutie1 = True Else solutie1 = False End If End Function 38. b As String b = " " For i = 1 To n b = b + "Tara = " + Str$(i) + ". Subrutina valid pentru “produs cartezian a n mulţimi” Sub valid_prod(ev As Boolean.ss(k) < st.ss(i)) + " " Next 120 .ss(i) = st.ss(k .ss(k)) Then ev = False End If Next If k > 1 Then If st.

Subrutina back pentru “generarea permutărilor” Sub back_perm() Dim k As Integer k = 1 init k. st End If Else 121 . 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. st End If Else k = k . Subrutina back pentru “problema celor n dame” Sub back() Dim k As Integer k = 1 init k. k If am_suc = True Then valid1 ev. st. st. st While k > 0 Do succesor am_suc. 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.MsgBox b End Sub 40. st. ib_title) back End Sub 42.1 End If Wend End Sub 41. k If am_suc = True Then valid ev. st While k > 0 Do succesor am_suc. Programul principal pentru “problema celor n dame” Sub Button2_Click() n = InputBox("n=".

1 If (st. Subrutina valid pentru metoda backtracking Sub valid1(ev As Boolean. b As String 122 . Subrutina tipar pentru metoda backtracking Sub tipar_r() Dim i As Integer.k = k .1 End If Wend End Sub 44. st. st While k > 0 Do succesor am_suc. k If am_suc = True Then valid1 ev. b As String b = " " For i = 1 To n b = b + Str$(st. Subrutina tipar pentru metoda backtracking Sub tipar_rr() Dim i As Integer. st.ss(k)) Then ev = False End If Next End Sub 45. Subrutina back pentru “generarea aranjamentelor” Sub back_aranj() Dim k As Integer k = 1 init k. 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 As stiva. st End If Else k = k ." Next MsgBox b End Sub 46. k As Integer) ev = True For i = 1 To k .ss(i) = st.1 End If Wend End Sub 43.ss(i)) + ".

1 End If Wend End Sub 48.1 End If Wend 123 . Subrutina back pentru “generarea combinărilor” Sub back_comb() Dim k As Integer k = 1 init k. st End If Else k = k . k If am_suc = True Then valid_c ev. Subrutina back pentru “generarea produsului cartezian a n multimi” Sub back_prod_cart() Dim k As Integer k = 1 init k. st. st While k > 0 Do succesor_prod am_suc.b = " " For i = 1 To p b = b + Str$(st." Next MsgBox b End Sub 47. k If am_suc = True Then valid_prod ev.ss(i)) + ". st End If Else k = k . 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. 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 While k > 0 Do succesor_c am_suc. st. st.

Subrutina tiparire pentru problema “generare partiţii” a unei mulţimi Sub tipar_part() Dim i As Integer.ss(1) For i = 2 To n If max < st. sir As String sir = "" max = st. k As Integer) Dim i As Integer. Subrutina succesor pentru problema “generare partiţii” a unei mulţimi Sub succesor_part(am_suc As Boolean.1 End If Wend End Sub 50. st While k > 0 Do succesor_part am_suc. st. st. k If am_suc = True Then valid_prod ev. j As Integer. max As Integer If k = 1 Then max = 1 124 .End Sub 49. st As stiva.ss(i) End If Next sir = " PARTITII " For j = 1 To max For i = 1 To n If 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. Subrutina back pentru “generarea partiţiilor unei mulţimi” Sub back_partitii() Dim k As Integer k = 1 init k. st End If Else k = k .ss(i) Then max = st. max As Integer.ss(i) = j Then sir = sir + Str$(i) + " " End If Next sir = sir + Chr(10) Next MsgBox sir End Sub 51.

ss(k) < max + 1 And st. Subrutina back pentru “colorarea hărţilor” Sub back_col() Dim k As Integer k = 1 init k.ss(k) + 1 Else am_suc = False End If End Sub 52. 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. Programul principal pentru inversarea unui număr natural n 125 . st.1 End If Wend End Sub Public s As String 53. st While k > 0 Do succesor_col am_suc. Funcţia pentru a verifica dacă un număr 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.ss(k) < k Then am_suc = True st. st.1 If max < st. k If am_suc = True Then valid_col ev.Else max = st.ss(i) Then max = st. st End If Else k = k .ss(1) For i = 2 To k .ss(i) End If Next End If If st.ss(k) = st.

Sortarea unui sir cu n componente utilizând metoda bulelor Private Sub Buton11_Click() Dim n As Integer.v(i + 1) Then x = a. b) If c = 1 Then MsgBox " nr.v(i) > a. b)) End If End Sub 56. b As Integer. n. a End Sub 57.v(i) 126 . n1 As Integer. c As Integer Do a = InputBox("a = ". a As vector cit_n "n = ". n. sunt prime intre ele (" + Str$(a1) + ". a tipar "vectorul initial a este ". n. y) a1 = a b1 = b Loop Until a > 0 And b > 0 And a > b c = euclid2(a. Subrutina pentru sortarea prin metoda bulelor Sub bule(n As Integer. ninv As Integer. sir As String Do n = InputBox(" n = ". a tipar "vectorul a sortat este : ".Sub buton1_Click() Dim n As Integer. a As vector) Do k = 0 For i = 1 To 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. n cit_date "a"." + Str$(b1) + ")=" + Str$ (euclid2(a. a bule n. y) b = InputBox("b = ".1 If a." + Str$(b1) + ")" Else MsgBox "Cmmdc (" + Str$(a1) + ".

v(k) a. s As Long.v(j) k = j End If Next If k <> i Then x = a. a As vector) For i = 1 To n .v(k) = x End If Next End Sub 60. n cit_date "a". n. Suma cifrelor unui număr natural dat n Sub buton2_Click() Dim n As Integer. n. n. n.v(i) = a. n. a As vector cit_n "n = ".v(i) k = i For j = i + 1 To n If min > a.v(i) a. a End Sub 59. Subrutina pentru sortarea prin metoda selecţiei directe Sub selectie(n As Integer. a selectie n. n1 As Integer Do n = InputBox(" n = ". Sortarea unui sir cu n componente utilizând metoda selecţiei directe Private Sub Buton12_Click() Dim n As Integer. a tipar "vectorul a sortat este : ".a. a tipar "vectorul initial a este ". a tipar "vectorul initial a este ".v(i + 1) a.v(i + 1) = x k = 1 End If Next Loop Until k = 0 End Sub 58.v(j) Then min = a. a As vector cit_n "n = ". n cit_date "a". a End Sub 61. Sortarea unui sir cu n componente utilizând metoda prin numărare Private Sub Buton14_Click() Dim n As Integer. a numarare n. a tipar "vectorul a sortat este : ".v(i) = a.1 min = a. y) Loop Until n > 0 127 . n.

Verificarea unui numar natural n daca este prim sau nu Sub buton3_Click() Dim n As Integer. 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. n1 As Integer. s As Long. s As Long. i As Integer Do n = InputBox(" n = ". Determinarea numerelor prime mai mici sau egale cu n utilizând metoda directă Sub buton4_Click() Dim n As Integer." i = 3 While i <= n If prim(i) = True Then sir = sir + Str$(i) + ".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. n1 As Integer Do n = InputBox(" n = ". Ciurul lui Eratostene 128 ." End If i = i + 2 Wend End If MsgBox "numere prime sunt : " + sir End Sub 64. y) Loop Until n > 0 n1 = n If n = 2 Then MsgBox "numerele prime sunt : 2" Else sir = "2.

" End If Next MsgBox "Numerele prime sunt : " + sir End Sub 65.v(i) <> 0 Then sir = sir + Str$(i) + ". sir As String Do n = InputBox(" n = ".v(i) = i Next For i = 2 To Int(Sqr(n)) If a.Sub buton5_Click() Dim n As Integer. n1 As Integer Do n = InputBox(" n = ". Scrierea unui număr ca suma a două cuburi 129 . sir As String. a As vector. 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.v(j) = 0 Wend End If Next sir = "" For i = 2 To n If a.v(i) <> 0 Then j = 2 * i While j <= n j = j + i a. y) Loop Until n > 0 For i = 1 To n a. Descompunerea unui numar in factori primi Sub buton6_Click() Dim n As Integer. a As vector.

" + Str$(b1) + ")=" + Str$ (euclid(a. c As Integer Do a = InputBox("a = ". 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 utilizând recursivitatea Sub buton8_Click() Dim a As Integer. b) If c = 1 Then MsgBox " nr. b As Integer. y) a1 = a b1 = b Loop Until a > 0 And b > 0 And a > b c = euclid(a. b)) End If End Sub 68. b As Integer) As Integer Dim r As Integer Do r = a Mod b MsgBox r 130 .Sub buton7_Click() Dim n As Integer. a As vector. y) b = InputBox("b = ". sir As String." + Str$(b1) + ")" Else MsgBox "Cmmdc (" + Str$(a1) + ". n1 As Integer Do n = InputBox(" n = ". Funcţia euclid Function euclid(a As Integer. sunt prime intre ele (" + Str$(a1) + ".

a Mod b) End If End Function 72. b . sunt prime intre ele (" + Str$(a1) + ". CMMDC a două numere utilizând scăderi repetate Private Sub Buton9_Click() Dim a As Integer. b As Integer) As Integer If b = 0 Then euclid2 = a Else euclid2 = euclid2(b. c As Integer Do a = InputBox("a = ".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. Funcţia Euclid utilizând scăderi repetate Function euclid1(a As Integer. y) b = InputBox("b = ". b) If c = 1 Then MsgBox " nr. b As Integer.b. Funcţia Euclid utilizând scăderi repetate Function euclid2(a As Integer. y) a1 = a b1 = b Loop Until a > 0 And b > 0 And a > b c = euclid1(a. b)) End If End Sub 70." + Str$(b1) + ")" Else MsgBox "Cmmdc (" + Str$(a1) + ".a) Else euclid1 = a End If End If End Function 71. b As Integer) As Integer If a > b Then euclid1 = euclid1(a . x ^ y utilizând un număr minim de înmulţiri 131 ." + Str$(b1) + ")=" + Str$ (euclid1(a. b) Else If a < b Then euclid1 = euclid1(a.

t As Byte Do x = InputBox("baza=". n. ib_title) y = InputBox("exponent=". m As Long Do n = InputBox("n=". a 'MsgBox "Sirul a este" tipar "Sirul a este". bb. y. xx t = "" MsgBox "n = " + Str$(xx) For z = xx To 1 Step -1 t = t + Str$(bb. y As Integer. a End Sub 132 . a 'MsgBox "Sirul a sortat este" tipar "Sirul a sortat este".Sub Button15_Click() Dim x As Integer. y As Byte. t) MsgBox Str$(z) + " " + Str$(t . ib_title) Loop Until (x > 0) And (y > 0) z = putere(x.v(z)) Next MsgBox t End Sub 73. bb As vector Dim xx As Integer Do x = InputBox("a=". 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. Quicksort Sub Button18_Click() Dim n As Integer. a divimp 1. n. Verifică dacă un număr natural este palindrome sau nu Sub Button16_Click() Dim n As Long. n cit_date "a". t As String.1) End Sub 75. z As Double. ib_title) y = InputBox("b=". Baza la exponent Sub Button17_Click() Dim x As Double. a As vector cit_n "n = ". n. n. y. ib_title) Loop Until (x > 0) And (y > 0) And (x >= y) baza1 x. z As Integer.

a." Else hanoi n . b As sir. 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. c As sir) If n = 1 Then d = d + "(" + a. a End If End Sub 79. st. b d = d + "(" + a. st While k > 0 Do succesor am_suc.s + ").s + "). Subrutina Hanoi Sub hanoi(n As Integer. k If am_suc = True Then valid1 ev. Subrutina back pentru permutări Sub back_perm() Dim k As Integer k = 1 init k. a 'MsgBox "Sirul a este" tipar "sirul dat este ". c As sir d = "" a. c MsgBox d End Sub 78. n cit_date "a". Turnurile din Hanoi Sub Button20_Click() Dim n As Integer." hanoi n . n. c. st. a As vector cit_n "n=". Minimul dintr-un şir de numere utilizând divide et impera Sub Button19_Click() Dim n As Integer.1. a MsgBox "minimul in Sirul a este" + Str$(minim(1. a As sir. b.s = "B" c. a As sir. st End If Else 133 .s = "C" n = InputBox("n=".76.s + "->" + b. b.1.s = "A" b.s + "->" + b. a. c. n. b As sir. n)) End Sub 77. ib_title) hanoi n.

ss As String cit_n "n = ".k = k .-1 Private Sub Buttton3_Click() Dim n As Integer.………….1 End If Wend End Sub 80.1-1-1-1-1-1-1……. Calculul sumei 1-1. 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 .1-1-1..

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

Sign up to vote on this title
UsefulNot useful