Sunteți pe pagina 1din 89

Bazele algoritmilor

Prefaţă
Cursul se adresează tuturor celor care doresc să pătrundă tainele programării
calculatoarelor. Elevii, studenţii, profesorii şi orice persoană interesată în rezolvarea
problemelor cu ajutorul calculatorului pot face primii paşi parcurgând această carte.
A doua ediţie, modificată, la sugestiile studenţilor şi a profesorilor care au studiat
prima ediţie, restructurează materialul în doua mari părţi: elemente de algoritmică şi
respectiv elemente de programare avansată.
Subiectul acestei cărţi rămâne fundamentarea cunoştinţelor elementare legate de
elaborarea algoritmilor, structurarea şi conceperea acestora, precum şi modalităţi de
reprezentare a datelor în cadrul rezolvării problemelor cu ajutorul calculatorului şi
reprezintă prima categorie prezentată mai sus. Cursul parcurge gradat etapele de
elaborare a algoritmilor şi de rezolvare a problemelor.
Conţinutul lucrării este elaborat în trepte, cu succesiuni naturale ale
evenimentelor, începând cu noţiunile introductive despre algoritmi şi descrierea
acestora până la descrierea principalilor algoritmi împreună cu modalităţile de
reprezentarea a datelor. Prezentarea metodelor evoluate de programare va fi subiectul
celei de a doua părţi, pe care cititorii o vor găsi sub titlul Programarea calculatoarelor.
Capitolele care întregesc lucrarea se referă la elaborarea, corectitudinea,
complexitatea şi testarea algoritmilor, la modurile de reprezentare a datelor structurate.
Un capitol aparte este dedicat prezentării unor algoritmi elementari, de fapt, a
transcrierii algoritmice a unor concepte matematice foarte des utilizate în practică.
Chiar dacă această carte reprezintă un al doilea pas spre realizarea unui lucru util
nu avem pretenţia de a realiza totul perfect, aşa încât ideile, sugestiile şi alte critici
constructive vor fi bine venite. Concepţia şi structura cursului este realizată după o
experienţă de peste zece ani de predare a algoritmilor la nivel liceal şi universitar.
Foarte constructivă este oportunitatea de a participa, de peste opt ani, la pregătirea şi
desfăşurarea concursurilor de programare, a olimpiadelor de informatică, atât la nivel
local, cât naţional şi internaţional.
Raţionamentul logic este cheia succesului în elaborarea corectă a algoritmilor. În
acest sens am încercat structurarea şi organizarea tuturor noţiunilor şi termenilor
specifici algoritmilor prin clasificări, modularizări şi structurări ale noţiunilor de
învăţat, astfel încât învăţarea să se realizeze prin paşi mici. Fiecare temă sau
subcapitol este scurt, presărat cu exemple sau cu probleme rezolvate. În acest sens un
sprijin real este manualul de laborator şi seminar care va face mai uşoară munca de
autoevaluare, de autotestare şi exemplificare a elementelor teoretice prezentate în curs.
Avantajul acestui curs este independenţa de limbajul de programare ales de
programator.
Elementul specific, de curs, al acestei cărţi îl constituie succesiunile lecţie,
exemplu, temă şi evaluare. Toate acestea sunt prezente şi sunt însoţite de explicaţii şi
răspunsuri corecte. Evaluarea îmbracă diverse forme de la teme pe parcursul
explicaţiilor, la exerciţii de tip grilă şi probleme cu rezolvări.1
Considerând că, de la prima ediţie, în multe din punctele sale cartea a fost
completată şi îmbunătăţită, ea va fi un util suport de curs pentru studenţii anilor I ai
secţiilor de specialitate informatică, pentru cei care se pregătesc pentru susţinerea unui
examen sau a licenţei, dar şi studenţilor de diverse specializări a căror cursuri de
bazele informaticii conţin în măsură mai mare sau mai mică elemente de algoritmică şi
programare.
Pentru ca acest volum să ajungă într-o formă finală pe placul cititorilor voi ruga
pe toţi cei care simt nevoia unor precizări, modificări, reorganizări sau sugestii să nu
ezite în a trimite sugestii pe adresa ovidiu@lmm.uab.ro.
Cu precizarea că această carte este una de studiu, cu calculatorul alături, nu de
lectură, vă doresc succes în învăţarea bazelor algoritmilor.
Alba Iulia, Ovidiu Domşa
Septembrie 2001
1
Rezolvările problemelor apar şi în Manualul de algoritmică, editat în paralel
cu acest curs şi în foarte strânsă legătură, sub formă de programe în limbaj
Pascal şi de asemenea pe suport magnetic.

4
Curs

Motto:

“Studiul ştiinţific al fenomenelor naturii caută


să ia forma matematică şi acest studiu se
socoteşte deplin, când forma matematică a fost
găsită.”

Gheorghe Ţiţeica

5
Bazele algoritmilor

1. Introducere

1.1. Scurt istoric


Problema calculelor şi a reprezentării informaţiilor a fost o preocupare a omului
din cele mai vechi timpuri. Aşa de veche, se pare, încât nici limbajul uman nu era încă
utilizat pe când se puneau problemele reprezentării numerice a unor elemente din
natură.
Să considerăm problema numărului de animale vânate sau a numărului de
persoane dintr-un grup. Numărarea lor se realiza, probabil, folosind degetele de la
mâini, un deget pentru o unitate. Reprezentarea lor nu a întâmpinat nici o problemă
atâta timp cât degetele erau suficiente. Când numărătoarea a depăşit zece elemente au
trebuit construite reguli după care simbolurile numerale să fie înţelese. Pentru a
reprezenta un număr care depăşeşte zece unităţi au folosit probabil o piatră care să
simbolizeze zece unităţi. De exemplu 37 putea fi reprezentat prin 5 pietre şi 7 degete.
Timpul a pus însă probleme serioase atunci când şi cele zece pietre au fost
insuficiente. Dar creativitatea umană nu s-a lăsat mai prejos şi au simbolizat cele zece
pietre printr-un pietroi. Aşa încât 231 arăta ca în Fig. 1.

Fig. 1.

Pas cu pas, stabilind reguli de reprezentare şi respectând principiul “celor zece


degete”, s-a ajuns la diverse forme de scriere zecimală: grafice, cifre romane, cifre
arabe sau diverse alte simboluri. Cu toate acestea reprezentarea zecimală a rămas cel
mai uzual sistem de numeraţie, principiului de construire a numerelor fiind universal
valabil.
Imaginaţi-vă cum ar arăta sistemul de numeraţie al unor “marţieni” care au un
singur braţ şi doar două degete. Bineînţeles e vorba de sistemul binar de numeraţie,
care foloseşte doar simbolurile 0 şi 1, sistem utilizat în prezent de către calculatoare.
Matematica a preocupat permanent minţile luminate iar necesitatea de a realiza
calcule corect, rapid şi eficient a dus la construirea unor metode, a unor succesiuni de
paşi de urmat în scopul găsirii soluţiilor.
O metodă de înmulţire a două numere, cunoscută ca “înmulţirea a la russe”,
permite înmulţirea a doua numere după următoarele reguli:
- se aşează pe trei coloane deînmulţitul, înmulţitorul şi iarăşi înmulţitorul dacă
deînmulţitul nu e par (în binar nu se termină cu zero);
- se înjumătăţeşte deînmulţitul considerând doar partea întreagă;
- se dublează înmulţitorul;
- se continuă aceste secvenţe până când deînmulţitul devine 1;
- suma valorilor de pe a treia coloană reprezintă rezultatul înmulţirii.
Exemplul 1.
(6 x 9 = 54 în zecimal)
Reprezentate în binar:
110 1001 --
11 10010 10010
1 100100 100100
110110 (54 în zecimal)
Observaţie: Prin înjumătăţire (împărţire întreagă la 2) deîmpărţitul pierde ultima
cifră, iar prin înmulţire împărţitorului i se adaugă un 0. Un mod similar de calcul
folosesc şi calculatoarele.
Cuvântul care caracterizează în general reguli de calcul, succesiuni de paşi sau
operaţii, algorism, a fost introdus de Abu ’Abd Allah Muhammad ibn Musâ al
Khwârizmi2, persan din sec. VIII-IX, în cartea cunoscută în traducere latină ca
2
În traducere”Tatăl lui Abdullah, Mahomed, fiul lui Moise, originar din
Khwarizm”.

6
Curs
“Algorithmi de numero indorum” sau “Liber algorithmi”. Prin “algorithm” se definea
o regulă pe baza cărora se efectuau calcule matematice.
Cuvântul “Algorithm” poate proveni de la denumirea oraşului natal al
matematicianului persan, “al-Khwârizmi”, în traducere “din oraşul Khwârizmi”,
actualmente oraşul Khiva în Uzbekistan.
Totodată însă se poate observa ca din punct de vedere semantic cuvântul
algoritm conţine două cuvinte greceşti “algos” care înseamnă calcul (vezi cuvântul
algebră) şi “rytmos” care înseamnă ritm, succesiune.
Noţiunea de algoritm a fost folosită şi ulterior în lucrări care descriu în general
reguli de calcul. Dintre acestea amintim lucrările lui Stifer (“Arithmetica integra”,
1544), Cardano (“Ars magna sive de reguli algebraicis”, 1545), câţiva algoritmi foarte
cunoscuţi azi prin numele autorilor, “Algoritmul lui Euclid” pentru calculul celui mai
mare divizor comun, “Algoritmul lui Kruskal şi Prim” care determină arborele parţial
de cost minim sau algoritmi care sunt studiaţi încă în clasele primare “Împărţirea
numerelor întregi”, “Calculul radicalului de ordin doi” şi altele.
În jurul anului 1930 matematicienii K. Gödel, E. Prost, A. M. Turing, A. Church
au propus în mod independent diverse formalisme care descriu noţiunea de algoritm.
Aceştia tratează problema algoritmilor în strânsă legătură cu teoria funcţiilor
recursive, concept lansat de Kronecker (1886) şi Dedekind (1888).
În 1951 Markov defineşte algoritmul ca o metodă generală de rezolvare a unei
probleme sau o succesiune de reguli care executate în mod logic conduc la soluţia
dorită.
În Webster’s New World Dictionary cuvântul algoritm apare pentru prima dată
de-abia în 1957; până atunci figura doar forma mai veche „algorism”, cu înţelesul său
antic, acela de proces al efectuării operaţiilor aritmetice ce utilizează cifre arabe.
Dacă privim din acest sens Exemplul 1 se observă că în încercarea de a înmulţi
două numere, indiferent de baza lor de numeraţie, dacă respectăm succesiunea de paşi
prezentată, obţinem rezultatul corect pentru orice două numere date.
Descrierea algoritmilor precum şi verificarea acestora este o problemă care a
determinat crearea unor unelte specifice, formate dintr-un ansamblu algoritm-metodă
de verificare, numit în continuare programare. Calculatorul, ca unealtă de verificare a
algoritmilor, permite prin intermediul unor limbaje specifice, numite limbaje de
programare, transcrierea algoritmilor în limbaj maşină şi executate pas cu pas.
Printre limbajele de programare cele mai utilizate, în ordine cronologică,
amintim3: ForTran (1956), AlgoL (1960), COBOL (1960), LISP (1961), BASIC (anii
1960) PASCAL (1971), C (1972), SIMULA (1973), C++ (1982), SMALLTALK-80
(1983), ADA (1986), JAVA (1995 în România).
Aspectul matematic, riguros, al descrierii algoritmilor impune stabilirea unor
reguli şi legi precise de scriere.
Anii ’70 au cristalizat un nou concept de elaborare al algoritmilor. Bohm şi
Jacopini au pus bazele unui nou principiu în elaborarea algoritmilor, cel al programării
bazate pe structuri.
Preocupările actuale în domeniul programării o reprezintă conceptele de
programare orientată pe obiecte, care are la bază programarea bazată pe obiecte,
obiecte care încapsulează date (care caracterizează starea lor) şi acţiuni (care
caracterizează comportamentul obiectelor), la care se adaugă două atribute noi:
moştenirea şi polimorfismul. Dar cea mai actuală este tema programării folosind
“agenţi”.

1.2. Noţiunea de algoritm. Caracteristici.


Algoritmul este o noţiune abstractă şi la fel ca mulţimea nu are o definiţie
matematică riguroasă. Ca noţiune elementară şi deosebit de importantă vom
accepta algoritmul ca o succesiune logică de paşi, care, pornind de la o

3
Descrierea, clasificarea şi modul de adaptare a limbajului la problema de
rezolvat se poate citi în [Code Complete], pag. 45-50.

7
Bazele algoritmilor
mulţime de valori ca date de intrare produce o anumită mulţime de valori ca
date de ieşire în scopul rezolvării unei probleme.
Un algoritm poate fi privit ca un instrument de rezolvare a problemelor de calcul
bine definite. Astfel enunţul problemei specifică relaţia dorită intrare / ieşire, iar
algoritmul descrie o anumită procedură de calcul pentru a se ajunge la această legătură
intrare / ieşire.
Din acest punct de vedere se poate constata că pentru rezolvarea unei probleme
pot exista mai mulţi algoritmi.
Distingem trei mari componente ale unui algoritm (fig. 2.):
Date de Paşi Date de
Instrucţiuni Fig.2.
intrare ieşire

- date de intrare
- paşii algoritmului sau instrucţiunile algoritmului
- date de ieşire.
Dacă analizăm algoritmul de la Exemplul 1 observăm că datele de intrare sunt
cele două numere naturale, datele de ieşire sunt reprezentate de valorile parţiale
obţinute în coloana a treia şi suma acestora care este de fapt soluţia problemei.
Distingem trei tipuri de paşi folosiţi în descrierea noastră.
- paşi succesivi sau liniari:
“se înjumătăţeşte deînmulţitul considerând doar partea întreagă”,
“se dublează înmulţitorul”;
- paşi de decizie:
“înmulţitorul dacă deînmulţitul nu e par”(caracterizaţi de cuvântul dacă);
- paşi care determină repetiţia:
“se continuă aceste secvenţe până când deînmulţitul devine 1”
(caracterizaţi de secvenţa până când);
Observăm însă că descrierea făcută în Exemplul 1 nu este foarte exactă şi destul
de greu de înţeles. Un cunoscător al operaţiilor elementare ar putea, totuşi, rezolva
problema propusă, folosind algoritmul dat, pentru orice set de date de intrare.
Problema de care se lovesc în general cei care încearcă să pătrundă tainele
elaborării unui algoritm este de a identifica în mod corect datele problemei, respectiv
cerinţele acesteia şi de a găsi un model matematic de rezolvare. În acest scop
propunem următoarele etape în elaborarea unui algoritm, etape pe care le întâlnim de
altfel în rezolvarea oricărei probleme:
a.) Înţelegerea enunţului problemei
b.) Delimitarea datelor de intrare (ipoteza) şi a celor de ieşire (concluzia).
c.) Pornind de la datele de ieşire se construiesc paşii algoritmului
d.) Transcrierea algoritmului într-o formă de exprimare.
e.) Testarea corectitudinii algoritmului.

Exemplul 2:
Problema lui Fibonacci4, a modului de înmulţire a perechilor de iepuri.
Se ştie că fiecare pereche de iepuri dă naştere numai la o pereche de
iepuri în fiecare lună, o pereche devine fertilă la vârsta de o lună. Se
cere să se determine numărul de perechi de iepuri care provin dintr-o
singură pereche de iepuri, întru-un număr date dat de luni. (respectiv
într-un an)
Pentru a înţelege problema se poate trece la calcul şi se obţin uşor
numărul perechilor în momentul începerii experienţei, după o lună, după

4
Problema a fost descrisă în 1202 de Leonardo Pisano (Leonardo din Pisa),
care este cunoscut şi sub numele de Leonardo Fibonacci (Filius Bonaccii, fiul
lui Bonaccio), în lucrarea Liber Abaci (Cartea Abacului), ca următorul
exerciţiu: „Câte perechi de iepuri se pot obţine într-un an pornind de la o
singură pereche?”

8
Curs
două luni, după n luni, respectiv secvenţa:
1,1,2,3,5,8,13,..
Acest şir se numeşte Şirul lui Fibonacci, şi este caracterizat din punct de
vedere matematic de ecuaţiile:

f(0)=1, f(1)=1, f(x+2)= f(x)+ f(x+1),


pentru x>0 natural.

Datele de intrare ale algoritmului nostru vor fi: n, numărul de luni.


Datele de ieşire vor consta în valoarea F a funcţiei f(n) după n luni,
F=f(n)
Pentru realizarea calculelor vom avea nevoie de câteva valori
intermediare pe care să le calculăm, F0, F1 numărul perechilor la
momentul 0 şi după o lună, I care să numere lunile, E o expresie
intermediară, pentru păstrarea valorilor la trecerea de o lună la alta.
Următorul algoritm calculează valoarea lui F:

E1: Citeşte n
E2: Dacă n=0 sau n=1, atunci F1=1, E5
altfel E3
E3: F0=1; F1=1; I=1;
E4: E=F0; F0=F1; F1=F0+E;
E5: I=I+1;
E6: Dacă I<=n-1 atunci E4
altfel E 7
E7: F=F1;
E8: Scrie F
E9: Stop

Să verificăm acest algoritm, întocmind un tabel cu valorile intermediare


la fiecare pas, pentru n=4:

Paşi / I F0 F1 E F
Etape
1,2 - - - - -
3 1 1 1 - -
4 1 1 2 1 -
5 2 1 2 1 -
6 2 1 2 1 -
4 2 2 3 1 -
5 3 2 3 1 -
6 3 2 3 1 -
4 3 3 5 2 -
5 4 3 5 2 -
6 4 3 5 2 -
7 4 3 5 2 5
8 5
9 - - - - -

Exerciţiu.

Încercaţi pentru alte valori posibile ale lui n. De exemplu într-un an,
n=12.

Caracteristicile algoritmilor.

9
Bazele algoritmilor

Sensul unui algoritm este undeva similar cu cel de reţetă, proces, metodă,
tehnică, procedură sau rutină cu deosebirea că el reprezintă un set finit de reguli care
indică o secvenţă de operaţii în vederea rezolvării unei probleme şi are următoarele
caracteristici importante:
a.) Finitudinea este proprietatea algoritmilor de a furniza rezultatul după
parcurgerea unui număr finit de paşi. În exemplul 2 se observă ca după 15 paşi am
găsit soluţia. În înţelegerea corectă a caracterului finit al unui algoritm trebuie ţinut
cont de diferenţa între numărul de operaţii care descriu algoritmul şi numărul de paşi,
deoarece, o aceeaşi operaţie poate fi executată de mai multe ori, fiecare parcurgere a
unei operaţii însemnând un pas.
În algoritmul descris în Exemplul 2 algoritmul conţine 9 operaţii numerotate E1-
E9, iar soluţia se obţine după 15 paşi.

Exerciţiu.

Câţi paşi sunt necesari pentru găsirea soluţiei Problemei lui Fibonacci pentru
n=12.

Observaţie.
În elaborarea unui algoritm, cu toate că numărul de paşi este finit, trebuie avut în
vedere ca numărul acestor paşi să fie cât mai mic posibil, pentru a optimiza obţinerea
soluţiilor în cazul unor probleme cu număr mare de paşi. Dar despre acest lucru vom
vorbi în paragraful destinat complexităţii algoritmilor.

b.) Generalitatea este proprietatea algoritmilor de a furniza rezultate corecte


pentru toate valorile posibile ale datelor de intrare. Aceste valori sunt limitate doar de
capacitatea de calcul a sistemelor utilizate în testarea algoritmilor. Spunem că
algoritmul rezolvă o clasă de probleme definite de o aceeaşi funcţie. Algoritmul
problemei Fibonacci furnizează rezultat corect pentru orice n număr natural, finit.

c.) Unicitatea este caracteristica algoritmilor prin care informaţia trece prin
succesiuni bine determinate de regulile algoritmului. Deci, pentru aceleaşi date de
intrare se obţin aceleaşi rezultate ca urmare a parcurgerii exacte a aceloraşi secvenţe
de paşi. Din acest punct de vedere un algoritm poate fi privit ca o funcţie, unic
determinata A:D R, de la mulţimea datelor de intrare D la mulţimea rezultatelor R.
d.) Corectitudinea este proprietatea algoritmilor prin care toţi paşii sunt
determinaţi în mod unic, se succed în mod logic, iar regulile se bazează pe principii
reale fără ambiguităţi. De regulă corectitudinea unui algoritm se demonstrează pe baza
unui model matematic. Acest model matematic este descris, pentru o mai mare
exactitate, folosind limbaje de programare, limbaje formale, bazate pe reguli stricte.
Expresia unei metode de calcul într-un limbaj de programare se numeşte program.
Modelul matematic utilizat în descrierea funcţiei din exemplul 2 este cel al unei
funcţii recursive de ordinul doi. Principiul recursivităţii este de altfel una din temele
capitolelor următoare.

1.3.Verificarea cunoştinţelor

E.1. Aplicând algoritmul de “înmulţire a la ruse” rezultatul corect al operaţiei


10101 x 1001, în binar, este:
a) 10101010 b) 11001101 c) 10111101

E.2. Care din următoarele reguli sunt algoritmi:


a) reguli de circulaţie

10
Curs
b) orarul săptămânal al studenţilor pentru un semestru
c) reguli de funcţionare ale laboratorului de informatică
d) programul de desfăşurare al unei excursii bine organizate

E.3. Care din următoarele componente nu sunt specifice algoritmilor:


a) programatorul
b) date de intrare
c) limbaj de programare
d) date de ieşire

E.4. Aplicaţi algoritmul problemei lui Fibonacci pe perioada unui an (12 luni) şi
precizaţi numărul perechilor de iepuri:
a) 377 b) 144 c) 233

E.5. Care din următoarele caracteristici nu sunt specifice algoritmilor:


a) flexibilitatea
b) generalitatea
c) actualitatea
d) corectitudinea
e) Finitudinea

E.6. Care din următoarele afirmaţii sunt adevărate:


a) Orice algoritm corect se încheie după un număr finit de paşi.
b) Un algoritm corect furnizează întotdeauna acelaşi rezultat pentru aceleaşi
date de intrare.
c) Paşii unui algoritm trebuie parcurşi exact în ordinea în care au fost scrişi.
d) Prelucrarea datelor unui algoritm respectă succesiunea: date de intrare, date
intermediare (dacă este cazul), date de ieşire.

T.7. Descrieţi un algoritm la alegere. Specificaţi datele de intrare, datele de ieşire,


eventual date intermediare necesare şi succesiunea paşilor.

1.4. Răspunsuri.

E.1. c);
E.2. b), d);
E.3. a);
E.4. c)
E.5. a) c )
E.6. a) b) c) d)
T.7. Încercaţi să descrieţi algoritmul de adunare a doua numere naturale a şi b.

11
Bazele algoritmilor

2. Descrierea algoritmilor

2.1.Proiectarea algoritmilor
Problema realizării unui algoritm pornind de la cerinţele unei problemei
presupune parcurgerea unor etape de construire a paşilor. Secvenţa logică de
construire a paşilor poate fi concepută în cel puţin două moduri:
- proiectarea descendentă, numită top-down (de sus în jos), presupune
construirea metodei de rezolvare pornind de la cerinţele problemei, explicând,
definind, aplicând propoziţii, proprietăţi ale noţiunilor cerute până la descompunerea
în elemente de bază, date cunoscute, definiţii elementare. Această metodă este
cunoscută şi sub numele de metoda rafinărilor succesive. Acest mod de proiectare a
algoritmilor permite programatorului definirea principalelor componente ale
algoritmului şi delimitarea eventualelor subprobleme, iar pentru probleme mai vaste,
împărţirea ei în module, şi rezolvarea acestora în echipe. Modelul de proiectare top-
down este un model constructiv, bazat pe construirea pas cu pas a etapelor de
rezolvare.
Când problema de rezolvat este vastă se procedează la descompunerea ei în
subprobleme independente, unele dintre acestea se pot descompune la rândul lor, iar în
final fiecare subproblemă se rezolvă independent. În final se stabilesc legăturile şi
succesiunea în care aceste subprobleme sunt rezolvate
Exemplul 1:

Să se proiecteze un algoritm care permite rezolvarea unei ecuaţii de


gradul al doilea cu coeficienţi reali.
În proiectarea algoritmului vom pleca de la forma generală a unei ecuaţii
de gradul al doilea, ax2+bx+c=0, unde a, b şi c sunt numerele reale.

Întrebările la care vom căuta răspuns pentru a construi algoritmul sunt:


- Cum rezolv o ecuaţie de gradul II?
(calculul discriminantului şi al soluţiilor, formule)

- Dar a apare la numitor, deci, dacă a=0?


(rezultă ecuaţie de gradul I)

- Cum rezolv o ecuaţie de gradul I?


