Documente Academic
Documente Profesional
Documente Cultură
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:
Gheorghe Ţiţeica
5
Bazele algoritmilor
1. Introducere
Fig. 1.
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”.
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:
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
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.
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
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.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
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:
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
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?
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.
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.
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.
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
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:
Notăm cu
T(i,j), i =1, n , j =1, m ,
matricea.
T(1,2)=9 este nota persoanei 1 la examenul 2.
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ă.
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.
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.
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.
21
Bazele algoritmilor
Prioritate Operatori
0 NOT, +, -, abs, int, frac – operatori unari
1 *, /,div , mod, AND – operatori multiplicativi
2 +, -, OR – operatori aditivi
3 >, <, >=, <=, <>,# , = - operatori relaţionali
22
Curs
poate aplica operanzilor numerici sau alfanumerici).
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.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ă.
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:
(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
(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
(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)]
(P)
Dacă < ExpresieLogică> atunci
[ <S1>]
[ altfel
<S2> ]
sfDacă
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ă:
<S2>
sfDacă.
(SL)
NU DA
< ExpresieLogică>
<S2> <S1>
27
Bazele algoritmilor
(P)
Cât timp < ExpresieLogică> execută
<S>
sfCât timp
(SL)
DA
< ExpresieLogică>
NU <S>
(P)
Repetă
<S>
până când < ExpresieLogică>
28
Curs
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
(SL)
<contor> ← <ini>
DA
< contor> <= <fin>
NU <S>
<contor> ← < 29
contor > + <pas>
Bazele algoritmilor
(P)
Stop
Există o singură instrucţiune care marchează sfârşitul algoritmului
(SL)
STOP
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ă.
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
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.
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
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.
32
Curs
sfdacă
stop
Problema 3.
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
Exemplu:
Pentru n=3 imbricări (nivele) avem 8
cazuri distincte şi 23-1= 7 blocuri 34
(Figura 4.).
Curs
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.
Soluţia I
V S I cont
50000 0 0 “D”
2000000 50000 1 “D”
10000000 2500000 2 “D”
12500000 3 “N”
36
Curs
Soluţia II
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.
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)
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:
2.8.Verificarea cunoştinţelor
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
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.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.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)
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.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.
P.2.
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ă.
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.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.
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...
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
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):
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
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)
3.6.Răspunsuri.
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.
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:
a ← a + b;
b ← a - b;
a ← a - b;
stop;
52
Curs
Pas a = 17 b = 13
1 30 13
2 30 17
3 13 17
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
sau
Repetă
{Operaţie asupra fiecărui element}
până când not <condiţie>;
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.
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.
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.
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}
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ă
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.
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.
57
Bazele algoritmilor
4, 7, 6, 5, 3 3, 4, 7, 6, 5 3, 4, 5, 7, 6 3, 4, 5, 6, 7
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.
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ă.
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:
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ă:
Citeşte c;
Dacă c<> “ “ atunci
cuvant_recursiv ( nr + 1 );
altfel
Algoritm principal;
cuvânt_recursiv ( 0 );
stop;
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
Exemple:
1) Funcţia care returnează valoarea maximă dintre două numere reale se defineşte
astfel:
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.
63
Bazele algoritmilor
Algoritm principal;
Citeşte (a, b);
Scrie (cmmdc ( a, b ));
stop;
64
Curs
4.9.Verificarea cunoştinţelor
E.2. Care este valoarea afişată a funcţiei recursive test, pentru a=24 şi b=5:
Algoritm principal;
Citeşte (a, b);
Scrie ( test ( a, b ));
stop;
a) 1 b) 2 c) 3 d) 4
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;
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.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.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.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
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:
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)
b) Ştergerea unui element din vârful stivei (deci vârf are o anumită valoare)
5.2.2. Coada
Coada (coada de aşteptare) este o listă liniară simplu înlănţuită cu proprietăţile:
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
b) Ştergerea unui element din coadă, deci prim are o anumită valoare)
73
Bazele algoritmilor
leg [q] ← p; {adresa_de_legătură a lui q este noul p}
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
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ă.
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.
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.
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;
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;
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
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 }
80
Curs
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
86
Curs
7. Anexa 2
Listă de probleme
Probleme. SET I.
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.3.Verificarea cunoştinţelor....................................................................................................10
1.4. Răspunsuri..........................................................................................................................11
2.Descrierea algoritmilor .................................................................................12
2.1.Proiectarea algoritmilor.....................................................................................................12
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.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.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.6.Interclasarea........................................................................................................................59
4.7.Recursivitatea......................................................................................................................60
4.9.Verificarea cunoştinţelor....................................................................................................65
4.10.Răspunsuri.........................................................................................................................68
5.Structuri de date..............................................................................................70
5.1.Liste .....................................................................................................................................70
5.3.Verificarea cunoştinţelor....................................................................................................75
5.4.Răspunsuri...........................................................................................................................75
6.Anexa 1...........................................................................................................76
7.Anexa 2...........................................................................................................87
8.Bibliografie.....................................................................................................90
92