(formule)

- Dar b apare la numitor, deci, dacă b=0?


(ecuaţia are soluţii când c=0 şi nu are soluţii în caz contrar)

- Când ecuaţia de gradul II are rădăcini reale sau când sunt


complexe? (discriminantul pozitiv sau negativ)

Am pornit în analiza problemei de la cerinţa acesteia şi am explicat


succesiv noţiunile, în final vom putea da un algoritm bazat pe acest
raţionament, descris în cuvinte:

Algoritm ecuaţie de gradul doi


P1: Se dau a, b, c
P2: Dacă a=0 atunci rezolvă ecuaţia de gradul I,
bx+c=0
stop
altfel P3

12
Curs
P3: delta=b*b-4*c
P4: Dacă delta<0 atunci soluţii complexe
x1= -b + rad5 (- delta) * i
X2= -b - rad (- delta) * i
stop
altfel soluţii reale
x1= -b + rad ( delta)
X2= -b - rad ( delta)
stop
Algoritm ecuaţia de gradul I, bx+c=0
R1: Dacă b=0 atunci P2
altfel o soluţie reală x= -b/a
stop
R2: Dacă c=0 atunci ecuaţia are o infinitate de soluţii
stop
altfel ecuaţia nu are soluţii
stop

Se pune astfel în evidenţă atât modul de extragere a unei subprobleme (ecuaţia de


gradul I) cât şi modul de a gândi pentru diverse situaţii în ordinea logică a rezolvării
problemei.

Exerciţiu.

Rezolvaţi folosind algoritmul de mai sus ecuaţiile de gradul doi care au următorii
coeficienţi:
A = 1, b= -2, c= 1
A = 0, b= 4, c= -12
A = 0, b= 0, c= 3
Există şi alte situaţii (date de intrare) ce parcurg secvenţe de paşi diferite de cele
parcurse pentru rezolvarea cazurilor de mai sus?

Proiectarea ascendentă, numită bottom-up (de jos în sus) presupunerea


cunoaşterea elementelor de bază ale unui algoritm sau subalgoritm şi stabilirea unor
principii de asamblare a acestora încă de la punerea problemei. Acest mod de
proiectare a algoritmilor presupune cunoaşterea preliminară a problemei şi necesită
doar crearea algoritmului de asamblare a componentelor în vederea rezolvării acesteia.
Modelul de proiectare bottom-up este un model descriptiv, axiomatic, şi se bazează
pe elemente cunoscute, definite. Acest mod de abordare permite lucrul în echipă
eliminând în mare măsură erorile de programare pentru fiecare subproblemă în parte.
Elementele dificile apar doar în faza de legare a subproblemelor.
Exemplul 2:

Să se calculeze cea mai mică valoare numerică din n valori date.

Ştim că min (a,b)=(a+b – |a-b|)/2. Calculând succesiv minimul dintre un


element şi minimul dintre cele anterioare lui vom avea în final minimul
dintre cele n valori numerice date. Iniţial vom considera primul element
ca fiind cel mai mic.
Pentru n=7 şi valorile 34, -12, 78, 0, -13, 45, 12 avem:
min = 34
min (34, -12) = -12
min (-12, 78) = -12, ş. a. m. d. min ( -13, 12) = -13

Exerciţiu.

5
rad (x) este funcţia corespunzătoare radicalului de ordin 2 din matematică.

13
Bazele algoritmilor
Aceeaşi formulă se poate aplica grupând altfel cele n numere. Găsiţi o altă
modalitate de a găsi elementul maxim.

Proiectarea algoritmilor este o etapă esenţială în rezolvarea unei probleme, de


aceea dezvoltarea permanentă a modalităţilor de descriere a algoritmilor a determinat
descoperirea unor metode specifice de rezolvare. Aceste metode încearcă să
optimizeze timpii în care se obţine rezultatul, numărul maxim de paşi şi să ofere un
model matematic foarte apropiat de soluţiile optime. Despre aceste metode vom vorbi
în capitolul destinat metodelor şi tehnicilor de elaborare a algoritmilor.

2.2.Programarea structurată. Programarea modulară. Programarea


orientată-obiect.
Principiile programării structurate au fost introduse în 1965 de către E.W.
Dijkstra şi C. A. R. Hoare, care au stabilit reguli stricte în descrierea algoritmilor în
scopul clarificării descrierii, creşterii eficienţei şi lizibilităţii acestora. Elementele de
bază în programarea structurată se bazează pe organizarea unui algoritm pornind de la
un singur punct numit START, descrierea paşilor utilizând doar trei tipuri de
organizare a acestora (secvenţiali, alternativi sau repetitivi) şi încheierea algoritmului
într-un singur punct numit STOP.
Teorema lui C. Böhm şi T.C. Jacopini, cunoscută sub numele de “Teorema de
structură” sau “Teorema fundamentală a programării structurate”, fundamentează
matematic [BIB12] principiul prin care:

Orice algoritm poate fi descris folosind doar trei tipuri de structuri:


- Liniare sau secvenţiale,
- Alternative;
- Repetitive,
numit algoritm structurat. De asemenea, orice algoritm nestructurat, prin
adăugarea sau eliminarea unor instrucţiuni, este echivalent cu un algoritm
structurat.
Descrierea algoritmilor în cadrul programării structurate6 se poate realiza prin
diverse modalităţi:
a) schemele logice presupun reprezentarea în mod grafic a paşilor algoritmului,
prin figuri geometrice care să permită o viziune clară, de ansamblu a algoritmului.
Acest mod de descriere prezintă dezavantaje la algoritmi amplii, deoarece devine
încărcat.
b) pseudocod este un limbaj apropiat de limbajul natural, descris de regulă în
limba cea mai apropiată utilizatorului. Descrierea în pseudocod permite o retranscriere
uşoară în diverse limbaje de programare, o exprimare independentă de particularităţile
de limbaj de programare. Este cel mai frecvent utilizat în descrierile generale ale
metodelor şi algoritmilor clasici.
c) limbajele de programare descriu algoritmii folosind un limbaj specific, cu o
sintaxă şi semantică bine definite, cu particularităţi specifice datelor pe care le
prelucrează şi cu unii subalgoritmi “prefabricaţi”. Programatorul va putea alege,
pentru un anumit algoritm, cel mai potrivit limbaj de programare pentru implementare.
Alegerea se face în funcţie de datele algoritmului, de facilităţile oferite de limbaj
precum şi de adaptabilitatea limbajului la tipul problemei.
Programarea structurată este foarte eficientă în rezolvarea problemelor
elementare. Problemele ample necesită împărţirea în subprobleme, subalgoritmi, care,
pe de o parte să poată exista independent, iar pe de altă parte să poată realiza legături
între ele (ei). Un astfel de subalgoritm este caracterizat de două componente de bază:
6
Conceptul de programare structurată este privit de diverşi autori sub diverse
aspecte: Knuth D. consideră programarea structurată ca fiind un mijloc de a
face produsele program mai uşor de citit, mulţi autori considera acest tip de
programare ca fiind programarea top-down; Schach o consideră ca
programarea fără salturi (GOTO)

14
Curs
algoritmul propriu zis şi datele de legătură numite parametrii (argumente). Parametrii
permit transmiterea datelor între subalgoritmi. Un subalgoritm împreună cu parametrii
săi se numeşte modul sau subprogram.
Principiul care are la bază utilizarea modulelor în descrierea unui algoritm se
numeşte programarea modulară. Acest principiu prezintă numeroase avantaje:
- reduce complexitatea problemei prin descompunerea în probleme mai simple;
- măreşte eficienţa în depistarea eventualelor erori;
- portabilitatea modulelor;
- eficienţa lucrului în echipă;
- testarea uşoară şi posibilitatea înlocuirii modulelor;
Programarea structurată şi programarea modulară se utilizează, de regulă,
împreună cu principiul de proiectare descendentă a programelor. La baza realizării
algoritmului stau datele ca entităţi de prelucrat şi paşii, funcţiile ce trebuie aplicate
acestora.
Programarea orientată-obiect permite înglobarea datelor şi a elementelor de
prelucrarea a acestora într-o singură entitate numită obiect. Acest obiect devine un
element de bază al unei “construcţii” ulterioare prin relaţiile de moştenire şi
polimorfism pe care acestea le au. Această temă nu reprezintă subiectul cursului de
faţă.
Descrierile următoare se referă la programarea structurată şi modulară, în
general, bazate pe principiul de proiectare top-down. În acest sens cele două elemente
de bază ale unui algoritm, datele şi instrucţiunile pot îmbrăca diverse forme de
organizare, reprezentare sau descriere.

2.3.Moduri de organizare şi reprezentare a datelor


În general se vorbeşte despre prelucrarea informaţiilor cu ajutorul calculatorului.
În realitate, calculatoarele prelucrează aceste informaţii sub o formă concretă,
codificată, numită dată sau date. Din aceste considerente calculatoarele se definesc de
fapt ca fiind sisteme de prelucrare a datelor.
Datele reprezintă elemente, mărimi, relaţii care servesc ca punct de plecare în
cercetarea unei probleme sau pentru a trage o concluzie, pentru a rezolva o problemă.
Din punct de vedere al algoritmilor datele îmbracă o formă foarte clară, precisă,
materializată prin tipul, modul de structurare, modul de reprezentare (de codificare) şi
natura acestora.
Data reprezintă valoarea unei informaţii utilizată ca element de raţionament,
discuţie sau calcul.
Din aceste puncte de vedere clasificăm datele după:

2.3.1. Tipul datelor

a) Date numerice; totalitatea datelor ce pot fi reprezentate prin numere reale


sau combinaţii ale acestora.
Exemplul 3:
- 145, -45.78, 0,
- un număr complex z=a+bi se poate reprezenta printr-o pereche
( a, b) ∈ R × R
deci numărul complex 1-i se reprezintă sub forma (1, -1)
- 2 se poate reprezenta aproximativ prin 1,41421356237309 cu
eroare de 10-15.

b) Date alfanumerice; datele ce pot fi reprezentate prin succesiuni de caractere


(litere, cifre, simboluri) cuprinse între două caractere “ (ghilimele) sau ‘
(apostrof).
Exemplul 4:

15
Bazele algoritmilor
- ‘Mihai Eminescu’
- “GEO1867-4”.

c) Date logice; care reprezintă o valoare booleană de adevăr sau fals (true sau
false).
Exemplul 5:
- x>7, este o expresie logică adevărată pentru valorile lui x mai mari
decât 7 şi falsă în rest;
- faptul că ‘Ion’ face parte sau nu din grupul de persoane (‘Ana’,
‘Vasile’, ‘Petre’, ‘Maria’) îl vom reprezenta printr-o mărime de tip logic,
COD, care are valoarea de FALS în această situaţie.
- (x >8) and (x<10) este o expresie logică, adevărată pentru valori ale
lui x din intervalul deschis (8, 10).

Exerciţiu.
Daţi câte un exemplu din fiecare tip de date.

2.3.2. Organizarea datelor.

a) Date simple; care se referă la un anumit moment la o singură valoare, de un


anumit tip. Variabilele utilizate în algoritmul de rezolvare a ecuaţiei de
gradul doi, a, b, c, delta sunt variabile simple.

b) Date compuse (structurate); conţin la un moment dat mai multe valori de


acelaşi tip sau de tipuri diferite.
Pentru a reprezenta soluţiile complexe ale ecuaţiei de gradul doi din Exemplul
1 va trebui să folosim un tip de date structurat, respectiv x1 şi x2 sunt perechi de
forma (real, imaginar) unde datele real şi imaginar sunt simple şi conţin o
valoare, număr real.

Datele compuse (structurate) pe care le utilizăm în scr ierea algoritmilor se


împart în funcţie de tipul legăturilor dintre ele şi respectiv de tipul datelor pe care
le conţin.

I. Din punct de vedere al tipului legăturilor distingem 4 mari categorii:


- structură de tip mulţime;
- structură liniară;
- arborescentă;
- structură de tip graf.

Tip structură Tip legătură între elemente


Mulţime Nici o legătură
Liniară Legătură unu la unu
Arbore Legătură unu – la - mai multe
Graf sau reţea Legătură mai multe – la - mai multe

Pentru a înţelege mai bine aceste tipuri vom da câteva definiţii care vor fi utile şi
la definirea ulterioară a altor tipuri sau categorii de date.
Definiţie:
O mulţime D, înzestrată cu o relaţie R, care satisface proprietăţile:
1. a R a, pentru orice a din D (reflexivitate)
2. Dacă a R b şi b R a atunci a=b, pentru a,b din D (antisimetrie)
3. Dacă a R b şi b R c atunci a R c, pentru a, b, c din D (tranzitivitate)
se spune că este parţial ordonată în raport cu R.

16
Curs
Definiţie:
Mulţimea D este total ordonată dacă pentru orice a, b din R avem fie a R b, fie b
R a.

Definiţie:
O relaţie R care satisface axiomele 1-3 se numeşte relaţie de ordine pe D.
Exemple:
Cele mai des întâlnite relaţii de ordine sunt:
- „<=” (mai mic egal) relaţia de ordine totală utilizată pentru valori numerice
din mulţimea numerelor reale.
- Ordinea alfabetică a unui set de caractere, de regulă alfabetul unei limbi.
(ordonarea acestor caractere se datorează codificării acestora prin valori
numerice de la 0 la 255, deci pentru calculator ele sunt văzute ca numere)
- Ordonarea lexicografică a şirurilor de caractere (a cuvintelor) din vocabularul
unei limbi. Această ordine este de fapt ordinea cuvintelor din
dicţionar(cuvântul cosmos este „mai mic” decât cot datorită egalităţii
secvenţelor „co” iar cel de al treilea caracter „s” este mai mic decât „t”.
(Atenţie, nu contează lungimea secvenţei de caractere!).
- Pentru un graf orientat, unde x şi y sunt două noduri, relaţia R este definită
astfel: x R y daca (x, y) este un arc (o muchie) de la x la y în graful dat.
Definiţie:
Spunem că o mulţime D este liniară dacă:

* D este vidă
sau
** D conţine un singur element
sau

*** Sunt îndeplinite condiţiile:


1. D este finită;
2. Există un unic element numit primul;
3. Există un unic element numit ultimul;
4. Pentru orice element x ∈ D, x ≠ ultimul există succ(x), succesor al lui x
5. Pentru orice element x ∈ D, x ≠ primul există pred(x), predecesor lui x

Mulţimile, împreună cu relaţiile de ordine, determină utilizarea diverselor tipuri


de date în vederea reprezentării acestora cu ajutorul calculatorului. În fiecare caz în
parte alegerea tipurilor de date utilizate în elaborarea algoritmilor trebuie să ţină cont
de structura şi de modul de acces la fiecare din elementele unei date structurate. În
acest sens trebuie să ştim ce operaţii putem efectua asupra datelor. Prin urmare este
necesar ca la definirea structurii unor date să se definească şi clasa de operaţii
specifice acestora. Pentru tipurile de date structurate prezentate în continuare vom
defini atât structura cât şi operaţiile necesare, iar asupra unora dintre acestea vom
reveni în capitole speciale.
II. Din punct de vedere al tipului datelor pe care le conţin, chiar dacă vom face
precizarea tipului structurii şi din punct de vedere al legăturilor, distingem următoarele
categorii:

2.3.2.1. Date structurate care conţin mărimi de acelaşi tip sau date structurate
omogene.
Principalele modele de organizare a datelor structurate care conţin mărimi de
acelaşi tip sunt:

Tablou; prin tablou n-dimensional vom înţelege o structură de date în care se pot
păstra n secvenţe a câte ni, i =1, n , date de acelaşi tip.
Notaţia matematică este:

17
Bazele algoritmilor
A(n1 ,n2 ,… ,nn-1 ,nn),
unde n şi ni, i =1, n sunt numere naturale finite,
A este numele tabloului,
ni sunt indici,
iar
A(i1 ,i2 ,… ,in-1 ,in), i j =1, n j , j =1, n ,
este un element al tabloului.
Exemplul 6:
1) Tablourile cu o singură dimensiune se numesc şiruri (vectori) cu n
componente.
Înălţimile a n persoane dintr-un grup se pot reprezenta printr-un şir
x(i), i =1, n ,
unde x(i) reprezintă înălţimea persoanei i din grup.
2) Tablourile bidimensionale se numesc matrice. Primul indice este
indicele de linie, iar al doilea cel de coloană. De fapt o matrice este un
şir de şiruri.
Notele a n persoane la m examene pot fi organizate ca o matrice cu n
linii şi m coloane sub forma:

Examen(1) Examen(2) … Examen(m)


Persoana(1) 8 9 5
Persoana(2) 7 4 10

Persoana(n) 10 8 9

Notăm cu
T(i,j), i =1, n , j =1, m ,
matricea.
T(1,2)=9 este nota persoanei 1 la examenul 2.

3) Tablourile n-dimensionale au imaginea spaţială mai dificilă. Dacă cele


3-dimensionale pot fi asemănate cu un paralelipiped format din n x m x
p cuburi identice, atunci cele 4-dimensionale pot fi imaginate ca o
matrice de matrice sau ca un şir de paralelipipede.

Exerciţiu.
Daţi un exemplu de tablou 4 – dimensional şi găsiţi o modalitate de reprezentare
în plan şi respectiv ca dată structurată.

Lista liniară, este un şir de n ≥ 0 noduri x[1], x[2], …, x[n], a cărui


proprietăţi structurale esenţiale se rezumă la poziţia relativă a elementelor aşa cum
apar ele, la rând. Lista liniară este un tip de structură unu – la - unu şi reprezintă un
mod de organizare a elementelor unei mulţimi, asemănătoare şirurilor, în care există o
ordine bine stabilită, distingem două noduri numite primul (bază), x[1], respectiv
ultimul (vârf), x[n], şi faptul că dacă 1<k<n, nodul al k-lea, x[k], este precedat de x[k-
1] şi urmat de x[k+1]. Printre operaţiile pe care le putem efectua asupra listelor liniare
se numără:
i) Accesul la nodul al k-lea pentru a examina şi /sau a modifica valorile pe
care le conţine.
ii) Inserarea unui nod nou imediat înaintea sau imediat după nodul al k-lea.
iii) Ştergerea nodului k.
iv) Combinarea a două sau mai multe liste liniare în una singură, operaţii
numite:
- concatenare; ultimul element al primei liste este urmat de primul elemente al
celei de a doua.

18
Curs
- interclasare; elementele listelor iniţiale se plasează în noua listă în aceeaşi
ordine, dar nu neapărat succesive.
- inserare; poziţiei k a unei liste îi urmează primul element al celei de a doua,
iar succesorul ultimului element din cea de a doua listă este elementul de pe poziţia
k+1 al primei liste,
v) Partiţionarea unei liste liniare în două sau mai multe liste.
vi) Copierea unei liste liniare.
vii) Determinarea numărului de noduri dintr-o listă.
viii) Sortarea nodurilor dintr-o listă în ordine crescătoare pe baza anumitor
valori (câmpuri, chei) ale nodurilor.
ix) Căutarea în listă a unui nod cu o valoare particulară.
Un exemplu de listă liniară este problema aşezării vagoanelor într-o garnitură de
tren. Prezentarea listelor şi exemplificarea acestora se va realiza în detaliu în capitolul,
Structuri de date.

2.3.2.2. Date structurate care conţin mărimi de diverse tipuri

Articol; permite reprezentarea datelor structurate care conţin tipuri diferite. Un


articol conţine mai multe câmpuri, fiecare câmp are propriul său tip şi propria sa
structură. Acest mod de structurare a datelor se utilizează cel mai frecvent în
prelucrarea volumelor mari de date, a datelor economice.
Exemplul 7:
Gestiunea mărfurilor dintr-un magazin se realizează pe baza unor date
care conţin: denumirea produsului, cantitatea, preţul unitar, codul de
bară. Aceste date care nume şi tipuri diferite le numim câmpurile
articolului. Articolul corespunzător unui produs îl vom numi PRODUS, iar
câmpurile fiecăruia sunt DEN, CANT, PRET, COD. La un moment dat
ne referim la denumirea unui produs prin PRODUS.DEN. Pentru un şir
de produse referinţa este PRODUS(i).DEN, adică denumirea produsului
de pe poziţia i.

Tip Abstract de Date; permite definirea abstractă a unei colecţie de date şi a


operaţiilor cu care se prelucrează aceste date. Această temă va fi subiectul unui curs
următor.

2.3.3. Modul de reprezentare.

Informaţia reprezentată cu ajutorul calculatorului ia forma datelor prin


intermediul unui sistem de codificare, de reprezentare în memoria sistemelor de
calcul. Dacă de exemplu dorim să reprezentăm pe un octet (8 bits) un număr cu semn,
vom avea la dispoziţie 7 cifre binare şi o primă cifră ca semn, respectiv 0 pentru + şi 1
pentru -. În acest fel valoarea maximă ce poate fi reprezentată este echivalentul lui
1111111(2)=127. Alocând mai mulţi octeţi pentru reprezentarea informaţiei sau
schimbând modul de reprezentare (pentru memorarea caracterelor se foloseşte un octet
pentru un caracter, codul fiecărui caracter fiind codul ASCI, cu valori cuprinse între
33 şi 255) se pot memora diverse valori ale datelor.
În funcţie de modul în care se gestionează şi se reprezintă datele în memorie
distingem două mari categorii de date:
- statice
- dinamice

a) Statice; pentru păstrarea şi gestionarea datelor statice se foloseşte un spaţiu, o


zonă de memorie (în terminologia limbajelor), numită locaţie de memorie, bine
precizată, rezervată numai acestor informaţii. Acest mod de reprezentare se numeşte
alocare statică. Pentru a păstra datele din tabloul bidimensional din Exemplul 5, pct.

19
Bazele algoritmilor
2) sunt necesare n x m locaţii identice. Locaţiile de memorie au diverse dimensiuni, de
regulă multipli de octet, în funcţie de valoarea, tipul şi mărimea datelor, precum şi în
funcţie de limbajul de programare utilizat. Alocarea statică prezintă avantaje pentru
situaţiile când datele sunt puţine şi pot fi păstrate în totalitatea lor. Ea este însă
dezavantajoasă la un volum mare de date, atât de intrare cât şi intermediare, necesare
în rezolvarea algoritmului.

b) Dinamice; păstrarea datelor dinamice se face în locaţii nerezervate anterior. În


funcţie de necesarul de locaţii, datele dinamice pot aloca o nouă zonă sau disponibiliza
o zonă folosită, cea din urmă devenind liberă. Modul de reprezentare se numeşte
alocare dinamică. Structurile cele mai des folosite în alocarea dinamică sunt listele.
De exemplu, pentru gestiunea vagoanelor care intră şi ies timp de o zi, într-o gară, pe
cele n linii, se va păstra la un moment dat doar informaţia referitoare la vagoanele
aflate în gară în acel moment. Asupra acestor aspecte vom reveni în capitolul V.

2.3.4. Natura datelor.


În elaborarea algoritmilor programatorul trebuie să decidă, în funcţie de valorile
datelor de intrare şi de ieşire, dacă valorile se modifică sau rămân aceleaşi în timpul
parcurgerii paşilor algoritmului, ori sunt folosite în calcule. Din acest punct de vedere
distingem în funcţie de natura datelor:
- constante,
- variabile,
- construcţii folosind operaţii şi date, numite expresii.
Constante = entităţi de date care nu îşi modifică valoarea pe parcursul
algoritmului.
În funcţie de tipul acestora vom întâlni:
- constante numerice reprezentate ca numere reale sau cu exponent sub forma:
34, -78, 89.34, -0.23, 0.345E+2 (34.5);
- constante alfanumerice (şiruri de caractere) delimitate de simbolul apostrof (‘)
sau („) sub forma: ‘nea Ion’ ‘Daţi valoare pentru x=’
- constantele logice, true şi false sau 1 şi 0 care corespund valorilor booleene
adevărat şi respectiv fals

Variabile = entităţi care la un moment dat păstrează o valoare unică, ce poate fi


identificată printr-un nume, numit identificator, şi care poate să-şi modifice această
valoare pe parcursul algoritmului. Identificatorul unei variabile este o succesiune de
litere şi cifre, primul caracter fiind obligatoriu literă.
Imaginea cea mai apropiată de noţiunea de variabilă este cea a unei găleţi cu
lichide, pe care să o numim GĂLĂ. Iniţial, de regulă, GĂLĂ e goală, deci variabila nu
are nici o valoare. Dacă turnăm 3L de lapte atunci GĂLĂ are valoarea 3L. Dacă mai
turnăm 5L atunci GĂLĂ are valoarea 8L. Atenţie când în GĂLĂ doriţi să puneţi vin!
Ce se întâmplă? Deci tipul unei variabile nu se modifică ci doar valoarea ei!
În funcţie de tipul, structura şi reprezentarea datelor, variabilele se împart după
mai multe criterii:
a. după valoarea pe care o iau:
- numerice,
- alfanumerice
- logice,
b. după numărul valorilor pe care le pot păstra la un moment dat:
- simple; conţin o singură valoare de un anumit tip
- structurate; conţin mai multe valori fie de acelaşi tip fie de tipuri diferite.
c. după modul de reprezentare în memorie
- statice
- dinamice.

20
Curs
Exemple:
a) x=4, x este o variabilă numerică, simplă
b) nume=”POP”, nume este o variabilă simplă de tip alfanumeric
c) y[i,j], este un element al unei variabile structurate de tip matrice
d) un articol student care conţine câmpurile (nume, adresă, tel) poate fi
identificat prin student.nume şi atunci ne referim la numele studentului
curent
Observaţie!
Valorile pe care le pot lua variabilele aparţin unei mulţimi D, numită domeniul
variabilei, aceste valori au anumite semnificaţii, astfel putem concluziona că o
variabilă are următoarele caracteristici:
(identificator, domeniu, valoare, semnificaţie).
De aici putem constata că nu putem folosi variabile cu acelaşi nume şi
semnificaţii diferite, unei variabile nu putem să-i atribuim simultan două sau mai
multe valori şi trebuie să precizăm foarte clar domeniul valorilor variabilei încă de la
început.
Asupra variabilelor se pot efectua diverse operaţii. Pe lângă operaţiile specifice
tipurilor datelor, ne referim aici la operaţiile elementare cu valori numerice (adunare,
înmulţire, etc.), cu cele logice (operatori de relaţie, operatori logici) cele mai
importante operaţii pe care le efectuăm asupra variabilele sunt:
- citirea valorilor variabilelor; această operaţie presupune preluarea unei
valori pentru o variabilă prin intermediul unor dispozitive de intrare cum ar fi
tastatura, fişiere de pe disc, senzori, etc.
- scrierea valorilor variabilelor; această operaţie presupune depunerea valorii
unei variabile prin intermediul unor dispozitive de ieşire la ecranul
monitorului, la imprimantă, într-un fişiere pe disc, la un dispozitiv de redare,
etc.
- atribuirea unei noi valori unei variabile; această operaţie presupune
pierderea valorii iniţiale a unei variabile şi înlocuirea sa cu noua valoare
calculată. Vom întâlni în informatică, foarte des, expresii de forma x=x+1,
ceea ce din punct de vedere matematic este incorect, dar în sensul operaţiei
de atribuire vom înţelege că vechea valoare a lui x creşte cu o unitate. Astfel
dacă înaintea executării acestei atribuiri x avea valoarea 2, după atribuire el
va avea valoarea 3.
În continuare vom descrie principalele operaţii specifice diverselor tipuri de
variabile şi constante, şi modul de construcţie corectă a expresiilor utilizate în
elaborarea algoritmilor.
Expresie = o succesiune validă de operanzi şi operatori, eventual delimitaţi prin
paranteze rotunde care specifică ordinea operaţiilor. Cu toate că definiţia, din punct de
vedere matematic nu este riguroasă, o acceptăm pentru simplitate.
Operanzii sunt constante, variabile sau alte expresii valide.
Operatorii sunt operaţiile permise asupra operanzilor în funcţie de tipul lor,
structura lor şi modul lor de reprezentare. Pentru operatori se defineşte o ordine a
priorităţii. Definim în continuare operatorii pentru câteva categorii de date utilizate
frecvent în algoritmică.
Operatorii se împart în două mari categorii în funcţie de numărul de operanzi
asupra cărora operează şi respectiv în funcţie de tipul acestora.

În funcţie de numărul operanzilor:


- operatori unari,
(Exemple: -5, |a|, not)
- operatori binari
(Exemple: a+b, x>6)
- operatori n-ari
(Exemplu: min(4,7,3,2,7) este 2).

În funcţie de tipul operanzilor:

21
Bazele algoritmilor

Operatori aritmetici; operează cu valori numerice:


operatori binari:
+, adunare
-, diferenţa
*, înmulţire
/, împărţire
div (câtul împărţirii întregi, 17 div 3=5),
mod (restul împărţirii întregi, 17 mod 3=2);
operatori unari:
- abs(x) (modulul lui x, abs(-3)=3),
- int(x) (partea întreagă a lui x, int(-3.23)=-4),
- frac(x) (partea fracţionară a lui x, frac(-3.23)=0.77).

Operatori logici; operează asupra valorilor booleene:


- AND (A and B este adevărat dacă şi numai dacă A este adevărat şi B este
adevărat).
- OR (A or B este fals dacă şi numai dacă A este fals şi B este fals).
- NOT ( not A este adevărat dacă şi numai dacă A este fals)

Operatori relaţionali; operează asupra datelor care permit o relaţie de ordine şi


sunt reprezentaţi prin simbolurile: >, <, >=, <=, <> sau #(diferit), = (egal);
Ordinea efectuări operaţiilor este dată în următorul tabel:

Prioritate Operatori
0 NOT, +, -, abs, int, frac – operatori unari
1 *, /,div , mod, AND – operatori multiplicativi
2 +, -, OR – operatori aditivi
3 >, <, >=, <=, <>,# , = - operatori relaţionali

Observaţie: Pentru eventualele operaţii definite ulterior se va preciza prioritatea


şi operatorii asupra cărora operează. Limbajele de programare folosite la transcrierea
algoritmilor permit o gamă specifică de operatori, de aceea pot să apară operatori noi
sau să existe operatori echivalenţi cu cei definiţi mai sus.
Exemplul 8:
1) Identificatori:
x, A(i, j), val2, t1ri,
incorect 453A, !%2

2) Dacă x este variabilă numerică întreagă, atunci expresia


(x+3)-(x mod 2)/2
este corectă, valoarea ei este numerică reală.

3) ‘Pop’+’Vasile’ este o expresie de tip caracter, are ca valoare


‘PopVasile’. Operatorul “+” se numeşte operator de concatenare a
şirurilor de caractere.

4) Dacă x = 3.5 şi cuv = ‘amarui’ atunci expresia


(X<5) and (‘amnar’<cuv)
are valoarea logică FALS, deoarece, ţinând cont de ordinea dată de
paranteze x<5 este ADEVARAT, iar ‘amnar’<cuv este FALS (ordinea
lexicografică).
Expresia
X<5 and ‘amnar’<cuv
Este incorectă deoarece ordinea operaţiilor presupune ca prima operaţie
să fie: 5 and ‘amnar’, operaţie care nu are sens (operatorul and nu se

22
Curs
poate aplica operanzilor numerici sau alfanumerici).

5) Pentru P şi Q operanzi logici, expresiile


not (P or Q) = not P and not Q
not (P and Q) = not P or not Q,
sunt adevărate pentru orice valori logice ale lui P şi Q. (relaţiile lui
DeMorgan).

2.4.Subalgoritmi

Noţiunea de subalgoritm
Când un anumit algoritm trebuie efectuat de mai multe ori în diverse locuri ale
unui probleme, respectiv este necesar în probleme diferite sau o problemă este prea
amplă şi se poate împărţi în subprobleme, este de dorit ca acesta să fie codificat o
singură dată şi utilizat de câte ori avem nevoie.
Secvenţa de paşi numită subrutină sau subalgoritm poate fi plasată o singură
dată şi apelată prin intermediul unor procedee specifice ori de câte ori este nevoie.
Se constată astfel că orice problemă poate apare ca o subproblemă a unei
probleme mai complexe. Algoritmul de rezolvare a acestei subprobleme îl vom numi
subalgoritm.
Pentru utilizarea unui subalgoritm vom avea nevoie de parcurgerea a trei etape
importante:
1. Elaborarea subalgoritmului şi identificarea sa printr-un nume.
2. Definirea unei liste de variabile ce constituie datele de intrare şi
respectiv datele de ieşire ale subalgoritmului.
3. Apelul subalgoritmului prin intermediul celor două elemente
definite anterior.
Exemplu:
Să urmărim Exemplul 1, algoritmul de rezolvare a ecuaţiei de gradul al doilea.
Algoritmul pentru rezolvarea problemei cuprinde un subalgoritm pentru rezolvarea
ecuaţiei de gradul I de forma bx+c=0.
Numele algoritmului principal este:
Algoritm ecuaţie de gradul doi
Numele subalgoritmului:
Algoritm ecuaţia de gradul I, bx+c=0
Apelul subalgoritmului se face o singură dată, când a=0 şi transmite ca date de
intrare variabilele b şi c, returnează ca rezultat fie x, fie un mesaj corespunzător. Acest
exemplu nu este suficient de edificator pentru a justifica utilizarea subalgoritmilor
deoarece, el se apelează o singură dată. Cu toate acestea dacă problema ecuaţiei de
gradul I era rezolvată anterior sau de un alt programator ea poate fi utilizată în
algoritmul nostru fără a rescrie paşii algoritmului.
Forma sub care au fost descrise atât algoritmul cât şi subalgoritmul de mai sus nu
este o formă standardizată ci una naturală, mai puţin convenţională şi pe înţelesul
tuturor. În acest sens, de-a lungul timpului s-a simţit nevoia unei standardizări. Aşa au
apărut diverse metode de descriere a algoritmilor bazate pe reguli stricte, independente
de limbajul de programare, care permit oricărui programator să înţeleagă mai uşor
paşii din cadrul oricărui algoritm.
Descrierea subalgoritmilor va fi prezentată în secţiunea ce urmează, împreună cu
modalităţile de descriere a paşilor unui algoritm.

Observaţie:
Câteva observaţii privind modul de abordare şi elaborare a subalgoritmilor
trebuie precizate înainte de a trece mai departe:
- de regulă, un subalgoritm nu realizează operaţii de citire / scriere a datelor;
- conceperea unui subalgoritm este independentă de contextul general, singura
legătură cu exteriorul fiind variabilele de intrare şi ieşire;
- scrie cât mai mulţi subalgoritmi atunci când o problemă este mai vastă;

23
Bazele algoritmilor
- verifică fiecare subalgoritm în parte, independent, indiferent de locul sau
rolul pe care acesta îl joacă într-un algoritm mai mare.

2.5.Metode de descriere a algoritmilor


Descrierea algoritmilor presupune reprezentarea datelor şi a paşilor, a
instrucţiunilor, ce trebuiesc parcurse pentru rezolvarea problemei.
Principiile programării structurate impun reguli stricte în ceea ce priveşte
descrierea instrucţiunilor admise pentru fiecare din structurile definite:
o liniară (secvenţială),
o alternativă
o repetitivă.
În continuare ne propunem să dăm utilizatorului cele mai răspândite modalităţi şi
metode de reprezentare generală a algoritmilor şi a subalgoritmilor
Modalităţile cele mai frecvent utilizate în descrierea algoritmilor sunt: limbajul
pseudocod, schemele logice şi limbajele de programare.

2.5.1. Limbajul pseudocod


Are la bază descrierea instrucţiunilor prin cuvinte cheie şi respectarea unei
sintaxe riguroase. Descrierea în limbaj pseudocod a algoritmilor presupune utilizarea
unor propoziţii asemănătoare celor folosite într-o limbă. Aceste propoziţii conţin în
principal „verbe”, cuvinte cheie, care descriu acţiunea ce urmează a fi realizată şi, pe
lângă acestea, cuvinte de legătură sau parametrii, care detaliază acţiunea pasului
respectiv din algoritm. Pe lângă aceste propoziţii standard, se utilizează de regulă
comentarii care însoţesc algoritmul şi care sunt la latitudinea programatorului.
Teorema lui C. Böhm şi T.C. Jacopini ne asigură că cele trei tipuri de structuri:
- liniară sau secvenţială; cu instrucţiunile:
algoritm,
scrie,
citeşte
atribuire “←“,
- alternativă; descrisă de structura
dacă ... atuci ... altfel ... sfdacă
- repetitivă, descrisă de instrucţiunea
CâtTimp ... execută ... sfcâttimp,
permit scrierea oricărui algoritm.

În practică, există structuri repetitive echivalente cu structura CâtTimp, numită şi


structură repetitivă cu condiţie iniţială. Acestea sunt:
Repetă ... până când ...,numită structură repetitivă cu condiţie finală
şi
Pentru var=valinit, valfinală, pas execută ... sfpentru, numită structură
repetitivă cu număr fix de paşi.
Acestea se vor folosi în scrierea algoritmilor în cele ce urmează, iar propoziţiile
1) şi 2), descrise în continuare vor demonstra echivalenţa lor cu structurile standard.

2.5.2.Schema logică
Schema logică reprezintă paşii algoritmului printr-o succesiune de blocuri, legate
între ele prin săgeţi direcţionale. Există un singur bloc de pornire START şi un singur
bloc de oprire STOP. Succesiunea blocurilor este dată de sensul săgeţilor. Fiecare bloc
este specific tipului de structură şi instrucţiunii descrise.
Pentru un set de date de intrare, pornind de la blocul de START există o cale
unică de a parcurge paşii algoritmului până la STOP.
Descriem în continuare modul de definire a secvenţelor unui algoritm în
pseudocod şi schemă logică, comparativ şi ilustrate cu exemple. Pentru fiecare
element nou care apare în descrierea unor instrucţiuni se vor da explicaţii, iar cele deja

24
Curs
întâlnite nu vor mai fi explicate, doar dacă există diferenţe faţă de prezentarea
anterioară.

2.5.3. Descriere comparativă pseudocod / schemă logică

2.5.3.1. Definirea unui algoritm şi a eventualilor parametrii

Pseudocod (P) 7
Modalitatea de descriere a formei generale a unei comenzi sau instrucţiuni pe
care o să o utilizăm în acest curs se numeşte notaţia BNF (Bachus Normal Form),
unde:
{…} reprezintă faptul că secvenţa se poate repeta de oricâte ori, inclusiv niciodată;
[…] secvenţa este opţională, deci poate lipsi;
<identificator> reprezintă numele unei variabile, algoritm, liste, etc. specificate de
către utilizator.
Cuvintele cheie şi simbolurile altele decât cele prezentate mai sus sunt obligatorii şi
aparţin sintaxei instrucţiunii respective, ele fiind scrise îngroşat. Fiecare opţiune care
apare în cadrul descrierii este explicată ulterior.
Astfel definirea unui algoritm sau subalgoritm se face cu:

Algoritm <nume> [ ( { <variabilă>{,<variabilă>}: <tip>} ) ];

<nume> numele algoritmului


<variabilă> este numele unei variabile, poziţia fiecăreia fiind importantă în
listă pentru a putea face legătura, eventual, cu un alt algoritm. Numele variabilelor
sunt separate prin virgulă. Pot exista mai multe variabile de acelaşi tip, respectiv de
tipuri diferite. Toate numele variabilelor trebuie să fie unice. Pentru un subalgoritm
lista acestor variabile se numeşte lista de parametrii şi constituie datele de intrare şi
cele de ieşire ale subalgoritmului.
Variabilele definite la nivelul unui algoritm au efect pe tot parcursul
algoritmului.
<tip> este tipul variabilelor

Schema logică (SL)

Blocul va conţine în interior numele algoritmului şi parametrii corespunzători

2.5.3.2.Declararea constantelor şi variabilelor

(P)
<listavar> : <tip>;
<tip> este tipul variabilei (numeric, caracter, logic, şir, matrice, listă).
<listavar> lista variabilelor de acel tip, separate prin virgulă sub forma
variabilă{,variabilă}.

(SL)
Se specifică la începerea algoritmului în mod similar pseudocod.

7
Pentru simplificarea scrierii vom folosi în continuare doar notaţia prescurtată
din paranteze, respectiv (P) Pseudocod, (SL) Schemă logică.

25
Bazele algoritmilor
2.5.3.3. Structura liniară
(S)
1)Instrucţiunea de atribuire
O variabilă primeşte valoarea calculată a unei expresii.

(P)
<numevar> ← < Expresie>;
<numevar> - numele unei variabile.
<Expresie> – o expresie validă, de acelaşi tip cu variabila <numevar>

(SL)

<numevar>←< Expresie>

(S)
2) Instrucţiuni de citire/scriere

Permit introducerea /afişarea de la /la dispozitivele de intrare /ieşire a valorilor


variabilelor.

(P)
Citeşte <listavar>;
- <listavar> lista variabilelor a căror valori se iau de la dispozitivul de intrare,
separate prin virgulă sub forma variabilă{,variabilă}.

Scrie <listaexpresii>;
- <listaexpresii> lista expresiilor a căror valori se vor afişa la dispozitivul de
ieşire, separate prin virgulă sub forma expresie {, expresie }.

(SL)

citeşte scrie
<listavar> <listaexpresii>

(S)
3)Apelul unui subalgoritm

Permite executarea paşilor unui subalgoritm şi revenirea în algoritm la pasul


următor apelului.
Algoritmul care face apel la un subalgoritm se numeşte apelant, iar
subalgoritmul se numeşte apelat.

(P)
<numealgoritm> [(<parametrii> )];
<numealgoritm> numele algoritmului (subalgoritmului) ce urmează a fi
apelat. Acest algoritm este descris în prealabil.
<parametrii> sunt numele unor variabile sau expresii, separate prin virgulă.
Aceste variabile sau expresii reprezintă datele de intrare şi cele de ieşire ale
subalgoritmului. Ca date de ieşire nu pot figura decât variabile. Lista variabilelor
trebuie să corespundă ca tip şi număr cu parametrii din definiţia algoritmului apelat.

26
Curs
Observaţie:
Numele variabilelor din algoritmul apelat sunt independente de numele
variabilelor din algoritmul apelant, deoarece între cei doi algoritmi se realizează doar
transferul valorilor acestor variabile.
Variabilele utilizate în cadrul unui subalgoritm se numesc variabile locale, ele
există doar la nivelul subalgoritmului.

(SL)

<numealgoritm> [(parametrii)]

2.5.3.4. Structura alternativă


(S)
Instrucţiunea de decizie “Dacă”
În urma evaluării unei expresii logice se execută o secvenţă de instrucţiuni,
S1, pentru valoarea de adevăr şi o altă secvenţă de instrucţiuni, S2, pentru valoarea
fals. După parcurgerea oricărei din cele două ramuri se continuă cu instrucţiunea de
după structură.

(P)
Dacă < ExpresieLogică> atunci
[ <S1>]
[ altfel
<S2> ]
sfDacă

< ExpresieLogică> este obligatoriu o expresie de tip logic.


<S1>, <S2> sunt instrucţiuni sau secvenţe de instrucţiuni.

Observaţie:
Este evident faptul că lipsa ambelor secvenţe posibile determină o structură
alternativă vidă, fără nici un efect, deci cel puţin o ramură va conţine o secvenţă de
instrucţiuni.
Dacă secvenţa S1 lipseşte, nu se foloseşte scrierea structurii folosind ambele
ramuri, respectiv atunci şi altfel ci se procedează la negarea <Expresiei logice>
obţinându-se astfel secvenţa care conţine doar o singură ramură:

Dacă not < ExpresieLogică> atunci

<S2>

sfDacă.

Scrierea pe nivele, cu ordonarea şi alinierea structurilor alternative va face


mult mai uşoară înţelegerea şi verificarea corectitudinii algoritmilor. Urmăriţi cu
atenţie alinierilor şi ordonarea structurilor în exemplele ce urmează.

(SL)

NU DA
< ExpresieLogică>

<S2> <S1>
27
Bazele algoritmilor

2.5.3.5. Structura repetitivă

Instrucţiunea repetitivă “Cât timp”.


Cât timp valoarea unei expresii logice este adevărată se execută o secventă S.
În urma evaluării unei expresii logice se execută o secvenţă de instrucţiuni, S, pentru
valoarea de adevăr şi se repetă această secvenţă atâta timp cât expresia este adevărată.
La fiecare revenire se reevaluează expresia logică. Când expresia logică devine falsă
se trece la prima instrucţiune de după structură.
Acest tip de structură se numeşte:
Structură repetitivă cu condiţie iniţială.

(P)
Cât timp < ExpresieLogică> execută

<S>

sfCât timp

< ExpresieLogică> este obligatoriu o expresie de tip logic.


<S> este o instrucţiune sau o secvenţă de instrucţiuni.
Observaţii.
1) În urma evaluării expresiei logice există posibilitatea ca secvenţa S să nu se execute
niciodată.
2) Atenţie la situaţia în care secvenţa S nu modifică valoarea expresiei logice. În acest
caz, dacă expresia este adevărată tot timpul, se generează aşa numitul “ciclu infinit” şi
algoritmul nu este corect.

(SL)

DA
< ExpresieLogică>

NU <S>

Instrucţiunea repetitivă “Repetă”.


În urma execuţiei unei secvenţe de instrucţiuni <S> se evaluează expresia
logică. Pentru valoarea de fals a expresiei se repetă secvenţa <S>, după care se
reevaluează expresia logică. Secvenţa se repetă până când expresia devine adevărată şi
se trece la prima instrucţiune de după structură.
Acest tip de structură se numeşte:

Structură repetitivă cu condiţie finală.

(P)
Repetă
<S>
până când < ExpresieLogică>

28
Curs

< ExpresieLogică> este obligatoriu o expresie de tip logic.


<S> este o instrucţiune sau o secvenţă de instrucţiuni.

Observaţii.
1) Secvenţa <S> se execută cel puţin o dată.
2) Atenţie la valoarea logică a expresiei pentru
care se părăseşte structura! Dacă la instrucţiunea <S>
cât timp părăsirea structurii se realizează atunci
când valoarea de adevăr a expresiei logice este
fals, structura repetă se încheie pentru valoarea
de adevăr a expresiei logice true.
NU
< ExpresieLogică>
(SL)
Instrucţiunea repetitivă “Pentru”
Execută secvenţa de instrucţiuni <S> DA
pentru fiecare valoare a <contor> începând cu
valoarea <ini>, până la valoarea <fin>, cu pasul <pas>. Structura “pentru” presupune
patru etape cu următoarea ordine:
1) iniţializarea
2) verificarea
3) secvenţa
4) incrementarea sau decrementarea
Verificarea valorii contorului se face înaintea executării secvenţei <S> pentru
fiecare parcurgere a structurii.
Structura se construieşte folosind “Cât timp” şi se numeşte:
Structură repetitivă cu număr cunoscut de paşi.

(P)
Pentru <contor> = <ini>, <fin>, [<pas>] execută
<S>
sfPentru

<contor> este o variabilă care permite evidenţierea numărului de paşi ce


doresc a fi efectuaţi. Tipul variabilei trebuie să permită o relaţie de ordine;
<ini> este o expresie cu a cărei valoare se iniţializează variabila <contor>;
<fin> este o expresie care reprezintă valoarea finală a variabilei <contor> în
cadrul structurii repetitive. În funcţie de <pas>, <fin> poate fi mai mare decât <ini>
sau mai mică, corespunzător ordinii dorite.
<pas> este o expresie care reprezintă valorile cu care se incrementează
(creşte) sau se decrementează (descreşte) valoarea variabilei <contor>.
Atenţie!
Implementările în diverse limbaje de programare a structurii “pentru” pot să difere,
mai ales în ceea ce priveşte <contor> şi <pas>.

(SL)

<contor> ← <ini>

DA
< contor> <= <fin>

NU <S>

<contor> ← < 29
contor > + <pas>
Bazele algoritmilor

2.5.3.6. Sfârşitul algoritmului

(P)
Stop
Există o singură instrucţiune care marchează sfârşitul algoritmului

(SL)

STOP

Înţelegerea utilizării acestor instrucţiuni va fi mult mai simplă dacă încercaţi să


parcurgeţi următoarele exemple de algoritmi. Înainte de a vedea soluţia încercaţi să
elaboraţi propria dumneavoastră soluţie.

2.6. Exemple folosind structuri alternative


Exemplul 9:
Prezintă algoritmi în pseudocod şi schemă logică pentru probleme
rezolvate folosind un anumit tip de structură sau combinaţii ale acestora.
Problema 1.
Mihai, Gigel şi Vasile au înălţimile exprimate în cm. Aflaţi care este
înălţimea cea mai mică la care poate fi plasat tavanul unei încăperi
astfel încât toţi să poată sta în picioare.

Soluţie
Care sunt datele problemei?
Înălţimile exprimate în cm. Fie variabilele a, b, c care păstrează
aceste valori numerice.

Ce se cere?
Înălţimea cea mai mică la care putem plasa tavanul. Ea este de fapt
înălţimea cea mai mare pe care o au cel puţin unul din cei trei copii.
Fie tavan variabila care păstrează valoarea maximă.

Dar max(a,b)=(a+b+abs(a-b))/2 (am notat abs(x)= | x | ).


Vom calcula succesiv maximul dintre a şi b, apoi maximul dintre acestea
şi c.
Soluţia (1) foloseşte doar structura liniară:

Soluţia (1)

Algoritm maxim_liniar(a,b,c,tavan:numeric);
Scrie ('Înălţimea lui Mihai:');
Citeşte (a);
Scrie ('Înălţimea lui Gigel:');
Citeşte(b);
Scrie ('Înălţimea lui Vasile:');
Citeşte(c);
tavan ← (a+b+abs(a-b))/2;
tavan ← (tavan+c+abs(tavan-c))/2;

30
Curs
Scrie ('Înălţimea minimă a tavanului:',tavan);
Stop

Rezultatul algoritmului şi tabelul de verificare pentru valorile de


intrare: a=175, b=168, c=186 sunt:
Înălţimea lui Mihai:175
Înălţimea lui Gigel:168
Înălţimea lui Vasile:186
Înălţimea minimă a tavanului:186

Paşi A b c Tavan
1, 2 175
3,4 186
5,6 179
7 186
8 186
9 175 186 179 186

Observaţii:
- primele trei instrucţiuni de scriere afişează doar constante de tip
caracter, iar cea de a patra conţine o constantă şi o variabilă în lista de
expresii.
- instrucţiunile de citire conţin în lista de variabile câte o singură
variabilă
- variabila tavan este folosită pentru a fi calculată în prima instrucţiune
de atribuire. În cea de a doua atribuire apare atât în membrul stâng cât
şi în expresia din membrul drept unde va avea valoarea calculată
anterior.

Soluţia (2) nu va folosi formula matematică şi rezolvă problema folosind


structura alternativă. În acest caz vom da un aspect mai general problemei,
algoritmul fiind valabil pentru calculul maximului dintre oricare 3 valori date, a,
b, c rezultatul fiind dat de variabila max .
Soluţia (2)
Algoritm maxim(a, b, c, max: numeric);
Citeşte (a, b, c);
START
dacă a<b atunci
max ← b;
altfel
max ← a; Citeşte (a, b, c)

sfdacă
dacă max<c atunci NU DA
max ← c; α < b
sfdacă
scrie (max); max ← a max ← b
stop
NU DA
Schema logică a algoritmului este: max< c

max ← c

Citeşte (a, b, c)

31
STOP
Bazele algoritmilor

Rezultatul algoritmului şi tabelul de verificare pentru valorile de intrare:


a=175, b=168, c=186 sunt:

175 168 186


186

Paşi A B C Max
1 175 186 179
2 186
3 186
4 175 186 179 186

Observaţii:
- numărul maxim de cazuri distincte pe care le rezolvă acest algoritm
este 4 (2 cazuri pentru primul “Dacă”, apoi, în funcţie de acesta alte 2
posibilităţi pentru cel de-al doilea “Dacă”);
- când algoritmul nostru constituie un subalgoritm pentru rezolvarea unei
probleme, citirea şi scrierea datelor de intrare şi de ieşire rămâne în
sarcina algoritmului apelant. Instrucţiunile citeşte şi scrie fiind eliminate,
singura legătură între algoritmul apelat şi cel apelant rămâne lista de
parametrii. Putem folosi algoritmul dat la soluţia (2) (fără liniile de citire şi
scriere) pentru a rezolva următoarea problemă.
Problema 2.
Calculaţi maximul din 5 valori date. (La alegere valorile pot fi numerice
sau caracter). Algoritmul de mai jos rezolvă problema indiferent de tipul
datelor, aşa încât acesta nici nu este precizat.

Algoritm maxim(a, b, c, max: numeric);


dacă a<b atunci
max ← b;
altfel
max ← a;
sfdacă
dacă max<c atunci
max ← c;

32
Curs
sfdacă
stop

Algoritm maxim_cinci (a, b, c, d, e, max);


Citeşte (a, b, c, d, e);

Maxim (a, b, c, max);


{Apelul subalgoritmului se face cu acelaşi nume de variabile, deşi variabilele
din subalgoritm sunt independente de cele din algoritmul apelant}
Maxim (d, e, max, max);
{La apelul subalgoritmului, valorile variabilelor a, b, c vor fi cele
corespunzătoare lui d, e şi respectiv max din algoritmul apelant. Valoarea
finală calculată pentru max se returnează în algoritmul apelant tot prin
intermediul variabilei max, aflată pe ultima poziţie dintre parametrii}
scrie (max);
stop

Întocmiţi tabelul de verificare pentru un set de date de intrare.


Observaţie:
Datele pot fi de tip caracter. În această situaţie ordinea este cea
lexicografică. Prin ordine lexicografică înţelegem ordinea cuvintelor într-
un dicţionar, bazată pe ordinea alfabetică a literelor dicţionarului.
(“sat”>”salt”).

Problema 3.

Calculaţi valoarea expresiei


 x + y , x ≥ 0, y < 0

 y + x, x < 0, y ≥ 0
E ( x, y ) =  , pentru ∀x, y
 x + y , x ≥ 0, y ≥ 0
 x 2 + y 2 , x < 0, y < 0

∈ R.

Schema logică şi algoritmul de rezolvare:

START

Citeşte (x,y)

NU x<0 DA

NU y<0 DA NU y<0 DA
e← sqrt (x) + sqrt e←sqrt(x*x)
e← sqrt(x) + y e← x + sqrt (y*y) _+sqrt(y*y)
(y)

Scrie (e)

STOP
33
Bazele algoritmilor

Algoritm expresie(x,y,e: numeric);


Citeşte (x, y);
dacă x<0 atunci
dacă y<0 atunci
e←sqrt(x*x) +sqrt(y*y)
altfel
e← x +sqrt(y)
sfdacă
altfel
dacă y<0 atunci
e←sqrt(x) + y
altfel
e←sqrt(x) +sqrt(y)
sfdacă
sfdacă
scrie (e);
stop
Funcţia sqrt(x) calculează radicalul de ordinul doi dintr-un număr real
nenegativ.
Întocmiţi tabelul de verificare pentru fiecare din cele 4 cazuri posibile şi
stabiliţi corectitudinea algoritmului.

2.6.1.Proprietăţi ale structurii alternative.


Proprietatea 1. Fig. 3. Secvenţe de structuri alternative
Structurile alternative se pot
utiliza în algoritmi prin succesiuni
ascendente (succesive) ca în figura
3.a., prin succesiuni descendente
(imbricate) ca în figura 3.b. sau
combinaţii ale acestora figura 3.c.
Proprietatea 2.
Numărul de cazuri distincte ale
unui algoritm cu n secvenţe alternative
succesive este 2n .
Demonstraţia o vom face prin
inducţie după n, n>0.
Pentru n=1 avem o singură a. b. c.
structură alternativă, pentru care avem
doar două cazuri distincte: condiţie1 adevărată şi condiţie1 falsă.
Presupunem că pentru k structuri succesive avem 2k cazuri distincte. Vom
demonstra că dacă se mai adaugă o structură alternativă numărul cazurilor va fi 2k+1 .
Există 2k cazuri distincte până la structura k inclusiv. La întâlnirea celei de a k+1
condiţii în 2k cazuri se alege ramura corespunzătoare valorii de adevăr, iar în alte 2k
cazuri ramura fals. Deci numărul total de cazuri devine 2k +2k =2*2k =2k+1.
Proprietatea 3.
Dacă se construieşte o structură descendentă
completă, (pe fiecare ramură a oricărei structuri
alternative există o singură structură alternativă) cu n
imbricări (nivele), atunci numărul de cazuri distincte este
2n iar numărul blocurilor de decizie utilizat este 1+2+22+
…+2n-1 =2n-1.

Exemplu:
Pentru n=3 imbricări (nivele) avem 8
cazuri distincte şi 23-1= 7 blocuri 34
(Figura 4.).
Curs

Fig. 4. Structură descendentă


completă cu 3 nivele

2.7. Exemple care utilizează structuri repetitive


Exemplul 10.
Problema 1
Algoritmul lui Euclid
Să se determine cel mai mare divizor comun a două numere naturale
nenule.

Reamintim algoritmul lui Euclid printr-un exemplu:


Cmmdc (24, 15)
24 : 15 = 1 rest 9 (prin împărţire întreagă)
15 : 9 = 1 rest 6
9 : 6 = 1 rest 3
6 : 3 = 2 rest 0
– cel mai mare divizor comun al celor 2 numere este ultimul rest diferit
de zero, 3

Fie cele două numere a şi b. Variabilele c – câtul şi r – restul în cadrul


împărţirii întregi.

Algoritm Euclid (a, b, cmmdc : numeric)


r : numeric;
citeşte (a,b);
cât timp (a mod b) < > 0 execută
r ← a mod b;
a ← b; {noua valoare a deîmpărţitului}
b ← r; {noua valoare a împărţitorului}
sf cât timp
cmmdc ← r; {valoarea lui r este cea calculată
la parcurgerea anterioară, deci nu
este nulă}
scrie (cmmdc);
Stop

Tabelul de verificare a algoritmului pentru exemplul de mai sus este:

a b r cmmdc
15 24 15
24 15 9 3
15 9 6
9 6 3
6 3
Observaţie:
Valorile variabilelor a şi b se alterează, se modifică, pe parcursul algoritmului.
Pentru a le păstra, ele vor trebui salvate, memorate, folosind alte 2 variabile, de
exemplu, m,n. În acest caz se vor adăuga după citirea lui a şi b, atribuirile

35
Bazele algoritmilor
m ← a;
n ← b;
Problema 2.

Un casier doreşte să însumeze un teanc de cecuri aflat pe masa sa.


Realizaţi un algoritm care să permită acest lucru în două situaţii :
a) când numărul de cecuri este necunoscut;
b) când există exact n cecuri.

Soluţia I

a). Date de intrare : v – variabilă numerică (suma înscrisă pe un


CEC);
cont – caracter (“D”,”N”) care permite casierului
sa introducă „D” în cazul în care mai are cecuri de
însumat şi „N” atunci când a terminat teancul de
cecuri.
Date de ieşire : S – numerică (suma totală)
i – contor pentru numărul cecurilor).

Algoritm cecuri_a (v, S, i : numeric)


Cont : caracter;
S ← 0; {Iniţializarea sumei totale}
i ← 0;{Iniţializarea contorului de numărare a cecurilor}
repetă
citeşte (v); {Se introduce valoarea unui cec}
i ← i+1; {Se numără cecurile}
S ← S+v; {Se însumează valoarea cecului}
citeşte (cont); {Se introduce “D” sau “N”}
până când (cont = “N”) or (cont = “n”);
scrie (“cele”, i, “cecuri au suma totală S =”, S);
Stop

V S I cont
50000 0 0 “D”
2000000 50000 1 “D”
10000000 2500000 2 “D”
12500000 3 “N”

TEMĂ: Transformaţi algoritmul folosind o structură ‘cât timp’.


b) Rezolvarea în acest caz necesită următoarele date:
Date de intrare : v – variabilă numerică (suma înscrisă pe un cec)
N – numărul de cecuri
Date de ieşire : S – variabilă numerică
Date intermediare: i – contor care urmăreşte numărul de cecuri
introduse.

Algoritm cecuri_b ( n, S : numeric)


v, i : numeric;
citeşte (n);
pentru i=1, n, 1 execută {iniţializarea, mărirea şi
verificarea contorului i}
citeşte (v);{Se introduce valoarea unui cec}
S ← S+v; {Se însumează valoarea cecului}
sf pentru
scrie (S);
Stop;

36
Curs

Soluţia II

Rezolvarea dată în soluţia I presupune ca la fiecare repetare a secvenţei


de citire să se introducă o valoare a unui cec. Valoarea se păstrează în
variabila v şi se pierde odată cu introducerea unui nou cec. Pentru a
păstra toate valorile cecurilor este nevoie de un alt tip de variabile,
structurat, cu n componente. Utilizăm pentru acest scop un şir vi,
i =1, n , cu valori numerice. Folosirea unui şir permite păstrarea tuturor
valorilor cecurilor în n variabile. În scrierea algoritmilor citirea
componentelor unui şir se face de regulă în mod separat de prelucrarea
şirului respectiv. De aceea dăm mai jos subalgoritmul de citire a
elementelor unui şir, subalgoritm pe care îl vom folosi în algoritmul de
însumare a cecurilor şi ori de câte ori vom mai avea nevoie de citirea
unui şir numeric.

Algoritm citeşte_şir(n: numeric , x: şir_numeric);


i : numeric;
citeşte (n); {se citeşte numărul de cecuri}
pentru i=1,n,1 execută {instrucţiunea include
iniţializarea variabilei
i, i=1 şi verificarea
i<=n}
citeşte (x(i));
sf pentru {la sfârşitul structurii
se realizează
incrementarea lui i,
i←i+1}
Stop

Algoritm cecuri_bII (v: şir_numeric , n, S: numeric);


i : numeric;
citeşte_şir (n, v); {apelul algoritmului de citire
a elementelor unui şir.
Corespondenţa se realizează
între n şi respectiv între v
şi x ca şiruri }
S ← 0;
Pentru i=1,n,1 execută
S ← S + v(i);
sf pentru
Scrie (S);
Stop

Problema 3
Să se determine valoarea cea mai mică dintre elementele unui şir având n
componente.
Soluţie:
Date de intrare : a – şirul de elemente numerice (elementele
şirului pot fi şi de tip caracter şi soluţia nu se
modifică)
N – numărul de componente ale şirului
Date de ieşire : min – valoarea minimă din şir
Date intermediare: i – contor care urmăreşte elementele şirului.

Algoritm min_şir(n:numeric,a:şir_numeric,min: numeric)

37
Bazele algoritmilor
i : numeric;
citeşte_şir (n, a); {apelăm algoritmul de citire a
elementelor unui şir definit
anterior}
min ← a(1); {considerăm ca element minim primul
element al şirului}
pentru i = 2,n,1 execută
Dacă a(i) < min atunci
{Dacă elementul de pe poziţia i este mai mic
decât cel mai mic element de până acum, min,
atunci noul min devine acel element}

min ← a(i)

sf dacă
sf pentru
scrie (min);
Stop

Observaţie:
Dacă se doreşte afişarea poziţiilor din şir care au valoarea egală cu
valoarea minimă a), sau câte elemente sunt egale cu valoarea minimă b), va fi
necesară o nouă parcurgere a şirului, respectiv:

a)
pentru i=1,n,1 execută
dacă min = a(i) atunci
scrie (i) {poziţiile care conţin min}
sf dacă
sf pentru

b)
k ← 0 {contorul de numărare a elementelor se iniţializează
cu 0}
pentru i=1,n,1 execută
dacă min = a(i) atunci
k ← k + 1 {k numărul de elemente egale cu min}
sf dacă
sf pentru
scrie (k)

TEMĂ: Întocmiţi tabelul de verificare al algoritmului pentru un şir cu n=7


elemente: -4, 7, 8, 13, 28, 18, -4.

2.8. Concluzii :

1. Variabilele utilizate în algoritmi pot păstra fie valori intermediare, fie toate
valorile (sub formă de şir).
2. Modul de combinare a structurilor permite fie programarea ascendentă
(structuri succesive), fie cea descendentă (structuri imbricate).
3. Alegerea tipului de structură repetitivă adecvată algoritmului permite
evaluarea condiţiilor (la începutul secvenţei sau la sfârşit) şi realizarea de
calcule în succesiunea dorită (cel puţin odată pentru secvenţa repetă sau
eventual niciodată în secvenţa cât timp).
4. Este obligatorie modificarea valorilor variabilelor din condiţiile structurilor
repetitive pentru a evita repetarea secvenţelor la infinit.

38
Curs
5. La utilizarea unor variabile în membrul drept al unor atribuiri aveţi grijă ca
variabila să fie iniţializată în prealabil (prin citire, prin atribuire sau
transmisă ca parametru dintr-un alt algoritm).
6. Programarea structurată nu permite începerea unei structuri în interiorul
altei structuri şi terminarea ei în afara acesteia. Nu este permisă intercalarea
structurilor sub forma:

Cât timp C1 execută


…..
dacă C2 atunci
…..
altfel
…..
sf cât timp
…..
sf dacă

2.8.Verificarea cunoştinţelor

E.1. Structura algoritmică alternativă conţine obligatoriu :


a) Un bloc de atribuire;
b) Un bloc de citire;
c) Un bloc de scriere;
d) Un bloc de decizie.

E.2. Determinarea maximului dintre a şi b se poate realiza folosind secvenţa de


instrucţiuni :
a) dacă a > b atunci c) dacă a<>b atunci
scrie (‘max=’,a); dacă a > b atunci
scrie (‘max=’,b); scrie (‘max=’,a);
sf dacă sf dacă
altfel
b) dacă a > b atunci scrie (‘max=’,b);
scrie (‘max=’,a); sf dacă
altfel
scrie (‘max=’,b); d) Nici o variantă propusă nu
sf dacă corespunde.

E.3. Care dintre următoarele probleme au o rezolvare algoritmică :


a) Tipăriţi toate zecimalele numărului 10/3;
b) Afişaţi primele cinci zecimale ale numărului π ;
c) Scrieţi toate zecimalele numărului π ;
d) Calculaţi câte cifre 1 sunt printre zecimalele numărului π .

E.4. Se dă următorul algoritm:


Algoritm test;
Citeşte (n);
S←0;
Pentru i = 1, n, 1 execută
P←1;
Pentru j = i , 1, -1 execută

39
Bazele algoritmilor
P ← P * j;
Sf pentru
S ← S + P;
Sf pentru;
Scrie (S);
Care este rezultatul corect al algoritmului pentru n=3
a) 6 b) 7 c) 8 d) 9

E.5. Se dă următoarea secvenţă de algoritm:


i←0
c←10
cât timp i < 4 execută
dacă c < 100 atunci i←i+1
sf dacă
i←i+1
scrie (‘TEST’)
sf cât timp
Efectul acestui algoritm este :

a) TEST b) TEST c) TEST d) TEST


TEST TEST TEST
TEST TEST
TEST

E.6. Care dintre expresiile următoare sunt incorecte, ştiind că operatorii a, b


sunt de tip numeric?
a) ( a ≠ b) and (c < b) c) (a + ‘vine’) + b e) b = (a mod b)
b) Not (a < b) d) (div a) + 2

E.7. Care atribuiri sunt corecte, variabilele a, b, x, y fiind de tip real ?


a) x ← 34 c) x ← 34.5 + y e) a ← (b /3) < 2
b) x ← 2.0 ← 3.3 d) 4 ←x

E.8. . Fie următoarea secvenţă:


dacă a > 1 atunci
dacă b > 1 atunci
dacă c > 1 atunci
c←c–1
sfdacă
altfel b ← b – 1
sfdacă
sfdacă
Care sunt valorile lui a, b şi c după execuţia secvenţei dacă iniţial a = 3, b = -3,
c = 2.
a) a = 3, b = -3, c = 2 c) a = 3, b = -4, c = 2
b) a = 3, b = -3, c = 1 d) a = 2, b = -3, c = 2

E.9. Care sunt structurile admise de programarea structurată ?


a) structura descendentă
b) structura alternativă
c) structura repetitivă
d) structura modulară
e) structura liniară

40
Curs

E.10. Care din următoarele secvenţe foloseşte o structură este de tip repetă ..
până când ?
a) b) c) d)
S1 S1
S1 S1
S2
NU C DA DA S2
C
C DA S2 S2 NU
C
NU
NU DA

E.11. Care din următoarele secvenţe pseudocod corespund schemei E.9.a).


a) S1 b) S1 c) S1
Repetă S2 repetă
S2 Dacă C atunci S2 S2
Până când C până când (not C)

E.12. Ce reprezintă un identificator ?


a) numele unei structuri
b) un algoritm
c) numele unei variabile
d) un tip de dată

E.13. Câte cazuri distincte generează o secvenţă ascendentă de n structuri


alternative?
a) 2n b) 2n-1 c) 2n d) 2n-1

E.14. Care din următoarele elemente sunt de bază în elaborarea unui algoritm:
a) limbajul de programare, date de intrare, date de ieşire;
b) date de intrare, date de ieşire, succesiune de paşi;
c) variabilele, date de intrare, succesiune de paşi;
d) constantele, date de ieşire, succesiune de paşi;

E.15. Care din următoarele tipuri de date sunt compuse (structurate):


a) şir b) boolean c) articol d) matrice e) caracter

E.16. Care din următoarele expresii logice au valoarea de adevăr pentru a=1 şi
b=0:
a) (a > b) and (b < 0)
b) not (a > b) or not (b > 0)
c) (a > 0) or (b > 0) and (b < 0) or (a <1)
d) (b > 0) and (b <1) or (a > 0) and (a < 2)

E.17. Caracteristicile algoritmilor sunt:


a) Corectitudine
b) Recunoaştere
c) Finitudine
d) Generalitate
e) Testare

P.1. Scrieţi un algoritm pentru a aranja, în ordine alfabetică, 3 cuvinte date.

41
Bazele algoritmilor
P.2. Trei copii au fiecare câte un loz câştigător. Dacă se cunosc numele copiilor
şi valoarea lozului pentru fiecare copil să se determine care dintre copii au
valoarea câştigului cea mai mare.

P.3. Calculaţi suma S=1+1*2+1*2*3+ … + 1*2*3*…*n pentru n>0, natural.

P.4. Un iepure fuge dintr-o poiană cu o viteză v1. După un timp t în poiană
soseşte vânătorul şi dă de urma iepurelui. Vânătorul porneşte în urmărirea
iepurelui cu o viteză v2. Dacă viteza este exprimată în unităţi de lungime pe
unitatea de timp, aflaţi dacă vânătorul ajunge iepurele şi după cât timp.

2.9.Răspunsuri.

E.1. d), E.2. b), E.3. b), E.4. d), E.5. b), E.6. c),d), E.7. a),c), E.8. c), E.9.
b),c),e), E.10. d), E.11. c), E.12. c), E.13. c), E.14. b), E.15. a), c), d),
E.16. b), c), d), E.17. a), c), d).

P.1.
Folosim un algoritm care permite schimbarea valorilor a două variabile.
În acest mod comparăm a cu b, dacă e cazul schimbăm valorile lor, apoi
a cu c şi în final b cu c.

Algoritm schimb(a, b : caracter);


aux : caracter; {variabila auxiliară are rolul de
a păstra intermediar una din
valori, exact ca în procesul de
schimbare a conţinutului a două
vase cu lichide, în care avem
nevoie de un vas auxiliar}
aux ← b;
b ← a; 2
a b
a ← aux;
stop aux
3 1
Algoritm ordine(a, b, c : caracter);
Citeşte (a, b, c);
dacă a > b atunci
schimb (a , b );
sfdacă
dacă a > c atunci
schimb (a , c );
sfdacă
dacă b > c atunci
schimb (b , c );
sfdacă
scrie (a, b, c);
stop

P.2.

Algoritm persoana(x,max: numeric, numex: caracter)

42
Curs
Dacă x=max atunci
Scrie (numex)
Sf dacă

Algoritm loz_mare(a,b,c:numeric;na,nb,nc:caracter);
Numeric : max;
Citeşte (a,na); {a valoarea lozului, na – numele
copilului}
Citeşte (b,nb);
Citeşte (c,nc);
Maxim (a,b,c,max); {Algoritmul de la Exemplul 9,
Problema 1}
Persoana(a,max,na);
Persoana(b,max,nb);
Persoana(c,max,nc);
Stop

P.3.

Algoritm suma ( n, S );
Citeşte (n);
P←1;
S←0;
Pentru i = 1, n, 1 execută
P ← P * i;{Calculează, cumulativ, produsele de forma
1*2*3*. . . *i, pentru fiecare
valoare a lui i}
S ← S + P;
Sf pentru;
Scrie (S);

P.4.

Este evident că dacă viteza vânătorului este mai mică sau egală cu cea a
iepurelui nu este posibilă prinderea. Variabila poc are rolul de a număra unităţile de
timp în care vânătorul se apropie de iepure cu distanţa (v2 - v1). Distanţa d care este
iniţial între cei doi scade în fiecare unitate de timp, prinderea are loc atunci când
distanţa este nulă.

Algoritm vânătoare ( v1, v2, t , poc );


Citeşte (v1, v2, t);
Poc ← 0
Dacă v1 < v2 atunci
d ← v1 * t; {Avansul
iepurelui }
Cât timp d > 0 execută
d ← d – ( v2 – v1 );
poc ← poc + 1;
Sf cât timp;
Scrie ( poc )
Altfel
Scrie (“Vântorul nu prinde iepurele!”);
Sf dacă

Observaţie: O altă soluţie pentru această problemă se poate determina prin simpla
împărţire a distanţei la diferenţa de viteză (d / (v2 – v1)) şi considerând câtul
împărţirii întregi. Algoritmul definit mai sus este eficient atunci când operaţiile de

43
Bazele algoritmilor
adunare şi scădere sunt singurele ce pot fi efectuate asupra variabilelor datorită
valorilor mari la care se poate ajunge.

44
Curs

3. Elaborarea, corectitudinea, complexitatea şi testarea


algoritmilor

3.1.Elaborarea algoritmilor
Rezolvarea unei probleme cu ajutorul calculatorului presupune din partea
programatorului să cunoască foarte bine modul de rezolvare a acesteia. Calculatorul
nu face altceva decât să execute succesiunea de paşi, algoritmul, pe care
programatorul l-a descris în cele mai mici detalii. Nici un amănunt nu este de neglijat
în elaborarea corectă a unui algoritm. Acesta trebuie să răspundă corect la toate
variantele posibile a datelor de intrare ale problemei. Elaborarea algoritmului de
rezolvare este o secvenţă dintr-un lanţ de evenimente pe care le parcurgem până la
rezolvarea corectă a unei probleme.

Definirea completă a problemei


Analiza cerinţelor
Structurarea de ansamblu a problemei
Detalii ale problemei
Construcţia algoritmului
Implementarea algoritmului

Figura 5. Testarea modulelor


Etapele elaborării Testarea de ansamblu
algoritmului unei
probleme Întreţinere

În figura 5 sunt prezentate principalele activităţi ce duc la rezolvarea unei


probleme cu ajutorul calculatorului. Vom numi în continuare această operaţie
elaborare de software sau programare.
Fără a restrânge importanţa tuturor activităţilor am haşurat patru dintre acestea
asupra cărora vom face referiri privitoare la elaborarea algoritmului de rezolvare a
problemei.
După definirea completă a problemei, înţelegerea acesteia, delimitarea cerinţelor
şi a elementelor cunoscute este foarte importantă delimitarea subproblemelor. În cazul
în care problema poate fi împărţită în mici părţi rezolvabile independent se trece la
delimitarea acestora şi la stabilirea modului lor de asamblare. Fiecare subproblemă
devine astfel o problemă independentă, cu propriile cerinţe şi date de intrare. Înainte
de a trece la rezolvarea fiecărei componente în parte se stabilesc legăturile care trebuie
să existe între acestea şi modul în care vor transmite între ele date sau rezultate.
Elaborarea algoritmului unei probleme presupune parcurgerea următoarelor
etape:
a) Analiza şi înţelegerea detaliilor problemei;
b) Stabilirea cerinţelor şi a datelor de intrare;
c) Stabilirea tipurilor de date şi numelor acestora;
d) Construirea şi delimitarea paşilor de rezolvare;
e) Stabilirea structurilor necesare descrierii paşilor. Programarea structurată
permite doar secvenţe liniare, alternative şi repetitive;
f) Urmărirea şi verificarea posibilelor erori la efectuarea unor paşi;
g) Implementarea; transcrierea algoritmului în pseudocod, schemă logică sau
limbaj de programare;

45
Bazele algoritmilor
h) Verificarea algoritmului pentru toate variantele posibile ale datelor de intrare.
Pe tot parcursul acestor paşi, în elaborarea algoritmului, încercaţi să vă gândiţi la
elementele din figura 6, şi la multe altele...

Figura 6. Analiza permanentă la elaborarea algoritmilor.

Complexitatea
calculelor! Problema
de
rezolvat!
Eficienţa
DATE:
metodei!
tipuri, Detalii!
Cum nume,
testezi dimensiuni!
Cel mai algoritmul?
bun
algoritm!
Corectitudinea metodei de rezolvare!

3.2.Corectitudinea algoritmilor

Studiul problemelor rezolvabile cu ajutorul algoritmilor a demonstrat faptul că nu


orice problemă poate fi rezolvată folosind algoritmi. Criterii legate de finitudinea
problemei, de volumul de date, de mecanismele care duc la rezultatele corecte fac
uneori imposibilă găsirea unui algoritm de rezolvare.
Tendinţa lumii moderne este de a găsi metode şi mijloace care să permită
rezolvarea celor mai multe dintre probleme folosind calculatorul, deci modelarea lor
sub formă algoritmică. La întrebarea “Pot calculatoarele să gândească?” un răspuns
posibil va veni tot prin crearea de algoritmi care să permită analiza, sinteza şi decizia
pe baza unui volum de date impresionant.
Rezolvarea unei problemei folosind un algoritm presupune identificarea acelor
paşi şi succesiuni ale acestora, care pentru orice set de date de intrare să furnizeze
rezultate corecte.
Să notăm mulţimea datelor de intrare cu D şi a rezultatelor cu R.

Definiţie
Definim ca fiind o problemă algoritmică (problemă ce poate fi rezolvată
folosind un algoritm) o funcţie de la mulţimea D la mulţimea R, P : D → R, unde
pentru x ∈D, P ( x ) se numeşte rezultatul algoritmului pentru datele de intrare x.
Mulţimile D şi R sunt nevide şi cel mult numărabile.

Definiţie
Definim funcţiile cu valori logice (numite predicate) f şi g astfel:
f : D →{true , false }
g : D × R →{true , false }
f - se numeşte predicatul de intrare, precondiţie şi descrie elementele din D
pentru care algoritmul are sens.
g – se numeşte predicat de ieşire, postcondiţie. El are valoarea true dacă
perechea ( x, y ) ∈D × R, corespunde rezultatelor corecte y obţinute prin aplicarea
algoritmului datelor de intrare x.
Exemplul 1:

46
Curs
Calculaţi rădăcina pătrată din x.
Definim pentru problema noastră cele două predicate:
f(x) este “x>=0” datele de intrare sunt numere nenegative
g(x,y) este “y2=x” trebuie găsit y a.î. pătratul său este x. Găsirea lui y
poate fi exactă sau aproximativă. Fie ε aproximaţia.
Atunci pentru f(x) : “x>=0” şi “ε > 0 ”, g(x,y) este “ y −x <ε ”
2

Definiţie
Algoritmul corespunzător problemei se defineşte ca fiind perechea A=(f,g).
Algoritmul A este parţial corect dacă pentru ∀x ∈D, f(x) este true şi g(x,
P(x)) există, deci programul are rezultate.

Definiţie
Algoritmul A este total corect în raport cu specificaţiile problemei dacă
∀ x ∈D, f(x) este true, rezultatul programului fiind P(x), iar g(x, P(x)) există şi este
true.
Desigur există metode mai mult sau mai puţin formale pentru definirea şi
demonstrarea corectitudinii unui algoritm. Această exprimare, mai puţin formală,
permite înţelegerea cu ajutorul noţiunii de funcţie a fenomenului de corectitudine a
algoritmilor. Desigur, dacă o problemă este definită în mod incorect algoritmul
echivalent cu aceasta nu poate decât să dea aceleaşi rezultate.
Pentru o problemă dată există desigur mai mulţi algoritmi, acest lucru se
datorează modului de succesiune a paşilor, a metodelor de rezolvare adoptate. De
exemplu înmulţirea a două numere naturale se poate realiza prin adunări succesive,
prin înmulţirea cu fiecare cifră sau prin “înmulţirea a la ruse” descrisă în capitolul 1.
În acest caz mulţimile D şi R sunt aceleaşi iar funcţiile ce descriu cei trei algoritmi
diferă, dar sunt echivalente.

3.3.Complexitatea algoritmilor
În cele ce urmează vom analiza timpul necesar execuţiei fiecărui algoritm
precum şi spaţiul de memorie destinat gestiunii datelor. Se observă că aceste două
aspecte determină situaţii diferite la înmulţirea a două numere. La adunarea repetată
numărul operaţiilor creşte foarte mult odată cu creşterea numerelor. Această creştere
nu este atât de semnificativă la înmulţirea cu fiecare cifră şi însumarea
corespunzătoare a rezultatelor. Spre deosebire de aceste două metode înmulţirea “a la
russe” oferă un rezultat după k+1 paşi (2k<nr, nr fiind primul număr).
Datorită performanţelor actuale ale calculatoarelor nu se va observa o diferenţă
semnificativă la executarea celor trei variante de algoritmi. Se pune însă problema
“Rezolvăm indiferent de timpul necesar execuţiei bazându-ne pe suficiente resurse
hard sau căutăm soluţia care în cele mai grele situaţii să furnizeze rezultatul cât mai
repede?”
Evident pentru valori mici nu contează dar să urmărim următorul tabel să vedem
care sunt diferenţele atunci când numărul de paşi este de diferite ordine de mărime:

log2n n n log2n n2 n3 2n
0 1 0 1 1 2
1 2 2 4 8 4
2 4 8 16 64 16
3 8 24 64 512 256
4 16 64 256 4096 65536
5 32 160 1024 32768 4294967296
Tabelul 1. Ordine de mărime ale puterilor lui n

47
Bazele algoritmilor
Dacă privim din punctul de vedere al limbajului de programare şi comparăm
limbajele Pascal şi C, timpii de execuţie, în raport cu memoria şi operaţiile executate,
arată astfel (unitatea de timp este considerată timpul necesar unei atribuiri simple8):

Operaţia Exemplu Timp consumat


Pascal C
Atribuire întregi x=y 1 1
Adunare întregi x=y+z 2 1.3
Înmulţire întregi x=y*z 3 2
Acces la tablou întregi x=y[i] 3 4
Acces pointer x=y^ 2.5 2
Adunare/înmulţire real x=y*z 300 150
Acces la tablou real x=y[i] 8 100
Funcţia radical x=sqrt(y) 500 300
Funcţia ex x=exp(x) 2000 1300
Funcţia sin(x) x=sin(x) 1000 700
Apel subprogram subalg(x) 6 6
Tabelul 2. Timpii de execuţie a unor operaţii elementare în Pascal şi C.

Pentru a calcula timpul necesar execuţiei unui algoritm vom considera în


continuare două situaţii de evaluare a complexităţii algoritmilor: complexitatea în
cazul cel mai defavorabil şi complexitatea medie. Datorită faptului că timpul necesar
efectuării diverselor operaţii (vezi tabelul 2) diferă cu cel mult k*103, timpi care sunt
nesemnificativ la procesoarele moderne, vom considera că toate operaţiile elementare
se efectuează în aceeaşi unitate de timp.

Definiţie
Notăm cu ta(n) timpul în care algoritmul a rezolvă problema P în cazul cel mai
defavorabil.
ta(n)= sup{Ta(P(x)) | x ∈D, n este numărul de operaţii pentru a obţine
rezultatul P(x)}
ta(n)=O(f(n)), este ordinul lui f(n), dacă există două constante c şi n0 astfel încât
ta(n)≤ cf(n) pentru orice n0 ≤ n.
Exemplu:
Pentru un algoritm cu f(n)=3n+10, ordinul algoritmului este O(f(n))=O(n), şi se
numeşte algoritm polinomial.
În algoritmul de însumare a cecurilor din problema 7 structura repetitivă se
execută de n ori indiferent de situaţii deci algoritmul este de complexitate O(n).
Pentru problemele pe care le vom întâlni în capitolele ce urmează vom da şi
studii comparative privind complexitatea algoritmului ales la rezolvarea problemei.
Practica a admis ca acceptabili doar algoritmii polinomiali, de complexitate
O(nk). Trebuie admis că există algoritmi în timp exponenţiali, în general de ordin
O(2n), care furnizează soluţii în timp îndelungat. Pentru aceşti algoritmi se caută
soluţii polinomiale, acceptabile pentru seturi de date întâlnite în practică.
Nu se ştie încă, dacă, orice problemă rezolvată în timp exponenţial are şi soluţie
polinomială.

3.4.Testarea algoritmilor
Problemele cele mai delicate referitoare la algoritm s-au dovedit însă cele de
verificare şi testare a acestuia pentru toate seturile de date de intrare posibile.
Testarea unui algoritm se poate realiza prin diverse metode, dar respectând o
succesiune a paşilor şi câteva tehnici specifice. Dintre principalele aspecte legate de
testarea programelor menţionăm:

8
Aceste măsuri depind de asemenea şi de circumstanţele compilării şi a specificaţiilor de generare a
codului maşină în fiecare limbaj în parte.

48
Curs
1. Testarea modulelor. Testarea programelor mici se face în ansamblul lor.
Problemele ample, care sunt constituite din module se testează prin
verificarea fiecărui modul în parte. La asamblarea modulelor se testează în
ansamblu doar module care au fost deja testate individual.
2. Testare şi depanare. Se folosesc de regulă în practică două noţiuni, cea de
“testare” a programelor şi cea de “depanare” a acestora. Unii programatori
nu fac deosebire între cei doi termeni.
- A testa un program înseamnă a detecta eventualele erori aplicând diverse
seturi de date de intrare şi comparând rezultatele cu rezultatele corecte.
- A depana un program înseamnă a diagnostica şi a corecta cauzele erorilor,
adică a parcurge pas cu pas algoritmul şi a depista pasul la care algoritmul
este greşit.
3. Testarea în timpul elaborării programelor. În general un modul de program se
construieşte ca o “cutie neagră”, în care sunt importante intrările şi ieşirile,
fără ca utilizatorul să aibă acces în nucleul secvenţei. Principiile moderne
dovedesc însă eficienţa, mai ales în domeniul testării, a modulelor sub formă
de “cutie albă” sau “cutie de sticlă”, transparentă la operaţiile din interior.
Acest lucru face mai uşor accesul la secvenţele din program şi deci o şansă
mai mare în a găsi anumite date de intrare pentru care algoritmul furnizează
erori. În acest sens se recomandă ca odată cu construirea unui modul, în
timpul elaborării algoritmului, să se efectueze şi teste. Aşa există
posibilitatea de a depista cauzele unei erori. Odată verificată o secvenţă o
eroare poate să apară doar din zona de program adăugată ulterior.
4. Testarea în funcţie de datele de intrare. La alegerea testelor se va ţine cont de
caracteristicile datelor de intrare:
- tipul datelor
- valorile minime şi maxime posibile
- modul de reprezentare
- validitatea intrărilor (corectitudinea datelor de intrare). Unele programe
verifică dacă datele de intrare respectă condiţiile impuse (vezi radical din x,
unde x>=0), altele presupun că intrările sunt valide, deci setul de teste trebuie
ales în mod corespunzător.
- gruparea testelor în seturi de date de intrare relevante pentru paşii ce vor fi
parcurşi în algoritm (pentru a testa maximul dintre 3 numere reale există 6
teste relevante, ţinând cont de ordinea celor 3 numere; următoarele două
teste, 65, 78, 45 şi 3, 9, 2, fac parte din aceeaşi categorie şi parcurg
algoritmul prin aceleaşi secvenţe). Construirea de clase echivalente la
testarea programelor duce la reducerea timpului necesar testării, prin
reducerea numărului de situaţii distincte.
5. Testarea automată. Acest concept modern de testare presupune ca pentru un
algoritm dat, pentru date de intrare cunoscute la care se cunoaşte ieşirea
dorită să se elaboreze un algoritm care să analizeze toate variantele posibile
ale programului de testat şi să furnizeze rezultatele pentru toate clasele
reprezentative de testare.
Prin testarea algoritmilor se determină erorile făcute în diverse etape de elaborare
a unui algoritm şi de scriere a programului. Un studiu efectuat de Boris Beizer în 1990
arată că cele mai frecvente erori se întâlnesc în etapa de proiectare a algoritmului iar
cele mai puţine se datorează software-ului utilizat. Procentele sunt enumerate mai jos:
• proiectarea algoritmului 5,18 %
• nivelul datelor 22,44 %
• funcţionalitatea modulelor 6,19 %
• implementare 9,88 %
• integrarea modulelor 8,98 %
• cerinţe de funcţionalitate 8,12 %
• testare şi execuţie 2,76 %
• hardware şi software 1,74 %

49
Bazele algoritmilor
• alte cauze 4,71 %
Testarea programelor este o necesitate în a decide dacă un program răspunde
s-au nu cerinţelor probleme. Problemele ample necesită însă un timp îndelungat
pentru testarea lor în ansamblu. Deşi se spune că “Un program care aproape
merge este ca un avion care aproape zboară!”, prin asumarea unui risc de câteva
procente în detrimentul câştigului, se lansează pe piaţă programe care “aproape
merg”, eventualele erori sunt depistate în etapa de întreţinere, corectate şi deci
programul îmbunătăţit.

3.5.Verificarea cunoştinţelor

E.1. Care este ordinea firească a următoarelor etape de elaborare a algoritmilor:


1) Verificarea algoritmului;
2) Construirea şi delimitarea paşilor de rezolvare;
3) Analiza cerinţelor;
4) Transcrierea algoritmului în pseudocod, schemă logică sau limbaj de programare;
5) Stabilirea datelor de intrare;
a) 5,2,4,3,1 b) 3,5,2,1,4 c) 3, 5, 2, 4, 1 d) 3, 2, 5, 1, 4

E.2. Pentru rezolvarea unui probleme există:


a) un algoritm unic;
b) nici un algoritm;
c) mai mulţi algoritmi dacă problema este algoritmică;
d) mai mulţi algoritmi dacă problema are soluţie;

E.3. Care din următoarele afirmaţii sunt adevărate:


a) un algoritm parţial corect furnizează întotdeauna rezultate;
b) un algoritm total corect furnizează întotdeauna rezultate corecte;
c) un algoritm parţial corect poate furniza rezultate incorecte;
d) un algoritm total corect poate furniza rezultate incorecte.

E.4. Ordinul algoritmului dat de funcţia f(n)=3n2+n+4 este:


a) O(n) b) O(n2)c) O(n3)d) O(n4)

E.5. Care este ordinul de complexitate a algoritmul:

Algoritm complexitate;
Citeşte (n, m);
Pentru i = 1, n, 1 execută
Pentru j = 1 , m, 1 execută
Scrie ( “perechea “, i,”,”, j )
Sf pentru
Sf pentru;
Stop;
a) O(n) b) O(n2)c) O(n x m) d) O(n+m)

P.1. Testaţi algoritmul de la E.5. pentru un număr suficient de date de intrare.


Analizaţi câte seturi distincte sunt necesare!

3.6.Răspunsuri.

E.1. c), E.2. c), E.3. a),b),c), E.4. b), E.5.c).

P.1.
Se are în vedere că algoritmul nu testează validitatea datelor de intrare. Deci:

50
Curs
- Pentru n şi m mai mici decât 1, algoritmul nu furnizează nici o soluţie.
- Pentru n < 1 şi m >= 1 sau n>=1 şi m < 1, algoritmul nu furnizează nici o
soluţie.
- Pentru n>1 şi m > 1 algoritmul afişează perechile produsului cartezian {1,2,
…,n}X{1,2,…,m}, indiferent dacă n>m, n<m sau n=m.
Observaţie: Verificaţi, în funcţie de limbajul de programare ales, care sunt
valorile maxime pentru n şi m şi comparaţi timpii de execuţie pentru valori
foarte mari ale acestora.

51
Bazele algoritmilor

4. Algoritmi elementari
Etapa de găsire a metodei de rezolvare şi transcrierea sub formă de paşi
constituie de regulă cea mai dificilă dintre etapele elaborării algoritmilor. Problemele
algoritmice îmbracă forma paşilor unui algoritm odată cu găsirea şi definitivarea
formei matematice a rezolvării problemei. Pentru a uşura această trecere de la forma
practică (enunţul “îmbrăcat” al problemei), la forma matematică (modelul
“abstract” al problemei) şi apoi la forma algoritmică (modelarea “calculator” prin
paşi şi structuri algoritmice a problemei) am dedicat acest capitol tratării câtorva dintre
cele mai des întâlnite situaţii în practica elaborării algoritmilor.
Vom considera pentru fiecare situaţie cele trei forme şi vom ilustra cu câteva
exemple clasice. Problemele propuse la finalul capitolului cuprind rezolvări ale căror
algoritmi îmbină situaţiile descrise mai jos.

4.1.Schimbarea valorilor a două variabile

forma practică:
O cană roşie conţine ceai, iar una albastră lapte. Se doreşte schimbarea
conţinutului celor două căni între ele.

forma matematică:
Reprezentarea a două mărimi se realizează folosind variabile de diverse tipuri.
Fie a, b variabilele care corespund celor două căni şi valorile lor numerice.
Deci a=c1 şi b=c2. Dar a = b este fals, atunci succesiunea de operaţii x =a + b şi
y = x – a , z = x - b ne dau b = y şi a = z.

forma algoritmică:
Variabilele utilizate în algoritmică au proprietatea de a-şi modifica valoarea după
fiecare operaţie de atribuire. Valorile lor pot fi de diverse tipuri, caracter: “ceai” şi
respectiv “lapte”, numerice, logice. Pentru a putea realiza schimbul valorilor
algoritmul:

Algoritm schimb ( a, b );
x : {Orice tip}
x ← a;
a ← b;
b ← x;
stop;

permite păstrarea valorii lui a în x, transferul valorii lui b în a şi apoi valoarea lui a
păstrată în x trece în b. Această schimbare se poate face indiferent de tipul
variabilelor.
Dacă variabilele a şi b sunt de tip numeric şi acceptă operaţii de adunare şi
scădere atunci variabilele matematice x, y şi z nu mai sunt necesare, iar algoritmul
este:

Algoritm schimb_numeric ( a, b : numeric );


x : numeric;

a ← a + b;
b ← a - b;
a ← a - b;
stop;

Exemplu: a = 17, b = 13, şi tabelul de verificare a celor trei paşi:

52
Curs
Pas a = 17 b = 13
1 30 13
2 30 17
3 13 17

4.2.Parcurgerea elementelor unei mulţimi9, (secvenţe).


forma practică:
Să se efectueze o anumită operaţie asupra fiecărui element al unei mulţimi.

forma matematică:
Se ştie că, matematic, o mulţime M este definită prin elemente distincte.
Operaţiile permise asupra mulţimilor sunt reuniune, intersecţie, apartenenţă,
incluziune, produs cartezian, etc.
Numărul elementelor unei mulţimi se numeşte cartezianul mulţimii şi se notează
cu M . Acesta poate fi finit sau infinit (numărabil sau nenumărabil). Dacă M
= n, finit, atunci elementele mulţimii pot fi parcurse folosind notaţia matematică
i =1, n , i parcurge toate elementele mulţimii {1,2,…,n}.
Dacă numărul elementelor nu se cunoaşte atunci exprimarea elementelor unei
mulţimi se face prin descrierea proprietăţilor elementelor sale, sub forma:
M = {x | x verifică <Condiţia>}
De reţinut că dintre mulţimi doar cele cu număr finit de elemente pot face studiul
problemelor algoritmice.

forma algoritmică:
Parcurgerea elementelor unei mulţimi, având în vedere că reprezintă o operaţie
care repetă o anumită secvenţă de un număr de ori se va rezolva algoritmic folosind
structura repetitivă. Distingem două cazuri:
a) Când numărul de elemente este n.
Secvenţa de paşi:

Pentru i = 1 , n, 1 execută
{Operaţie asupra fiecărui element}
Sf pentru

Dintre problemele clasice care se încadrează în această categorie: suma sau


produsul a n elemente, sume definite prin termen general, parcurgerea elementelor
unui şir (citirea, scrierea elementelor).
b) Când numărul elementelor nu se cunoaşte dar este finit şi există o
<condiţie> care permite parcurgerea elementelor.

Cât timp <condiţie> execută


{Operaţie asupra fiecărui element}
Sf cât timp;

sau

Repetă
{Operaţie asupra fiecărui element}
până când not <condiţie>;

Probleme care se încadrează în această categorie: Algoritmul lui Euclid,


determinarea cifrelor unui număr, descompunerea unui număr în factori primi,

9
Noţiunea de mulţime, acceptată matematic, utilizată în paragrafele ce
urmează, se poate extinde la secvenţe de elemente (şir, listă, matrice, etc.,) iar
în accepţiunea informatică această structură de date poate conţine şi elemente
egale (n.a.).

53
Bazele algoritmilor
transformarea numerelor în diverse baze de numeraţie, prelucrarea şirurilor de
caractere.

4.3.Implementarea cuantificatorilor matematici oricare şi există.


forma practică:
(A) Să se verifice dacă toate elementele unei mulţimi verifică o anumită
proprietate.
(B) Să se verifice dacă există cel puţin un element care verifică o proprietate
dată.
Vom numi aceste tipuri de probleme, probleme cu cod de validare, “cu beculeţ”.

forma matematică:
Se cunoaşte exprimarea matematică a celor doi cuantificatori pentru o mulţime M
şi un predicat P(x), P: M → {Fals, Adevărat}:
(A) ∀x ∈M , P ( x ) este adevărat
(B) x ∈M , astfel încât P(x) să fie adevărat

forma algoritmică:
Descrierea algoritmică presupune introducerea unei variabile logice, cod, care
să-şi modifice valoarea doar în cazul în care nu se certifică proprietatea cerută. Fie
<condiţie> condiţia de parcurgere a elementelor mulţimii şi <P> predicatul
(proprietatea), pentru care P( x ) este adevărat sau fals.

(A) Algoritm care permite implementarea cuantificatorului „oricare”


Cod ← Adevărat;
Cât timp <conditie> and cod execută
Dacă not <P> atunci
Cod ← Fals;
Sf cât timp;

Dacă cod atunci


{Oricare element verifică proprietatea}
altfel
{Cel puţin un element nu verifică proprietatea}
sf dacă

(B) Algoritm care permite implementarea cuantificatorului „există”


Cod ← Fals;
Cât timp <conditie> and not cod execută
Dacă <P> atunci
Cod ← Adevărat;
Sf cât timp;
Dacă cod atunci
{Există element care verifică proprietatea}
altfel
{Nu există element care să verifice
proprietatea}
sf dacă

Observaţii:
1) Implementarea folosind structurile Pentru sau Repetă sunt similare şi rămân
ca exerciţiu.
2) Complexitatea algoritmului este O(n), deoarece în cel mai defavorabil caz
trebuie parcurse toate cele n elemente ale mulţimii.

Exemplul 1.

54
Curs
Să se determine dacă un număr natural n, n>2, este prim.

Algoritm prim ( n: numeric, cod : boolean );


d : numeric;
Cod ← Adevărat;
d ← 2;
Cât timp d <= sqrt (n) and cod execută
Dacă (n mod d) = 0 atunci
Cod ← Fals;
Sf dacă
d ← d + 1;
Sf cât timp;
Dacă cod atunci
Scrie (n, “ este prim”);
altfel
Scrie (n, “ NU este prim”);
sf dacă;
stop;

Algoritmul verifică dacă orice număr d, cuprins între 2 şi sqrt(n), nu


este divizor al lui n.
O problemă clasică la care se aplică acest algoritm este căutarea
secvenţială. Verifică dacă un element aparţine unei mulţimi şi reţine
poziţia acestuia, parcurgând elementele mulţimii în ordinea în care se
dau.

4.4.Implementarea produsului cartezian a două mulţimi.

forma practică:
Să se genereze toate elementele produsului cartezian a două mulţimi, cu m şi
respectiv n elemente.

forma matematică:
Exprimarea matematică a produsului cartezian a doua mulţimi A şi B este:

A ×B = {( x, y ) x ∈A, y ∈B}

Deci fiecare element al mulţimii A formează o pereche cu fiecare element din


mulţimea B. Dacă mulţimea A are m elemente, iar B are n elemente, mulţimea AxB
are mxn elemente.

forma algoritmică:
Din descrierea matematică rezultă că mulţimea A va trebui parcursă în întregime,
deci vom folosi o structură repetitivă, iar pentru fiecare element din A vom parcurge
mulţimea B, deci o altă structură repetitivă, inclusă în prima. Rezultă următoarea
secvenţă de paşi:

Pentru i = 1 , m, 1 execută
{Operaţie asupra fiecărui element din A}

Pentru j = 1 , n, 1 execută

{Operaţie asupra fiecărui element din B.


Această secvenţă se execută de n ori
pentru fiecare element din A, deci pentru
fiecare element al produsului cartezian,
(a, b)}

55
Bazele algoritmilor
Sf pentru
Sf pentru

Observaţii:
1) Implementarea folosind structurile Cât timp sau Repetă necesită stabilirea
condiţiilor de parcurgere a fiecărei mulţimi şi rămân ca exerciţiu.
2) Complexitatea acestui algoritm este O(mxn).
3) Algoritmul se poate generaliza pentru produsul cartezian a trei sau mai multe
mulţimi. În general pentru a genera elementele produsului cartezian a m
mulţimi fiecare având ni , i =1,m elemente, se vor folosi m structuri repetitive
incluse, iar complexitatea algoritmului este O(n1 x n2 x … x nm).

Exemplul 2.
Să se numere elementele nule de pe fiecare linie a unei matrice cu m
linii şi n coloane.

Algoritm matrice (a [m,n]:matrice_numerică,


nule:numeric);
i, j: numeric;
Pentru i = 1 , m, 1 execută
nule ← 0;
{pentru fiecare linie se reiniţializează
contorul de numărare}
Pentru j = 1 , n, 1 execută
{se verifică elementul matricei de pe
linia i coloana j, linia i rămâne
constantă pentru j=1,n}
Dacă a [i,j] = 0 atunci
nule ← nule + 1;
Sf dacă
Sf pentru;
Scrie (nule);
{pentru fiecare linie se afişează contorul de
numărare după parcugerea elementelor de pe linia i}
Sf pentru;

Variabila nule se iniţializează cu 0 la începerea parcurgerii fiecărei linii


şi se incrementează de fiecare dată când s-a întâlnit un element nul pe
linia corespunzătoare. Odată cu încheierea structurii corespunzătoare
parcurgerii unei linii se afişează valoarea variabilei nule.
Numărarea elementelor poate fi utilizată şi la implementarea
cuantificatorilor există şi oricare. Un contor care numără elementele care
verifică proprietatea P, dacă are valoarea mai mare decât 1 rezultă
existenţa, iar când acesta are valoarea egală cu numărul elementelor
mulţimii este verificată universalitatea.

4.5.Metode de sortare a elementelor unei mulţimi.

forma practică:
Să se ordoneze elementele unei mulţimi, corespunzător ordinii definite pentru
elementele acesteia.

forma matematică:

56
Curs
Fie A = {x1, x2, … , xn } o mulţime cu n elemente şi o relaţie de ordine “<” între
elementele sale. Spunem că elementele mulţimii A sunt ordonate crescător10 dacă
xi < xi+1 pentru ∀i =1, n −1

forma algoritmică:
Principalele metode de sortare se disting prin modalităţile de lucru şi prin
complexitatea algoritmilor aplicaţi. Prezentăm în continuare câteva dintre cele mai
reprezentative metode11.

4.5.1. Sortarea prin metoda bulelor, algoritmul “Bubble Sort”


Metoda constă în parcurgerea elementelor şi schimbarea valorilor a două
elemente vecine care nu sunt în ordine, respectiv x i < xi+1. Parcurgerea se reia atâta
timp cât există două elemente care nu sunt în ordine. Se numeşte metoda bulelor
pentru că, în acest mod, comparând câte două elemente succesive, cel mai mare
element întâlnit la o parcurge trece spre dreapta până în poziţia lui finală.
De exemplu secvenţa de mai jos trece prin următoarele etape:
4, 7, 6, 5, 3 4, 6, 7, 5, 3 4, 6, 5, 7, 3 4, 6, 5, 3, 7

elementul 7, la o parcurgere, ajunge pe ultima poziţie, şi se reia parcurgerea


4, 6, 5, 3, 7 4, 5, 6, 3, 7 4, 5, 3, 6, 7

elementul 6, la a doua parcurgere, ajunge pe penultima poziţie, şi se reia


parcurgerea
4, 5, 3, 6, 7 4, 3, 5, 6, 7

elementul 5, la a treia parcurgere, ajunge pe antepenultima poziţie, şi se reia


parcurgerea
4, 3, 5, 6, 7 3, 4, 5, 6, 7

elementul 4, la a patra parcurgere, ajunge pe poziţia sa, şi se reia parcurgerea


3, 4, 5, 6, 7
La această parcurgere nu există elemente care nu sunt în ordine, deci algoritmul este
gata.

Algoritm bubble_sort (a [n]:sir, n:numeric);


i, k : numeric;
cod : boolean;
k ← 1
Repetă
cod ← adevărat;
Pentru i = 1 , n -k, 1 execută
Dacă a [ i ] > a [ i+1 ] atunci
cod ← fals;
schimb (a [i],a[i+1]);12
Sf dacă
Sf pentru;
k ← k + 1;
până când cod;
stop;

Ordinul de complexitate al algoritmului se calculează prin însumarea


parcurgerilor elementelor, respectiv, (n-1) + (n-2)+ … +1= n (n-1)/2. Complexitatea
este O(f((n2-n)/2))=O(n2).
10
Ordonarea crescătoare sau strict descrescătoare nu influenţează semnificativ algoritmii de
sortare. În prezentarea algoritmilor vom folosi doar ordonarea crescătoare.
11
O referinţă utilă pentru aceste metode este [8] pag 240-273.
12
Algoritmul de schimbare a valorilor a două variabile definit în 4.1..

57
Bazele algoritmilor

4.5.2.Sortarea prin selecţie


Metoda este uşor de înţeles pentru că are la bază algoritmul de determinare a
minimului dintr-un şir. Astfel la fiecare parcurgere se determină un element mai mic
din elementele de după poziţia i şi se aduce pe această poziţie valoarea prin
schimbarea valorilor. Pentru şirul 4, 7, 6, 5, 3 avem:

4, 7, 6, 5, 3 3, 6, 7, 5, 4 3,5,7,6,4 3,4, 7, 6,5 3, 4, 6,7,5 3, 4, 5, 7, 6

sirul devine ordonat 3, 4, 5, 6, 7.

Algoritm sort_selecţie (a [n]:sir, n:numeric);


i, j : numeric;
Pentru i = 1 , n-1, 1 execută
Pentru j = i + 1 , n, 1 execută
Dacă a [ i ] > a [ j ] atunci
schimb (a [i],a[j]);
Sf dacă
Sf pentru;
Sf pentru;
stop;

Complexitatea algoritmului de sortare prin selecţie se calculează prin însumarea


celor n-1 parcurgeri de la i + 1 la n, deci (n-1) + (n-2)+ … +1= n (n-1)/2.
Complexitatea este O(f((n2-n)/2))=O(n2).

4.5.3.Sortarea prin inserţie


Metoda constă în împărţirea şirului dat în două zone. O zonă A, care conţine
elemente ordonate şi o altă zonă B, care conţine celelalte elemente. Iniţial primul
element este în zona A, iar restul şirului în zona B. Algoritmul constă în trecerea
fiecărui element din zona B într-o poziţie în şirul A astfel încât acest şir să fie în
permanenţă ordonat. Şirul 4, 7, 6, 5, 3 are următoarea configuraţie în timpul, ordonării
(zona A negru/alb, zona B alb/negru):

4, 7, 6, 5, 3 3, 4, 7, 6, 5 3, 4, 5, 7, 6 3, 4, 5, 6, 7

Algoritm sort_inserţie(a [n]:sir, n:numeric);


i, k : numeric;
x : tip element şir;
Pentru i = 2 , n, 1 execută
x ← a [ i ];
k ← i – 1;
cât timp k > 0 and x < a [ k ] execută
a [ k + 1 ] ← a [ k ] {elementele şirului se}
k ← k – 1; {deplasează spre dreapta}
Sf cât timp
a [ k + 1 ] ← x;
Sf pentru;
stop;
Complexitatea algoritmului este O(f((n2-n)/2))=O(n2).

4.5.4.Sortarea prin numărare

58
Curs
Pentru fiecare element din vector se numără câte elemente mai mici decât el
există în şir. Păstrăm aceste valori într-un şir pentru fiecare element şi vom cunoaşte
poziţia lui în şirul ordonat.
Lăsăm ca exerciţiu verificarea pe exemplul nostru 4, 7, 6, 5, 3.
Datele acestui algoritm sunt: a (n) şirul iniţial, b(n) şirul ordonat şi Poz(n) şirul
poziţiilor.

Algoritm sort_numărare (a [n], b [n]:sir, n:numeric);


i, j : numeric;
poz [n] : sir_numeric;
Pentru i = 1 , n, 1 execută
poz [i] ← 1;
Sf pentru;
Pentru i = 2 , n, 1 execută
Pentru j = 1 , i - 1, 1 execută
Dacă a [ i ] < a [ j ] atunci
poz [j] ← poz [ j ] + 1;
altfel
poz [ i ] ← poz [ i ] + 1;
Sf dacă
Sf pentru;
Sf pentru;
Pentru i = 1 , n, 1 execută
b [ poz [i]] ← a [ i ];
Sf pentru;
stop;

Observaţii:
1) Algoritmul are unele inconveniente datorate volumului mare de date ce
trebuie păstrate.
2) Complexitatea este dată de două parcurgeri de şir şi respectiv cele două
structuri repetitive imbricate similare cu sortările anterioare, deci:
O(f((n2-n)/2+2n))=O(f((n2+3n)/2))= O(n2) .

Există metode de sortare care folosesc metode algoritmice evoluate. De aceea vom
enumera în continuare celelalte metode urmând ca la momentul potrivit să dăm şi
algoritmii de rezolvare a câtorva dintre acestea.
a) Sortarea prin metoda “Quick Sort” sau sortarea rapidă.
b) Sortarea prin inserţie binară.
c) Sortarea topologică.
d) Sortarea prin distribuire.

4.6.Interclasarea

forma practică:
Se dau două şiruri ale căror elemente sunt ordonate crescător. Să se obţină un alt
şir care să conţină toate elementele celor două şiruri ordonate crescător.

forma matematică:
Fie A = {x1, x2 , … , xn }, B = {y1, y2, … , ym } cu n şi respectiv m elemente.
Şirurile sunt ordonate conform aceleaşi relaţie de ordine “<” între elemente. Se cere un
şir C = {z1, z2, … , zn+m } unde zi sunt elementele lui A şi B în ordine crescătoare.
Metoda “brutală” ar fi concatenarea celor două şiruri şi apoi ordonarea lor. Dar
complexitatea acestui algoritm este O(f(n+m+(n+m)2 )) = O((n+m)2). Vom rezolva
problema prin interclasarea celor două şiruri cu complexitate O(n+m).

forma algoritmică:

59
Bazele algoritmilor
Idea algoritmului constă în compararea unui element ai din şirul A cu un element
bj din şirul b şi plasarea în şirul rezultat a valorii minime dintre acestea. Pentru a nu
trece peste dimensiunile şirurilor vom plasa pe poziţiile n+1 şi respectiv m+1 din şiruri
valoarea maximă din celălalt şir. Aceste valori poartă numele de santinele.
Algoritmul pune incrementează indicele poz din sir [n] şi îi atribuie
valoarea val, iar indicele ind corespunzător şirului din care a fost luată valoarea se
incrementează.

Algoritm pune (ind, val, poz, sir [n]);


poz ← poz + 1;
sir [poz] ← val;
ind ← ind + 1;
stop;

Algoritm interclasare (a[n+1], b[m+1], c[ m + n ]);


i, j, k : numeric;
a [n+1] ← b [ m ] +1;
b [m+1] ← a [ n ] +1;
i ← 1;
j ← 1;
Pentru k = 1 , m+n, 1 execută
Dacă a [ i ] < b [ j ] atunci
Pune (i, a[ i ], k, c );
altfel
Pune (j, b[ j ], k, c );
Sf dacă
Sf pentru;
stop;

Încercaţi să elaboraţi un alt algoritm pentru interclasare parcurgând şirurile până


la epuizarea unuia dintre ele, apoi, completând şirul soluţie cu elementele din celălalt
şir.

4.7.Recursivitatea

forma practică:
Problemele practice care necesită prelucrarea recursivă sunt acele probleme care
prin definiţia lor se referă la ele însele. De regulă recursivitatea se foloseşte la
rezolvarea problemelor:
- Care se definesc printr-o funcţie recursivă, f(n)=Expresie(f (n-1)).
- Care au datele organizate pe structuri recursive (vezi cap. Structuri de date).
- Care folosesc metode de rezolvare cu caracter recursiv (Backtracking, Divide
et Impera).

forma matematică:
În matematică definiţia funcţiilor recursive se face astfel:
Fie A o mulţime şi f : A → A. Spunem că o funcţie este recursivă dacă există o
funcţie
R : A → A, astfel încât f(x)= R(R( … R(x))), pentru orice x din A.
N

(compunerea de n ori, n
ri
o

finit).
Un exemplu simplu de definiţie recursivă este funcţia factorial fact: N → N
 1, pt .n = 0;
fact ( n ) = 
n • f (n −1), pt .n ≥1.
Problema înmulţirii iepurilor, sau şirul lui Fibonacci se poate transcrie sub forma
unei funcţii recursive FIB : N → N dată de relaţia:

60
Curs
 1, n = 1 ∨ n = 0
FIB ( n) = 
FIB ( n −1) + FIB ( n − 2), n > 1.

forma algoritmică:
Problema recursivităţii în cadrul algoritmilor se pune doar atunci când lucrăm cu
subalgoritmi care conţin referiri, de fapt auto referiri, la propriul subalgoritm.
Spunem că un subalgoritm este recursiv dacă în definirea sa se auto apelează. În
general rezolvarea unei probleme se realizează în două moduri:
- iterativ, pas cu pas; presupune utilizarea secvenţelor repetitive cunoscute,
împreună cu structurile liniare şi alternative, în rezolvarea problemelor prin
etape succesive.
- recursiv, cu revenire; presupune ca un subprogram apelant, care se
autoapelează, să rămână activ până la revenirea din programul apelat, chiar
dacă acest apel s-a făcut de mai multe ori.
Există două modalităţi de apel recursiv:
- recursivitate directă; când un subalgoritm se apelează chiar din corpul său.
- recursivitate indirectă; când un subalgoritm apelează un alt subalagoritm care
apoi apelează subalgoritmul iniţial. Deci apelul se face printr-unul sau mai
mulţi intermediari.
Deoarece un apel recursiv este de fapt o structură asemănătoare cu o structură
repetitivă un subalgoritm recursiv trebuie că conţină obligatoriu o <Condiţie> de
oprire a apelului recursiv. Atunci forma generală a unui algoritm recursiv simplu este:

Algoritm recursiv ( {parametrii} );


{variabile locale}
{Secvenţa de instrucţiuni S1}
Dacă not <Condiţie> atunci
recursiv ( {parametrii} );
altfel
{Secvenţa de instrucţiuni S2}
Sf dacă
{Secvenţa de instrucţiuni S3}
stop;

Apel 1 Apel 2 Apel 3 Apel 4


Valorile variabilelor locale şi V1 V2 V3 V4
ale parametrilor la apel
Not <Condiţie> Adevărat Adevărat Adevărat Fals
Secvenţa de instrucţiuni S1 S1 S1 S1
efectuată S2
Starea algoritmului Activ Activ Activ Activ
La apelul recursiv se realizează de fapt o structură repetitivă care execută secvenţa S1
pentru valori succesive V1, V2, V3, V4 ale variabilelor locale.
Valorile variabilelor locale şi V1 V2 V3 V4
ale parametrilor la revenirea în
algoritmul apelant
Instrucţiune ce urmează a fi Secvenţa Secvenţa S3 Secvenţa S3 Secvenţ
efectuată dupa daca S3 a S3
Secvenţa de instrucţiuni S3 S3 S3 S3
efectuată
Starea algoritmului Inactiv Inactiv Inactiv Inactiv
La revenirea recursivă în algoritmii apelanţi se realizează de fapt o altă structură repetitivă
care execută secvenţa S3 pentru valori succesive V4, V3, V2, V1 ale variabilelor locale.
Secvenţa S2 se execută o singură dată pentru valorile V4, la ultimul apel.

61
Bazele algoritmilor
Pentru a înţelege uşor principiul de funcţionare a unui algoritm recursiv reţineţi
următoarele:
a) Toţi algoritmi apelaţi recursiv rămân activi până la revenirea din algoritmul
apelat.
b) Variabilele locale ale unui algoritm apelant se păstrează până la revenirea din
cel apelat nealterate.
c) La revenirea din algoritmul apelat se continuă cu următoarea instrucţiune a
algoritmului apelant.
d) Parametrii fac legătura între algoritmul apelant şi cel apelat la fel ca într-un
apel de subalgoritm elementar.
Să urmărim care este evoluţia algoritmului dacă apelul recursiv, conform
condiţiei, s-ar efectua de 4 ori.

Problemă:

Să se afişeze un cuvânt dat, care se încheie cu spaţiu, citit de la dreapta la stânga.


Să se precizeze numărul de caractere ale cuvântului.

Exemplu: cuvântul “facultate ” va trebui afişat “ etatlucaf”.

Algoritm cuvânt_recursiv ( nr : numeric );


c : caracter;

Citeşte c;
Dacă c<> “ “ atunci

cuvant_recursiv ( nr + 1 );

altfel

scrie (“ Numărul de caractere este: “, nr)


Sf dacă
Scrie c;
stop;

Algoritm principal;
cuvânt_recursiv ( 0 );
stop;

Să completăm tabelul de parcurgere a apelului recursiv generat prin apelul


algoritmului cuvânt_recursiv ( 0 )din Algoritm principal pentru
cuvântul “NUC“.
În algoritmul descris mai sus a existat un singur punct în care am realizat apelul
recursiv. Astfel există doar două posibilităţi, apelul recursiv şi revenirea din
recursivitate. Acest tip de recursivitate se numeşte recursivitate liniară.
Recursivităţile liniare se mai numesc şi iterative. Un exemplu de recursivitate liniară
este factorialul.
Dacă într-un algoritm există mai multe puncte în care se apelează algoritmul recursiv
atunci procedeele de lucru devin mult mai interesante, iar revenirea la algoritmul
apelant permite ramificarea algoritmului, respectiv parcurgerea arborescentă. Acest tip
de recursivitate se numeşte recursivitate neliniară sau arborescentă. Pentru
exemplificarea acestei recursivităţi puteţi considera şirul lui Fibonacci, care se
defineşte prin două apeluri recursive FIB(n-1) şi respectiv FIB(n-2). Probleme mai
interesante care folosesc recursivitatea vom întâlni în capitolele următoare.

cuvânt_ cuvânt_ cuvânt_ cuvânt_


recursiv ( 0 ) recursiv ( 1 ) recursiv ( 2 ) recursiv ( 3 )

62
Curs
Valorile variabilelor c = “N” c = “U” c = “C” c=“ ”
locale şi ale parametrilor nr = 0 nr = 1 nr = 2 nr = 3
la apel
c<>“ “ Adevărat Adevărat Adevărat Fals
Secvenţa de instrucţiuni Citeşte(c) Citeşte(c) Citeşte(c) Citeşte(c)
efectuată Scrie (nr)
Starea algoritmului Activ Activ Activ Activ

Valorile variabilelor c = “N” c = “U” c = “C” c=“ ”


locale şi ale parametrilor nr = 0 nr = 1 nr = 2 nr = 3
la revenirea în algoritmul
apelant
Instrucţiune ce urmează a Scrie (c) Scrie (c) Scrie (c) Scrie (c)
fi efectuată
Secvenţa de instrucţiuni “ CUN” “ CU” “ C” “ ”
efectuată
Starea algoritmului Inactiv Inactiv Inactiv Inactiv

4.8.Funcţii. Funcţii recursive.


4.8.1. Funcţii. Subalgoritm de tip funcţie.
Un subalgoritm care prin numele său returnează o valoare calculată în corpul
subalgoritmului se numeşte funcţie sau subalgoritm de tip funcţie. O funcţie este
asemănătoare unui subalgoritm având următoarele caracteristici proprii:
- Numele subalgoritmului de tip funcţie este o variabilă de un anumit tip;
- Apelul unei funcţii se face odată cu apelul valorii sale, deci în cadrul unei
expresii;

Exemple:
1) Funcţia care returnează valoarea maximă dintre două numere reale se defineşte
astfel:

Funcţia max ( a, b: numeric ): numeric;


Dacă a > b atunci
Max ← a;
altfel
Max ← b;
Sf dacă
stop;

Algoritm principal;
Citeşte (a, b);
Scrie max( a, b );
stop;
Max – este numele funcţie, este de tip numeric şi returnează cea mai mare din cele
două valori a şi b.

4.8.2. Funcţii recursive.


Dacă valoarea funcţiei se calculează folosind aceeaşi funcţie ea se numeşte
funcţie recursivă.

2) Un exemplu de funcţie recursivă este algoritmul lui Euclid, prin


Funcţia cmmdc, definită astfel:

63
Bazele algoritmilor

Funcţia cmmdc ( a, b: numeric ): numeric;


Dacă b = 0 atunci
cmmdc ← a;
altfel
cmmdc ← cmmdc (b, (a mod b) );
Sf dacă
stop;

Algoritm principal;
Citeşte (a, b);
Scrie (cmmdc ( a, b ));
stop;

Observaţie: În cazul funcţiilor recursive calculul valorii funcţiei într-o relaţie


recursivă se efectuează la revenirea în programele apelante. Tabelul de verificare a
acestei funcţii pentru a=24 şi b=15 este:

Paşii/ algoritmul activ a b Cmmdc


Pas 1/ principal 24 15 -
Pas 2/ pricipal 24 15 -
Pas 1/ cmmdc (24, 15) 24 15 -
Pas 1/ cmmdc (15, 9) 15 9 -
Pas 1/ cmmdc (9, 6) 9 6 -
Pas 1/ cmmdc (6, 3) 6 3 3
Pas 2/ cmmdc (15, 9) 9 6 3
Pas 2/ cmmdc (24, 15) 15 9 3
Pas 3/ principal 24 15 3

Următoarele capitole vor pune în evidenţă diverse situaţii în care algoritmii


recursivi şi funcţiile recursive rezolvă probleme prin diverse metode de reprezentare a
datelor sau metode de rezolvare a problemelor algoritmice.

64
Curs

4.9.Verificarea cunoştinţelor

E.1. Secvenţa de algoritm:


b,s : sir_de_caractere; a : caracter; i : numeric
b ← ‘NU’;
a ← ‘D’;
s ← ‘’; {s atribuie secvenţa vidă}
pentru i = 0, 2, 1 execută
s ← b + s + a;
{ + este operaţia de concatenare}
sf pentru;
scrie (s);

Are ca efect afişarea şirului :


a). ‘DNUDNUDNU’
b). ‘NUDNUDNUD’
c). ‘NUNUNUDDD’
d). ‘DDDNUNUN’

E.2. Care este valoarea afişată a funcţiei recursive test, pentru a=24 şi b=5:

Funcţia test ( a, b: numeric ): numeric;


Dacă a < b atunci
test ← a;
altfel
test ← test (a-b, b);
Sf dacă
stop;

Algoritm principal;
Citeşte (a, b);
Scrie ( test ( a, b ));
stop;
a) 1 b) 2 c) 3 d) 4

E.3. Algoritmii de mai jos doresc să calculeze produsul cartezian M x M x…x M,


de n ori, pentru mulţimea M = {1, 2, 3, …, m}, recursiv. Care dintre ei este corect?
(Precizăm că n şi m sunt cei din enunţul problemei iar şirul x conţine un element (x1,
x2, …, xn ) al produsului cartezian).

a)
Algoritm Cartezian ( i : numeric );
k : numeric;
Pentru k = 1 , m, 1 execută
x [ i ] ← k;
Dacă i < n atunci
cartezian ( i + 1 );
altfel
scrie_şir ( x , n);13
Sf dacă;
Sf pentru;
stop;

Algoritm principal;

13
Algoritmul de scriere a elementelor unui şir, descris în capitolele anterioare.

65
Bazele algoritmilor
Citeşte ( m );
Citeşte ( n );
Cartezian ( 1 );
stop;

b)
Algoritm Cartezian ( i : numeric );
k : numeric;
Pentru k = 1 , m, 1 execută
x [ i ] ← k;
Dacă i < n atunci
cartezian ( i + 1 );
Sf dacă;
scrie_şir ( x , n);
Sf pentru;
stop;

Algoritm principal;
Citeşte ( m );
Citeşte ( n );
Cartezian ( 1 );
stop;

c)
Algoritm Cartezian ( i : numeric );
k : numeric;
Pentru k = 1 , m, 1 execută
x [ i ] ← k;
Dacă i < n atunci
cartezian ( i + 1 );
Sf dacă;
Sf pentru;
scrie_şir ( x , n);
stop;
Algoritm principal;
Citeşte ( m );
Citeşte ( n );
Cartezian ( 1 );
stop;
d)
Algoritm Cartezian ( i : numeric );
k : numeric;
Pentru k = 1 , m, 1 execută
x [ i ] ← k;
Dacă i < n atunci
cartezian ( i + 1 );
Sf dacă;
Sf pentru;
stop;

Algoritm principal;
Citeşte ( m );
Citeşte ( n );
Cartezian ( 1 );
scrie_şir ( x , n);
stop;

66
Curs
E.4. Valorile unui şir a(i), i=1,7 sunt iniţial: 3, 7, 2, 1, 0, 6, 2. După execuţia cărei
secvenţe şirul se transformă în 7, 2, 1, 0, 6, 2, 3 (transformarea circulară):
a) c)
x ← a(1); x ← a(1);
pentru i = 1, 6, 1 execută pentru i = 1, 6, 1 execută
a(i+1) ← a(i); a(i) ← a(i+1);
sf pentru; sf pentru;
a (7) ← x; a (7) ← x;

b) d)
x ← a(1); x ← a(1);
pentru i = 2, 7, 1 execută pentru i = 7, 2, -1 execută
a(i) ← a(i-1); a(i) ← a(i-1);
sf pentru; sf pentru;
a (7) ← x; a (7) ← x;

E.5. Precizaţi dacă următorul algoritm furnizează corect rezultatul problemei:


“determinaţi dacă numărul x, x>2, este un număr prim?”.

Algoritm Ghici;
d, x : numeric;
prim : boolean;
citeşte ( x );
pentru d = 2, SQRT(x), 1 exectă
dacă (x mod d) = 0 atunci prim : = False;
altfel prim: = True;
sf dacă;
sf pentru;
Dacă prim atunci scrie (x, ’este prim’)
altfel scrie (x, ‘NU este prim’);
Sf dacă;
Stop;
a) Da, este corect pentru orice număr x>2;
b) Este corect doar pentru numere prime şi numerele pătrate perfecte;
c) Nu este corect pentru nici un număr x>2;
d) Nu este corect pentru numerele pare.

P.1. Scrieţi un algoritm care permite extragerea cifrelor unui număr natural într-
un şir. Scrieţi un algoritm liniar şi unul recursiv.
Exemplu: n= 35621, cifrele sunt 3, 5, 6, 2, 1

P.2. N copii sunt aşezaţi în cerc şi numerotaţi de la 1 la n. Ei vreau să decidă cine


va merge după o minge, apelând la numărătoarea binecunoscută cu “Ala bala
portocala …”. Ştiind că:
- secvenţa de numărat conţine k silabe,
- numărătoarea începe de la 1,
- fiecare silabă corespunde numărării unui copil,
- copilul care este numărat pe poziţia k este eliminat şi numărătoarea continuă
de la cel eliminat,
- numărătoarea continuă până rămâne un singur copil.
Determinaţi care este copilul care va merge după minge.
Exemplu: n = 5, k =3 ,
eliminarea se face în ordinea 3, 1, 5, 2 şi rămâne copilul 4.

P.3. Se dă un număr natural n. Determinaţi cel mai mare număr natural scris cu
toate cifrele lui n.
Exemplu: n=123532, nmare=533221.

67
Bazele algoritmilor

P.4. Calculaţi minimul dintre elementele unui şir printr-o singură parcurgere a
elementelor sale.

P.5. Determinaţi cel mai mare număr care se poate obţine dintr-un alt număr prin
eliminarea unei singure cifre, fără a modifica ordinea cifrelor.
Exemplu: n=53429,
eliminând cifra 3 de poziţia 2 se obţine cel mai mare număr 5429.

P.6. Se introduc numere reale până la introducerea valorii 0. Calculaţi numărul şi


suma valorilor negative şi respectiv a celor pozitive.
Exemplu: succesiunea –3 5 2 -6 4 0 are ca rezultat:
suma celor 3 numere pozitive este 11
suma celor 2 numere negative este -9

P.7. Se dă un număr n. Să se construiască cel mai mare număr format din cifrele
distincte ale lui n.
Exemplu: n=46372824,
Ce mai mare număr este 876432

P.8. Fişierul de tip text, “date.in” conţine pe prima linie numărul de elemente ale
unui şir iar pe a doua linie elementele şirului separate prin câte un spaţiu. Să se
ordoneze folosind metoda BubbleSort elementele şirului şi să se scrie în fişierul
“date.out”, pe fiecare linie câte un singur element.
Exemplu:
Dacă fişierul “date.in” conţine:
5
45 78.3 –3 -12.4
Atunci fişierul “date.out” va conţine
-12.4
-3
45
78.3

P.9. Un pictor a realizat un tablou, format din m x n puncte albe şi negre, de


aceeaşi mărime, dispuse sub forma unui dreptunghi. El caută cea mai mare
suprafaţă, de formă dreptunghiulară, care să conţină doar puncte de aceeaşi
culoare (fie numai albe, fie numai negre).
Exemplu:
Reprezentăm tabloul sub forma unei matrice cu m linii şi n coloane, cu elemente
0 şi 1, corespunzătoare culorilor alb şi negru. Pentru matricea:
m= 8, n=4
10101011
11001011
11010011
11001111
Cea mai mare suprafaţă este de puncte negre şi are coordonatele (7,1) şi (4.8), 8
puncte.

P.10. Scrieţi algoritmul recursiv care calculează “răsturnatul” unui număr natural
n dat.
Exemplu: pentru n=14623, nrăsturnat=32641

4.10. Răspunsuri.

E.1. c), E.2. d), E.3. a), E.4. c), E.5. b).

68
Curs

Pentru a uşura posibilitatea de verificare a algoritmilor pentru problemele


P.1. … P.10. soluţiile lor se află în ANEXA1, sub formă de programe în limbaj
PASCAL. Numele fişierului corespunzător problemei este C<nr.capitol>P<nr.
problemă>.pas.
Exemplu: C4P1.pas

69
Bazele algoritmilor

5. Structuri de date
Elementele de bază în elaborarea unui algoritm sunt datele, de intrare sau de
ieşire şi respectiv paşii de rezolvare. Dacă în capitolul precedent am făcut referiri la
diverse modalităţi de lucru cu privire la transformarea paşilor unei probleme din formă
practică, în formă matematică şi apoi algoritmică în acest capitol ne referim la
modalităţi de organizare şi structurare a datelor.
Organizarea şi structurarea datelor utilizate în programare presupun de obicei
lucrul cu tabele de informaţii. Aceste tabele de informaţii conţin atât valori numerice
cât şi alte tipuri de valori codificate, de regulă, tot sub formă numerică. Corecta
utilizare a reprezentării datelor cu ajutorul calculatorului presupune cunoaşterea unor
relaţii structurale de organizare a acestora.
- Dacă dorim să prelucrăm o listă liniară de elemente, folosim de regulă un şir.
- Dacă tabelul de date este bidimensional folosim o matrice.
- Dacă între date există relaţii ierarhice de subordonare sau ramificate ar putea fi
vorba de o structură arborescentă.
- Dacă relaţiile de legătură sunt multiple, cu diverse conexiuni şi legături putem
folosi un graf.
Toate aceste modele se bazează pe modele matematice, care din punct de vedere
teoretic dispun de forme de reprezentare şi operaţii specifice. Problema abordată în
acest capitol se referă, nu la modelul matematic al structurilor de date ci la
proprietăţile statice sau dinamice, la metodele de alocare şi gestiune, la modul de
reprezentare şi la algoritmi eficienţi în prelucrarea acestora.
Reprezentarea datelor cu ajutorul calculatorului presupune codificarea acestora
şi păstrarea în memorie sau pe suport extern (disc, hârtie, bandă magnetică) sub formă
de fişiere. În funcţie de modul de organizare şi de specificul limbajului de programare
formatul fişierelor diferă, dar conţinutul lor este de regulă acelaşi. În acest capitol nu
ne vom referi la tipurile de fişiere specifice unui limbaj de programare ci la câteva
categorii de date structurate cu foarte largă aplicabilitate.
Categoriile de date structurate, în funcţie de omogenitatea datelor pe care le
conţin, se împart în:
- omogene (toate componentele au acelaşi tip); tipurile de date aferente sunt
numite tablou, mulţime şi fişier;
- heterogene (elementele unei date au de obicei componente diferite ca tip);
ele aparţin tipului de date înregistrare.
Din categoria datelor structurate o categorie aparte sunt listele.

5.1. Liste
O listă (listă liniară) am definit-o din punct de vedere matematic în 2.3.2.1, pag.
21, şi am precizat principalele operaţii care se pot efectua asupra lor. În acest paragraf
vom prezenta modalităţi de reprezentare în memorie, metode de alocare a spaţiului pe
disc sau în memorie precum şi câţiva algoritmi specifici de prelucrare a listelor.
Dacă listele, din punct de vedere matematic, reprezintă o succesiune de elemente,
la reprezentarea lor vom ţine cont şi de informaţii legate de structura listei. Aceste
informaţii conţin şi elemente de legătură, de conexiune cu elementele învecinate.
Fiecare element al unei liste liniare ocupă o zonă de memorie (locaţie) formată din
două componente: INFORMAŢIA şi LEGĂTURA. Legătura poate să precizeze
elementul predecesor al elementului curent, cel succesor sau legături duble, chiar
multiple.
Distingem următoarele tipuri de liste liniare:
a) lista liniară simplu înlănţuită
b) Lista liniară dublu înlănţuite
c) Lista circulară.
Pentru o listă simplu înlănţuită, cu o singură legătură, principalele caracteristici
sunt:

70
Curs
- Elementele listei sunt aşezate în ordine de la capul listei (numit prim
element) la coada listei (numit ultim element);
- Elementele listei sunt legate între ele prin adresa elementului care urmează;
- O listă permite determinarea predecesorului / succesorului unui element
pentru oricare din elemente.
Memorarea listelor se face prin alocarea unor zone de memorie pentru elementele
acesteia în două moduri:
a) Alocarea secvenţială constă în memorarea elementelor listei în locaţii aflate
la adrese succesive în memorie, pornind de la o adresă de bază, adresa primului
element din listă. Fiecare element din listă poate fi identificat conform ordinii în listă.
Un exemplu, pe care l-am studiat, de astfel de liste, sunt tablourile. Fiecare
element se identifică prin indicele său în tablou, iar informaţia se află în locaţia T(i1,
i2,…,in). O listă liniară simplu înlănţuită va fi memorată şi prelucrată folosind siruri
(vectori), poziţia unui element în listă fiind dată de indicele corespunzător din şir.
b) Alocarea înlănţuită (dinamică) presupune ca fiecărui element din listă să i se
aloce o zonă corespunzătoare în care se păstrează INFormaţia şi adresa de LEGătură
la care se află următorul element, doar în momentul folosirii elementului din listă, sub
forma:

Cap IN LEG IN LEG INF LEG INF LE Coada


Prim F 16 F 80 44 G Ultim
Nil
0 0 16 80 44 44

Sub fiecare locaţie am precizat adresa la care se află şi valorile corespunzătoare


pentru primul şi ultimul element. Se observă că locaţiile de memorie nu au adrese
succesive. Avantajul alocării înlănţuite este că se foloseşte doar zona de memorie
necesară şi se poate folosi orice zonă liberă la un moment dat.
Operaţii elementare asupra listelor:
- Inserarea unui element, într-un anumit loc, în listă (la cap, la coadă, în
interiorul listei);
- Ştergerea unui element din listă (eliminarea din listă);
- Parcurgerea elementelor unei liste, deci accesul la elementele sale, fie prin
poziţia în listă fie prin trecerea secvenţială de la un element la altul căutând
valoarea unei informaţii sau o anumită adresă.
- Concatenarea listelor.

5.2. Tipuri de liste


În funcţie de modul de înlănţuire a elementelor unei liste liniare distingem
următoarele tipuri de liste:
a) liste liniare simplu înlănţuite – au o singură adresă de legătură.
- Stiva (lista LIFO, Last In First Out, ultimul intrat va fi primul ieşit)
- Coada (lista FIFO, First In First Out, primul intrat va fi primul ieşit)
- Lista circulară
b) liste liniare dublu înlănţuite – au două adrese de legătură.
5.2.1. Stiva
Stiva (stack în engleză) este o listă liniară simplu înlănţuită cu proprietăţile:
1) Inserarea unui element se face numai la capul stivei, numit vârful stivei.
2) Ştergerea unui element se face numai la vârful stivei.
3) Legătura elementului din coada stivei, numit baza stivei este nil (nimic).

Vârf INF LEG INF LEG INF LEG INF LEG Baza
Pri 16 80 44 Nil Ultim
m
70 70 16 80 44 44

71
Bazele algoritmilor
Un exemplu clasic de stivă este “stivuirea unor cutii care au un anumit conţinut”.
Este evident că doar asupra cutiei din vârful stivei putem să acţionăm.
Stivele permit trei operaţii elementare: inserarea la vârf, ştergerea de la vârf şi
parcurgerea.
În descrierile algoritmilor, pentru operaţiile pe stivă, vom folosi în reprezentarea
generală a unui element dintr-o listă tipul de date articol care are structura:
Element = articol
leg: adresa_element;
inf: informaţia_de_un_anumit_tip;
unde
Adresa_element = adresa_unei_zone_ de_memorie
Vom folosi variabilele

p, q, vârf : adresa_element;

- Prin leg [p] şi inf [p] vom înţelege legătura şi informaţia aflată la adresa p.
- leg [p] este de tip adresa_element, iar inf [p] este de tip
informaţia_de_un_anumit_tip.
- Pentru stiva vidă avem vârf = nil.
- Alocarea unei zone noi de memorie se realizează cu aloc ( adresa_element)
- Disponibilizarea unei zone de memorie se realizează cu disp
(adresa_element).

a) Inserarea unui element în vârful stivei (deci vârf are o anumită valoare)

Aloc (p); {alocarea memorie pentru noul element}


inf [p] ← <expresie>; {atribuirea valorii zonei de informaţie}
leg [p] ← vârf; {adresa_de_legătură a noului element este vârf}
vârf ← p; {noul vârf se află acum la noua adresă p }

b) Ştergerea unui element din vârful stivei (deci vârf are o anumită valoare)

P ← vârf; {se salvează adresa vârfului pentru a nu se pierde}


Vârf ← leg[p]; {noua adresă a vârfului este legătura celui vechi}
Disp ( p ); {se disponibilizează (şterge) zona de adresă p}
c) Parcurgerea elementelor unei stivei pornind din vârf.

P ← vârf; {se salvează adresa vârfului pentru a nu se pierde}


Cât timp p <> nil execută
{condiţia poate fi schimbată după cerinţele de parcurgere}
{Operaţie asupra elementului de la adresa p}
p ← leg[p]; {noua adresă a elementului p}
sf cât timp;

5.2.2. Coada
Coada (coada de aşteptare) este o listă liniară simplu înlănţuită cu proprietăţile:

1) Inserarea unui element se face numai la un capăt al listei, numit ultim


element.
2)Ştergerea unui element se face la celălalt capăt al listei, numit prim element.
3)Legătura ultimului element al listei, este nil (nimic).

Cap INF LEG INF LEG INF LEG INF LEG Coadă
Pri 16 80 44 Nil Ultim
m
70 70 16 80 44 44

72
Curs

Un exemplu clasic de coadă este “Trecerea vagoanelor, pe o linie de cale ferată,


printr-un tunel, într-un singur sens”. Este evident că vagoanele intră şi ies în aceeaşi
ordine. Deci locomotiva, vagonul 1, 2, etc.
Cozile permit trei operaţii elementare: inserarea la coadă (ultim), ştergerea de la
cap (prim) şi parcurgerea.
În descrierile algoritmilor, pentru operaţiile asupra cozilor, vom folosi în
reprezentarea generală aceleaşi notaţii ca în cazul stivelor:
Vom folosi variabilele

p, q, prim, ultim : adresa_element;

- Pentru iniţializarea cozii avem:


aloc (prim);
leg [prim] = nil;
ultim = prim;.
- Alocarea unei zone noi de memorie se realizează cu aloc ( adresa_element)
- Disponibilizarea unei zone de memorie se realizează cu disp
(adresa_element).

a) Inserarea unui element în coadă, deci ultim are o anumită valoare.

Aloc (p); {alocarea memorie pentru noul element}


inf [p] ← <expresie>; {atribuirea valorii zonei de informaţie}
leg [p] ← nil; {p fiind ultimul element, adresa de legătură este nil}
leg [ultim] ← p; {adresa_de_legătură a ultimului element este noul p}
ultim ← p; {noul vârf se află acum la noua adresă p }

b) Ştergerea unui element din coadă, deci prim are o anumită valoare)

P ← prim; {se salvează adresa lui prim pentru a nu se pierde}


prim ← leg[prim]; {noua adresă a lui prim este legătura sa}
Disp ( p ); {se disponibilizează (şterge) zona de adresă p}

c) Parcurgerea elementelor unei cozi pornind de la prim.

P ← prim; {se salvează adresa prim pentru a nu se pierde}


Cât timp p <> nil execută
{condiţia poate fi schimbată după cerinţele de parcurgere}
{Operaţie asupra elementului de la adresa p}
p ← leg[p]; {noua adresă a elementului p}
sf cât timp;

5.2.3. Lista circulară


Lista circulară este o listă liniară simplu înlănţuită, definită în mod similar cu
coada. În plus are proprietatea că:
leg [ ultim ] = prim;
Pe lângă operaţia de parcurgere care este similară cu cea de la coadă, operaţiile
de inserare şi ştergere se pot efectua la orice adresă q convenabilă.
a) Inserarea după elementul de la adresa q.

Aloc (p); {alocarea memorie pentru noul element}


inf [p] ← <expresie>; {atribuirea valorii zonei de informaţie}
leg [p] ← leg [q] ; {adresa de legătură a lui p este cea a lui q}

73
Bazele algoritmilor
leg [q] ← p; {adresa_de_legătură a lui q este noul p}

d) Ştergerea elementului de după elementul de la adresa q (deci de la leg [q]).

P ← leg[q]; {se salvează adresa lui leg [q] pentru a nu se pierde}


leg[q] ← leg[p]; {noua legătură a lui q este legătura lui p}
Disp ( p ); {se disponibilizează (şterge) zona de adresă p}

5.2.4. Lista dublu înlănţuită

Lista dublu înlănţuită este o listă în care un element este format din INFormaţie
şi două adrese de legătură, înspre elementul PREdecesor şi respectiv SUCcesor. Lista
dublu înlănţuită are două capete pe care le vom nota la fel ca în cazul cozii cu prim şi
respectiv ultim.

Cap Nil INF SUC PRE INF SUC PRE INF SUC Coadă
Prim 16 70 44 16 Nil Ultim
70 70 16 44 44

Definiţia unui element al listei dublu înlănţuite:

Element = articol
pre: adresa_element;
suc: adresa_element;
inf: informaţia_de_un_anumit_tip;

Pe lângă operaţia de parcurgere care este similară cu cea de la coadă sau stivă, cu
diferenţa că deplasarea se face spre PRE sau spre SUC, operaţiile de inserare şi
ştergere se pot efectua la orice adresă q convenabilă.

a) Inserarea înaintea elementului de la adresa q.

Aloc (p); {alocarea memorie pentru noul element}


inf [p] ← <expresie>;{atribuirea valorii zonei de informaţie}
pre [p] ← pre [q] ; {legătura pre a lui p este legătura pre a lui q}
suc [p] ← q ; {suc lui p este q}suc [ pre [p]] ← p;
{predecesorul lui p are ca succesor pe p}
pre [q] ← p; {adresa_de_legătură a lui q este noul p}
Verificaţi pentru lista din figura de mai sus presupunând noua adresă a lui p=60
şi q=16.

b) Ştergerea elementului aflat la adresa succesorului lui q (deci de la suc [q]).

P ← suc[q]; {se salvează adresa lui suc [q] pentru a nu


se pierde}
suc[q] ← suc[p]; {noul succesor a lui q este lui p}
pre [suc[p]] ← q; { succesorul lui p are ca predecesor pe p}
Disp ( p ); {se disponibilizează (şterge) zona de adresă p}

Verificaţi pentru lista din figura de mai sus presupunând q=70.

74
Curs
Listele dublu înlănţuite se folosesc la reprezentarea arborilor binari, despre care
vom vorbi în capitole speciale din cursurile următoare.
Pentru exemplificare propunem spre rezolvare problemele de la secţiunea de
verificare, soluţiile acestora fiind studiate în manual folosind implementarea în limbaj
Pascal.

5.3. Verificarea cunoştinţelor

P.1. Se dau într-un fişier text numele şi media studenţilor la un examen. Creaţi o
stivă cu datele din fişierul de intrare.
P.2. Se dau într-un fişier text numele şi media studenţilor la un examen. Creaţi o
listă înlănţuită cu studenţii ordonaţi după media la examen.
P.3. Se dau într-un fişier text numele şi media studenţilor la un examen. Creaţi o
coadă de aşteptare cu studenţii şi afişaţi studenţii care au mediile cuprinse între 9 şi 10
şi respectiv mai mici decât 9.
P.4. Să se determine dacă un graf este ciclic sau aciclic.
P.5. Problema prezintă o modalitate de parcurgere a unui graf conex, numită
Dept First, adică în adâncime. Metoda constă în parcurgerea pornind de la un vârf
oarecare şi vizitarea vârfurilor în adâncime.
Exemplu: Graful definit prin perechile (1,2), (1,3), (1,4), (2,5), (3,5), (4,6), (5,7),
(6,7), (6,8) este parcurs DF în ordinea: 1, 2, 5, 3, 7, 6, 4, 8 . Reprezentaţi graful şi
urmăriţi parcurgerea.

5.4. Răspunsuri.

Soluţiile la probleme în, ANEXA1.

75
Bazele algoritmilor

6. Anexa 1
C4P1.pas
program cifre_număr;
type sir=array[1..100] of integer;
var a:sir;
n:longint;
i, k:byte;

Procedure scrie_sir( a:sir; n:byte);


Var i: byte;
Begin
for i:= n downto 1 do
writeln(a[i],' ');
end;

Procedure cifre (n: longint; var a:sir; var m:byte);


begin
i:=1;
repeat
a[i]:=n mod 10;
n:=n div 10;
i:=i+1
until n=0;
m:=i-1;
end;

begin
write('dati n ');readln(n);
cifre (n, a, k);
scrie_sir (a, k);
end.

C4P2.pas
program copii;
var i,k,p,n,j,l,nr:integer;
x:array[1..100]of boolean;
begin
write('dati nr de copii si numaratoarea:');
readln(n,p);
i:=0;
for j:=1 to n do
x[j]:=true;
repeat
k:=0;
repeat
i:=i+1;
if x[i] then k:=k+1;
if i>=n then i:=0;
until k=p;
if i=0 then x[n]:=false
else x[i]:=false;
nr:=0;
for j:=1 to n do
if x[j] then
begin

76
Curs
nr:=nr+1;
l:=j;
end;
until nr=1;
write('In joc a ramas copilul ',l);
end.

C4P3.pas
program max_din_cifre;
type sir=array[1..100] of byte;
var n,p,i:byte;
nr, m:longint;
a:sir;

Procedure cifre (n: longint; var a:sir; var m:byte);


begin
i:=1;
repeat
a[i]:=n mod 10;
n:=n div 10;
i:=i+1
until n=0;
m:=i-1;
end;

Procedure bubble_sort (var a: sir; n: byte);


var cod:boolean;
begin
repeat {Ordonarea cifrelor cu
metoda}
cod:=true; {bubble sort}
for i:=1 to n-1 do
if a[i]<a[i+1] then
begin
p:=a[i];
a[i]:=a[i+1];
a[i+1]:=p;
cod:=false;
end
until cod;

end;

begin
write('numarul=');readln(nr);
cifre (nr,a,n);
bubble_sort (a, n);
m:=0;
i:=1;
repeat {formarea noului
numar}
m:=m*10+a[i];
inc(i);
until i>n;
writeln(m);
readln;
end.

77
Bazele algoritmilor

C4P4.pas
program minim;
var a:array[1..50] of longint;
i:byte;
n,n1:longint;
begin
write(' nr. elem sir:');readln(n);
write('introduceti un numar ');
readln(a[1]);
n1:=a[1];
i:=2;
repeat
begin
write('introduceti un numar ');
readln(a[i]);
if a[i]<n1 then
n1:=a[i];
end;
i:=i+1;
until i>n;
write('numarul minim este ',n1);
readln;
end.

C4P5.pas

program maxim_fara_o_cifra;
var nr,n,x,y,c,i: longint;
a:array[1..20] of byte;
cod:boolean;
begin
write('Introduceti numarul ');readln(nr);
i:=1;
x:=nr;
repeat
a[i]:=x mod 10;
inc(i);
x:=x div 10;
until x=0;
n:=i-1;
i:=n;
cod:=false;
repeat
if (a[i]<a[i-1]) or (i=1) then
begin
a[i]:=10;
cod:=true;
end;
i:=i-1;
until cod or (i<1);
y:=0;
for i:=n downto 1 do
if a[i]<>10 then
y:=y*10+a[i];
writeln('numarul maxim este ',y);

78
Curs
readln;
end.

C4P6.pas
program suma;
var n1,n2:longint;
s1,s2,x:real;
begin
s1:=0;
s2:=0;
read(x);
while x<>0 do
begin
if x>0 then
begin
s1:=x+s1;
inc(n1);
end
else
begin
s2:=x+s2;
inc(n2);
end;
readln(x);
end;
writeln('suma celor ',n1,' nr pozitive este
',s1:7:1);
writeln('suma celor ',n2,' nr negative este
',s2:7:1);
readln;
end.

C4P8.pas

{Algoritmul de sortare prin metoda bulelor - bubble sort}


var x:array[1..50] of real;
i,j,n:byte;
aux:real;
ok:boolean;
f,g:text;
Begin
assign(f,'date.in');
assign(g,'date.out');
rewrite(g);
reset(f);
writeln('');
readln(f,n);
for i:=1 to n do
read(f,x[i]);
repeat
ok:=true;
for i:=1 to n-1 do
if x[i]>x[i+1] then
begin
aux:=x[i];
x[i]:=x[i+1];
x[i+1]:=aux;
ok:=false;

79
Bazele algoritmilor
end;
until ok;

for i:=1 to n do
writeln(g,x[i]:8:2,' ');
readln;
close(f);
close(g);
end.

C4P9.pas
{pentru simplitatea calculelor la matrice de dimensiuni
mari}
{am scris o procedura care genereaza aleator tablouri
deintrare}
program tablou;
uses crt;
type mat=array[1..100,1..100] of byte;

var a:mat;
m,n,i,j,k,l,mi,mj,ml,mk:byte;
fis:string;
f:text;
nr,max:word;
{secventa de citire a unei matrice dintr-un fisier text }

procedure cit_mat(m,n:byte; var a:mat; fis:string);


var f:text;
begin
assign(f,fis);
reset(f);
readln(f,m,n);
for i:=1 to m do
begin
for j:=1 to n do
read(f,a[i,j]);
readln(f);
end;
close(f);
end;

{secventa de generare aleatoare a matricei intr-un fisier


text}
procedure gen_mat(m,n:byte; fis:string);
var f:text;
begin
assign(f,fis);
rewrite(f);
writeln(f,m,' ',n);
randomize;
for i:=1 to m do
begin
for j:=1 to n do
write(f,random(2),' ');
writeln(f);
end;
close(f);
end;

80
Curs

{functie de test pentru o zona dintr-o matrice,intre


coordonate}
{(i,j) si (m,n), daca toate elementele din acea zona sunt
egale}
function ver(i,j,m,n:byte; a:mat):boolean;
var p,q:byte;
begin
ver:=true;
nr:=0;
for p:=i to m do
for q:=j to n do
if a[p,q]<>a[i,j] then
ver:=false
else
nr:=nr+1;
end;

{Cauta patru elemente, sub forma unui dreptunghi cu


elementele}
{ din cele patru colturi avand valori egale }
procedure gasire(m,n:byte);
begin
for i:=1 to m-1 do
for j:=1 to n-1 do
for l:=i+1 to m do
for k:=j+1 to n do
if a[i,j]=a[l,k] then
if ver(i,j,l,k,a) then
begin
if max<nr then
begin
max:=nr;
mi:=i;mj:=j;ml:=l;mk:=k;
end;
end;
end;

begin
max:=1;
mi:=1;mj:=1;ml:=1;mk:=1;
write('m,n=');readln(m,n);
write('f1=');readln(fis);
gen_mat(m,n,fis);
cit_mat(m,n,a,fis);
gasire(m,n);
write('f2=');readln(fis);
assign(f,fis);
rewrite(f);
write(f,'drept.',mi,',',mj,',',ml,',',mk,',cu',max,'elem
ente');
close(f);
end.

C5P1.pas
type lista=^element;
element=record

81
Bazele algoritmilor
nume:string[20];
medie:real;
leg:lista;
end;
var p,q,stiva:lista;
f:text;
elev:element;
fis:string[10];

procedure adaug;
begin
new(p);
p^.nume:=elev.nume;
p^.medie:=elev.medie;
p^.leg:=stiva;
stiva:=p;
end;
begin
readln(fis);
assign(f,fis);
reset(f);
stiva:=nil;
while not eof(f) do
begin
readln(f,elev.nume);
readln(f,elev.medie);
adaug;
end;
repeat
writeln(p^.nume,p^.medie);
stiva:=p^.leg;
dispose(p);
p:=stiva;
until p=nil
end.

C5P2.pas
type lista=^element;
element=record
nume:string[20];
medie:real;
leg:lista;
end;
var p,q,prim,ultim:lista;
f:text;
elev:element;
fis:string[10];

procedure inserare;
begin
new(q);
q^.nume:=elev.nume;
q^.medie:=elev.medie;
q^.leg:=p^.leg;
p^.leg:=q;
if p=ultim then ultim:=q;
end;

procedure parcurg;

82
Curs
begin
p:=prim;
q:=p;
while (q^.medie>elev.medie) and (q<>nil) do
begin
p:=q;
q:=q^.leg;
end
end;
begin
write (‘Numele fisierului de intrare’);
readln(fis);
assign(f,fis);
reset(f);
readln(f,elev.nume);
readln(f,elev.medie);
new(p);
p^.leg:=nil;
p^.nume:=elev.nume;
p^.medie:=elev.medie;
prim:=p;
ultim:=p;
while not eof(f) do
begin
readln(f,elev.nume);
readln(f,elev.medie);
if elev.medie> prim^.medie then
begin
new(q);
q^.leg:=prim;
q^.nume:=elev.nume;
q^.medie:=elev.medie;
prim:=q;
end
else
begin
parcurg;
inserare;
end;
end;
p:=prim;
repeat
writeln(p^.nume,p^.medie);
p:=p^.leg;
until p=nil;
end.

C5P3.pas
type lista=^element;
element=record
nume:string[20];
medie:real;
leg:lista;
end;
var p,q,prim,ultim:lista;
f:text;
elev:element;
fis:string[10];

83
Bazele algoritmilor
procedure adaug;
begin
new(p);
p^.nume:=elev.nume;
p^.medie:=elev.medie;
p^.leg:=nil;
if ultim<>nil then ultim^.leg:=p
else prim:=p;
ultim:=p;
end;

procedure parcurg(med1,med2:real);
begin
p:=prim;
repeat
if (p^.medie>med1) and (p^.medie<=med2) then
writeln(p^.nume,p^.medie);
p:=p^.leg;
until p=nil

end;
begin
write ('numele fisierului de intrare');
readln(fis);
assign(f,fis);
reset(f);
ultim:=nil;
prim:=nil;
while not eof(f) do
begin
readln(f,elev.nume);
readln(f,elev.medie);
adaug;
end;
parcurg(9.00,10);
parcurg(1.0,9);
end.

C5P4.pas
const ni='graf.in';
no='graf.out';
var v:array[1..200] of set of byte;
n,i,k,l:byte;
m:word;
sw:boolean;

procedure citeste1;
begin
assign(input,ni);reset(input);
readln(n,m);
end;

procedure da;
begin
write('Graful este ciclic.');
end;

procedure nu;

84
Curs
begin
write('Graful este aciclic.');
end;

procedure vezi;
begin
for i:=1 to n do v[i]:=[];
for i:=1 to m do begin
readln(k,l);
v[k]:=v[k]+[l]+v[l];
v[l]:=v[l]+[k]+v[k];
end;
sw:=false;
for i:=1 to n do if i in v[i] then sw:=true;
if sw then da
else nu;
end;
begin
citeste1;
assign(output,no);rewrite(output);
if m>=n then da
else vezi
end.

C5P5.pas
program df;
var n,m,i,j,x,y,vf,u,ps,k:integer;
s,v,sol:array [1..20] of integer;
a:array[1..20,1..20]of integer;
f:text;

begin
assign(f,'test');
reset(f);
readln(f,n);
readln(f,m);
for i:=1 to n do
for j:=1 to n do
a[i,j]:=0;
for i:=1 to m do
begin
readln(f,x,y);
a[x,y]:=1; a[y,x]:=1;
end;
write('vf de pornire:');readln(vf);
for j:=1 to n do
begin
v[j]:=0;
end;
ps:=1; s[ps]:=vf; v[vf]:=1;x:=1;sol[1]:=vf;
while ps>=1 do
begin
u:=s[ps];
k:=1;
while (k<=n)and((a[k,u]=0)or(a[k,u]=1) and (v[k]=1))
do
k:=k+1 ;
if k=n+1 then ps:=ps-1

85
Bazele algoritmilor
else begin
x:=x+1;
sol[x]:=k;
ps:=ps+1;
s[ps]:=k;
v[k]:=1;
end;
end;
close(f);
for i:=1 to n do
write(sol[i],' ');
readln;
end.

Convenţii de notaţie

- <nume> - numele unui identificator;


- {comentariu} - textul este interpretat ca un comentariu;
- [facultativ] - opţiunile din paranteze drepte nu sunt obligatorii;
- i =1, n , i parcurge toate elementele mulţimii {1,2,…,n};
- a (x, y, …, z) sau a[x, y, …, z] – elementul unui tablou cu indicii x, y, …, z;
- AxB – produsul cartezian a două mulţimi;
- sqrt ( x ), sau rad(x) – radicalul de ordinul doi dintr-un număr real
nenegativ;
- a div b – câtul împărţirii întregi a lui a la b.
- a mod b – restul împărţirii întregi a lui a la b.

86
Curs

7. Anexa 2
Listă de probleme

Probleme. SET I.

1. Să se rezolve ecuaţia de gradul I.


2. Să se rezolve ecuaţia de gradul II.
3. Afişaţi radical din x, radical de ordin 3 din x şi radical de ordin n din x
la m.
4. Calculaţi expresia E(x,y,z)=1/x+1/y+1/z, pentru x, y, z numere reale.
5. Ordonaţi crescător o mulţime cu 3 elemente.
6. Se dau a, b, c verificaţi dacă unul din numere este suma celorlalte
doua.
7. Mihai, Vasile şi Andrei au cate un loz câştigător, de sume a, b, c lei. O
racheta costa r lei. Care sunt posibilităţile de a plăti exact suma r
folosind lozurile.
8. Ionel are la banca suma s. Dobânda este de p%. Care este suma după k
luni
9. Un an calendaristic este cuprins între 0 şi 3000. Precizaţi dacă este
bisect
10. A câta zi din an este o dată calendaristică?
11. Se dau trei numere reale a,b,c. Precizaţi dacă ele sunt laturile unui
triunghi.
12. Determinaţi max (a,b,c,d).
13. Valoarea unui octet este data prin 8 caractere 0 şi 1. Calculaţi valoarea
zecimală a octetului
14. Se dau doua laturi ale unui triunghi dreptunghic. Calculaţi celelalte
elemente.

Probleme. SET II. Structuri combinate (liniare, alternative, repetitive)

1. Calculaţi produsul a n numere naturale (caz particular n!).


2. Determinaţi cifrele unui număr natural dat. (rezultatul va fi un şir de
cifre).
3. Calculaţi frecvenţa de apariţie a cifrelor într-un număr.
Exemplu 2435634 are
2: 1 dată; 3: 2 ori; 4:2 ori; 5: 1 dată; 6: 1 dată
4. Pentru un număr natural dat să se precizeze dacă este prim sau nu.
5. Afişaţi toate numerele prime mai mici decât un n dat.
6. Se dă u număr natural n. Aflaţi cel mai mare număr ce poate fi obţinut
prin eliminarea unei cifre.
7. Calculaţi cmmdc a n numere naturale date.
8. Determinaţi divizorii unui număr natura dat.
9. Descompuneţi în factori primi un număr natural dat.
10. Scrieţi un algoritm care permite transformarea unui număr din baza b
într-o altă bază B (se foloseşte baza 10).
11. Să se introducă între două elemente consecutive ale unui şir de numere
reale, media lor aritmetică.
12. Se dă un şir de numere reale cu n termeni. Determinaţi:
- Câte elemente aparţin intervalului dat (a, b).
- Numărul de apariţii şi poziţiile pe care apare un element dat x.

87
Bazele algoritmilor
- Extrageţi mulţimea formată cu elementele şirului.
- Frecvenţa de apariţie a elementelor în şir.
13. Calculaţi pentru un n natural dat sumele:
- S1=1*2+2*3+3*4+...+(n-1)*n
- S2=1/2+1/3+...+1/n
- S3=1/(2*3)+ 2/(3*4)+ 3/(4*5)+...+ n/((n+1)*(n+2))
- S4=1/1!+ 1/2!+ 1/3!+..+ 1/n!
14. Calculaţi valoarea unui polinom P(x), într-un punct x dat. Polinomul
este dat prin coeficienţi săi,
15. Efectuaţi următoarele operaţii cu polinoame:
- adunarea a două polinoame
- diferenţa a două polinoame
- produsul a două polinoame
- împărţirea unui polinom prin x-a (schema lui Horner)
16. Se dă un cuvânt de maxim 255 de caractere.
- Scrieţi cuvântul în ordine inversă.
- Eliminaţi vocalele din cuvânt
- Găsiţi frecvenţa de apariţie a fiecărei litere
- Verificaţi proprietatea de palindrom a cuvântului (citit de la
dreapta la stânga este identic cu cel citit de la stânga la dreapta).
17. O propoziţie este formată din litere mari şi mici şi spaţii.
- transformaţi toate literele mici în litere mari
- dacă un cuvânt este delimitat de spaţii, determinaţi numărul de
cuvinte din text.
- Determinaţi dacă un cuvânt dat există sau nu în propoziţia dată.
18. Se dă o matrice rară cu m linii şi n coloane.(o matrice rară conţine doar
valori 0 şi 1). Să se determine:
- Numărul de 0 şi 1 din matrice.
- Câte elemente 1 sunt pe fiecare linie şi pe fiecare coloană.
- Reprezentaţi matricea folosind doar două şiruri care păstrează
perechile (linie, coloană) pentru elementele 1 ale matricei
- Determinaţi dreptunghiul de arie maximă din această matrice
care conţine doar valori 0.
19. Efectuaţi următoarele calcule cu matrice pătratice (nxn):
- Suma elementele de pe diagonala principală
- Suma elementelor de sub (de deasupra) diagonale principale.
- adunarea
- înmulţirea
- ridicarea la puterea n a unei matrice
20. Se ştie ziua şi data calendaristică curentă. Aflaţi în ce zi este o dată
calendaristică oarecare.
21. Două grupuri de copii sunt formate din m şi respectiv n indivizi. Afişaţi
toate grupele posibile care se pot forma cu doi indivizi astfel încât unul
să fie din prima grupă iar celălalt din a doua.
22. Se dau n beţe de chibrit. Din acestea, doi jucători, iau pe rând cel puţin
un băţ dar nu mai mult de p chibrituri. Pierde cel a care este nevoit să ia
ultimul chibrit. Scrieţi un algoritm care permite unui jucător să joace cu
calculatorul.
23. Un copil indisciplinat trece pe coridorul unei şcoli care are n uşi şi
deschide toate uşile. Se întoarce şi închide din două în două. Reia cursa
din 3 în 3 uşi şi le deschide pe cele închise şi le închide pe cele
deschise, apoi procedează la fel din 4 în 4 şi aşa mai departe.
a) Aflaţi configuraţia uşilor după t treceri.

88
Curs
b) Care este numărul de treceri ca toate uşile să fie din
nou închise.

89
Bazele algoritmilor

8. Bibliografie
1. Andone R., Gârbacea I., Algoritmi fundamentali o perspectivă C++, Editura
Libris, Cluj Napoca, 1995.
2. Böhm C., Jacopini T.C., Flow diagrams, Turing Machines and Languages with
only two Formation Rules, CACM 9, 5, 1966.
3. Calude C., Complexitatea calcului, aspecte calitative, Editura Ştiinţifică şi
Enciclopedică, Bucureşti, 1982.
4. Cormen T.H., Leiserson E.C., Rivest R.R., Introducere în algoritmi, Editura Libris
Agora, 2000 (traducere în limba română).
5. Dahl O.J., Dijkstra E.W., Hoare C.A.R., Structured Programing, Academic Press,
1972.
6. Frenţiu M., Motogna S., Lazăr I., Prejmerean V., Elaborarea algoritmilor,
Litografia Universităţii “Babeş Bolyai”, Cluj Napoca, 1998.
7. Knuth E. Donald, Arta programării calculatoarelor
8. Lica D., Onea E., Informatică, Manual pentru clasa a IX-a, Editura L&S,
Bucureşti, 1999.
9. Livovschi L., Georgescu H., Sinteza şi analiza algoritmilor, Editura Ştiinţifică şi
Enciclopedică, Bucureşti, 1986.
10. McConnell S.C., Code Complete: a practical handbook of software construction,
Microsoft Press, Washington, 1993
11. Mitrana V., Provocarea algoritmilor, Editura Agni, Bucureşti, 1994.
12. Motogna S.,Metode şi tehnici de proiectare a algoritmilor, Universitatea “Babeş
Bolyai”, Cluj Napoca, 1998
13. Pólya G., How to solve it? A new aspect of mathematical method, Princeton
Univerity Press, 1957.
14. Rancea D., Limbajul Pascal. Algoritmi fundamentali., Editura Computer Libris
Agora, Cluj Napoca, 1999.
15. Tudor S., Cerchez E., Şerban M., Informatică. Manual pentru clasa a IX-a, Editura
L&S, Bucureşti, 1999.

90
Curs
Cuprins
1.Introducere........................................................................................................6

1.1. Scurt istoric...........................................................................................................................6

1.2.Noţiunea de algoritm. Caracteristici...................................................................................7

1.3.Verificarea cunoştinţelor....................................................................................................10

1.4. Răspunsuri..........................................................................................................................11
2.Descrierea algoritmilor .................................................................................12

2.1.Proiectarea algoritmilor.....................................................................................................12

2.2.Programarea structurată. Programarea modulară. Programarea orientată-obiect. ..14

2.3.Moduri de organizare şi reprezentare a datelor..............................................................15

2.3.1.Tipul datelor.....................................................................................................................15

2.3.2.Organizarea datelor.........................................................................................................16
2.3.2.1. Date structurate care conţin mărimi de acelaşi tip sau date structurate omogene. ...17
2.3.2.2. Date structurate care conţin mărimi de diverse tipuri...............................................19

2.3.3.Modul de reprezentare....................................................................................................19

2.3.4.Natura datelor..................................................................................................................20

2.4.Subalgoritmi........................................................................................................................23

2.5.Metode de descriere a algoritmilor...................................................................................24


2.5.2.Schema logică...............................................................................................................24
2.5.3. Descriere comparativă pseudocod / schemă logică......................................................25
2.5.3.1. Definirea unui algoritm şi a eventualilor parametrii.................................................25
2.5.3.2.Declararea constantelor şi variabilelor.......................................................................25
2.5.3.3. Structura liniară.........................................................................................................26
2.5.3.4. Structura alternativă..................................................................................................27
2.5.3.5. Structura repetitivă....................................................................................................28

2.6. Exemple folosind structuri alternative.............................................................................30


2.6.1.Proprietăţi ale structurii alternative...............................................................................34

2.7. Exemple care utilizează structuri repetitive....................................................................35

2.8.Verificarea cunoştinţelor....................................................................................................39

2.9.Răspunsuri...........................................................................................................................42
3.Elaborarea, corectitudinea, complexitatea şi testarea algoritmilor.................45
3.1.Elaborarea algoritmilor......................................................................................................45

3.2.Corectitudinea algoritmilor...............................................................................................46

3.3.Complexitatea algoritmilor ...............................................................................................47

3.4.Testarea algoritmilor..........................................................................................................48

3.5.Verificarea cunoştinţelor....................................................................................................50

3.6.Răspunsuri...........................................................................................................................50

91
Bazele algoritmilor
4.Algoritmi elementari .....................................................................................52
4.1.Schimbarea valorilor a două variabile..............................................................................52

4.2.Parcurgerea elementelor unei mulţimi, (secvenţe)..........................................................53

4.3.Implementarea cuantificatorilor matematici oricare şi există........................................54

4.4.Implementarea produsului cartezian a două mulţimi.....................................................55

4.5.Metode de sortare a elementelor unei mulţimi.................................................................56


4.5.1. Sortarea prin metoda bulelor, algoritmul “Bubble Sort”.............................................57
4.5.2.Sortarea prin selecţie.....................................................................................................58
4.5.3.Sortarea prin inserţie.....................................................................................................58
4.5.4.Sortarea prin numărare..................................................................................................58

4.6.Interclasarea........................................................................................................................59

4.7.Recursivitatea......................................................................................................................60

4.8.Funcţii. Funcţii recursive...................................................................................................63


4.8.1. Funcţii. Subalgoritm de tip funcţie...............................................................................63

4.9.Verificarea cunoştinţelor....................................................................................................65

4.10.Răspunsuri.........................................................................................................................68
5.Structuri de date..............................................................................................70

5.1.Liste .....................................................................................................................................70

5.2.Tipuri de liste ......................................................................................................................71


5.2.1. Stiva..............................................................................................................................71
5.2.2. Coada............................................................................................................................72
5.2.3. Lista circulară...............................................................................................................73
5.2.4. Lista dublu înlănţuită....................................................................................................74

5.3.Verificarea cunoştinţelor....................................................................................................75

5.4.Răspunsuri...........................................................................................................................75
6.Anexa 1...........................................................................................................76
7.Anexa 2...........................................................................................................87
8.Bibliografie.....................................................................................................90

92

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