Sunteți pe pagina 1din 35

ASDC

Algoritmi, Structuri de date şi


Complexitate

Ludmila NOVAC
Dr., conf. univ.
Dep. Informatică
Bibliografie recomandată
1. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest,  Clifford Stein
Introduction to Algorithms.  
2. D. E. Knuth. Tratat de programarea calculatoarelor. Volum I. Algoritmi
fundamentali. Editura tehnică. Bucureşti, 1974.
3. D. E. Knuth. Tratat de programarea calculatoarelor. Volum III. Sortare şi
căutare. Editura tehnică. Bucureşti, 1974.
4. Dorel Lucanu. Bazele proiectării programelor şi algoritmilor. Volum II. Tehnici
de programare. Editura Universităţii „Al. I. Cuza”, Iaşi, 1996.
5. Dorel Lucanu. Bazele proiectării programelor şi algoritmilor. Volum III.
Proiectarea algoritmilor. Editura Universităţii „Al. I. Cuza”, Iaşi, 1996.
6. Tudor Sorin. Tehnici de programare. Editura Teora, Bucureşti, 1997.
7. Octavian Catrina, Iuliana Cojocaru, Turbo C++, Editura Teora, Bucureşti,
1994.
8. Emanuela Cerchez, Marinel Şerban, Programarea in limbajul C/C++. Vol. 2,
Metode şi tehnici de programare, Polirom, Iaşi, 2005.
9. Emanuela Cerchez, Marinel Şerban, Programarea in limbajul C/C++.  Vol. 3,
Polirom, Iaşi, 2006.
Unităţi de conţinut
1. Noţiunea de structură abstractă de date. Reprezentarea structurilor în MO a
calculatorului. Clase abstracte şi algoritmi pentru construirea elementelor de
date. Clase derivate.
2. Tabele. Problema de căutare, aprecierea complexităţii algoritmilor de
căutare, viteza medie de căutare, lungimea medie de căutare. Tabele neordonate
simple. Algoritmul căutării secvenţiale. Tabele neordonate structurate
arborescent.
3. Tabele ordonate. Tabele ordonate după cheie. Căutarea binară. Căutarea după
metoda lui Fibonacci. Căutarea prin interpolare. Tabele ordonate după frecvenţa
de adresare la înregistrări tabelare.
4. Tabele cu adresarea directă. Funcţia de repartizare. Tabele de repartizare.
Coliziuni. Rezolvarea coliziunilor. Examinarea lineară. Tabele cu înlănţuirea
externă. Tabele cu înlănţuirea internă.
5. Tehnici de sortare. Noţiunea de sortare şi tipuri de sortare. Sortarea bazată pe
comparaţii, aprecierea algoritmilor de sortare. Algoritmi de sortare prin
interschimbare. Metoda bulelor, sortarea bazată pe metoda „Divide et Impera”
(sortare rapidă - quicksort). Aprecierea complexităţii. Îmbunătăţirile
algoritmului de sortare rapidă.
6. Algoritmi de sortare prin inserţie. Inserţia simplă recursivă, inserţia simplă
iterativă. Sortarea prin metoda lui Shell. Algoritmi de sortare prin interclasare
(mergesort). Aprecierea complexităţii.
Unităţi de conţinut
7. Algoritmi de sortare prin selecţie. Selecţia simplă. Selecţia sistematică
(piramidală, arborescentă - heapsort). Aprecierea complexităţii.
8. Structuri dinamice de date (arbori binari, liste, stive, cozi). Arbori
binari. Crearea arborilor. Accesul la elementele unui arbore. Parcurgerea
arborilor binari. Arbori binari plini. Arbori binari de căutare.
9. Liste simplu înlănţuite. Liste înlănţuite ciclic. Liste dublu înlănţuite.
Liste dublu înlănţuite ciclic.
10. Stive. Stive prin buffer de lungime fixă. Stive prin liste simplu
înlănţuite. Realizarea algoritmului de sortare rapidă prin utilizarea stivei.
11. Cozi. Cozi prin buffer ciclic. Cozi prin liste simplu înlănţuite.
12. Matrici dreptunghiulare. Reprezentarea matricelor în MO.
Reprezentarea „pe linii”, reprezentarea „pe coloane”. Accesarea
elementelor.
13. Accelerarea accesului la elementele matricei. Vectori definitori.
14. Vectori lui Iliffe. Exemplu de clasă generică dotată cu vectori lui Iliffe.
4 lucrări de laborator:
• 1. Metode de căutare în tabele
• 2. Metode de sortare
• 3. Structuri dinamice de date
• 4. Metode de acces la elementele unui masiv

5
Tipuri de date
Tip de date este un set de valori valide pe care un obiect le poate accepta,
precum şi un set de operaţii valide care se aplică la obiecte. În sensul aplicativ,
tipul depinde şi de prezentarea internă a informaţiilor.
Astfel, date de diferite tipuri sunt stocate şi prelucrate în moduri diferite.
Tipul de date defineşte:
reprezentarea internă a datelor în memoria calculatorului;
Volumul de memorie alocată datelor;
un set (interval) de valori care pot lua valori de acest tip;
operaţiile şi funcţiile care pot fi aplicate datelor de acest tip.
În baza acestor caracteristici, este necesar să se determine tipul fiecărei
valori utilizate în program pentru a reprezenta obiectele. O descriere
obligatorie a tipului permite compilatorului să verifice valabilitatea diferitelor
construcţii în program.
Succesiunea instrucţiunilor la nivel de cod maşină construită de compilator
depinde de alegerea tipului pentru valorile utilizate.
6
Tipuri abstracte de date
Tipul abstract de date— Acesta este un tip de date care oferă un set de
funcţii pentru lucrul cu elemente de acest tip, precum şi posibilitatea de a crea
elemente de acest tip utilizând funcţii speciale.

Întreaga structură internă de acest tip este ascunsă de dezvoltătorul de software


— aceasta este esenţa abstractizării. Un tip de date abstract defineşte un set de
funcţii independente de o anumită implementare a unui tip pentru operarea cu
valorile sale.

Implementările specifice ale tipurilor abstract de date se numesc structuri de


date.

7
Structura abstractă de date
Definiţie Prin structura abstractă de date (SAD), sau pur şi simplu structura
de date (SD), vom înţelege o totalitate de reguli şi restricţii ce reflectă
legăturile existente între părţile separate de date şi prin care părţile
acestea se unesc într-o unitate întreagă.

Structurile de date se divizează în două categorii: statice şi dinamice.


Definiţie Prin structură de date statică vom înţelege aşa SD, la care în
procesul de lucru se schimbă numai informaţiile ce se conţin în elemente
de date şi nu se schimbă cantitatea acestor elemente.
Exemplu: Matrice cu dimensiunile fixe, tablou cu număr fix de înregistrări
tabelare, Vectori cu număr fix de elemente.

Definiţie Prin structură de date dinamică vom înţelege aşa SD, la care în
procesul de lucru se schimbă atât informaţii ce se conţin în elementele de
date, cât şi numărul de elemente (componenţa cantitativă).
Exemplu: Liste înlănţuite de diferite tipuri, stive, cozi, arbori binari.
Clasificarea tipurilor de date în C ++
• Limbajele de programare moderne, de regulă, conţin un set de tipuri simple de date
care sunt încorporate în limbajele de programare şi mijloacele pentru crearea
tipurilor derivate.
Limbajele de programare orientate pe obiecte ne permit să definim tipurile de clase.
Implementarea tipurilor de date simple reprezintă modalitatea de a reprezenta valori de
acest tip în computer şi existenţa setului de operaţii acceptate pentru acel tip.
• Tipul de date determină volumul memoriei alocate unei variabile de acest tip atunci
când este creată. Limbajul de programare C ++ acceptă următoarele tipuri de date
(Figura 1 ).
• Tipuri de bază. Tipurile de bază sunt predefinite de standardul limbajului, sunt
indicate de cuvinte cheie rezervate şi sunt caracterizate printr-o singură valoare.
Ele nu trebuie să fie definite şi nu pot fi descompuse în componente mai simple,
fără a pierde esenţa datelor. Tipurile de obiecte de bază oferă baza pentru
construirea unor tipuri mai complexe.
• Tipuri derivate. Tipurile derivate sunt definite de utilizator, iar variabilele acestor
tipuri sunt create folosind atât tipurile de bază, cât şi tipurile de clase.

9
Clasificarea tipurilor de date
Tipuri de date

Tipuri de date Tipuri de date Tipuri de clasă


predefinite (de derivate (declarate) (obiecte)
bază, simple)
- întreg,
- real, Tipuri de date Tipuri de date
-caracter, derivate simple: derivate compuse:
-logic, - tablouri, - structuri
-tipul void. - înregistrări, - uniuni
- linkuri, - clase
- pointeri

Figura 1
Structura de date
Structura de date este o unitate software care permite să
stocheze şi să proceseze o mulţime de date similare de acelaşi tip
şi/sau date cu o legătură logică în tehnologia de calcul.
• Pentru a adăuga, căuta, edita şi şterge datele, o structură de
date oferă un anumit set de funcţii care formează interfaţa sa.
• Structura de date este adesea o implementare a unui tip abstract
de date.

11
Structura de date – tablou de date (array)

Cea mai populară structură de date este tabloul în care accesarea


elementelor se face direct prin numărul său de ordine.
Cuvântul “tablou /array” este utilizat în diferite contexte:
• Ca tip de date abstract, adică un set de elemente cu operaţiile:
- obţinerea elementului cu numărul N,
- scrierea unui element cu numărul N,
• Ca o structură fizică implementată sub formă de zona de
memorie continuă.
Caracteristicile pozitive ale tabloului:
• Accesarea oricărui element în interval constant de timp,
• Memoria se consumă doar pentru date.
12
Tipuri de structuri de date în programare

• Variabile simple
• Tablouri /array
• Şiruri de caractere
• Înregistrări
• Liste
• Cozi
• Stive
• Grafuri
• Arbori
• Tabele
Tipuri de structuri de date în programare

• Variabilele simple - descriu structuri care constau


dintr-un singur element, deoarece ele sunt
caracterizate printr-o singură valoare (scalară).
Numele unei variabile simple caracterizează numărul
(unei sau mai multe) celule unde se stochează
valoarea acesteia. O variabilă simplă poate fi întreg,
real, logic, caracter etc.
Tipuri de structuri de date în programare

• Tablourile - variabile cu indici care descriu structuri


ce constau dintr-un set limitat de componente,
ordonate în conformitate cu valorile indicilor.
Numărul de indici determină dimensiunea
(unidimensională, bidimensională etc.). Indicele oferă
acces direct la orice element al tabloului. Elemente ale
tabloului pot fi atât date simple cât şi structurate.
De exemplu, poate fi un tablou multidimensional.
Tipuri de structuri de date în programare

•  Şirurile de caractere – sunt secvenţe de caractere ordonate,


limitate ale unui alfabet.

• Înregistrările  – reprezintă o structură de date care constă


dintr-un număr fix de componente, numite câmpuri, fiecare
dintre ele având un tip propriu. Înregistrările permit, într-o
formă convenabilă, prezentarea listelor, a tabelelor, a
cataloagelor, cartotecilor şi alte date.
•  Listele – sunt lanţuri de înregistrări. Operaţiile de bază cu
liste: vizionarea înregistrărilor, includerea unei înregistrări
noi şi excluderea unei înregistrări din listă. Listele ne permit
crearea obiectelor cu o structură complexă în permanentă
schimbare.
Tipuri de structuri de date în programare

•   Cozile– structuri de date organizate în conformitate cu principiul


"primul venit – primul deservit“ (FIFO) (“First in - First out”). Acestea
sunt structuri dinamice, numărul elementelor cărora pot varia în timpul
procesării. Procesarea elementelor unei cozi se efectuează succesiv
unul după altul. Adăugarea elementelor noi se face la sfârşitul cozii.
Operaţiile de bază cu elementele unei cozi sunt: citirea, procesarea,
scrierea în coadă, eliminarea din coadă. Exemplu: o coadă la magazin.

• Stivele– structuri de date organizate în conformitate cu principiul


"ultimul venit - primul deservit" (LIFO) (“Last in - First out”).
Exemple: un teanc de cărţi, un teanc de cărămizi, farfurii etc.
Tipuri de structuri de date în programare

• Grafurile – modele matematice ale sistemului relaţiilor dintre


obiecte. Un graf constă din vârfuri (noduri) şi muchii (ramuri)
care conectează nodurile situate la diferite nivele.

•  Arborii– grafuri conexe în care nu există cicluri. În cazul


rezolvării multor probleme aplicative, este convenabil să se
reprezinte seturi de obiecte sub formă de arbori.
De exemplu, reprezentarea codurilor binare.
Tipuri de structuri de date în programare
• Tabelele – reprezintă un set de înregistrări, fiecare având un nume,
numit cheie. Căutarea înregistrării necesare în tabel se face prin
cheia acesteia. Operaţiile de bază cu tabele: căutarea înregistrărilor,
includerea unei înregistrări noi în tabel şi excluderea unei
înregistrări din tabel. Exemplu:
Exemplu:Tabelul de trecere din baza 10 în bazele 2, 8 şi 16
Tabelul

Din punct de vedere fizic, tabelul este un vector, elementele căruia sunt
înregistrări. O trăsătură caracteristică logică a tabelelor, care
determină examinarea lor separată este faptul că accesul la
elementele din tabel se face nu prin numărul (indexul ei), dar prin
cheie – după valoarea uneia dintre proprietăţile obiectului descris de
elementul tabelului.
O cheie este o proprietate care identifică o înregistrare dată într-un set
de înregistrări de acelaşi tip. De regulă, pentru cheie este indicată
cerinţa unicităţii ei în acest tabel. O cheie poate fi inclusă într-o
înregistrare şi poate fi unul din câmpurile sale, dar poate să nu fie
inclusă în înregistrare şi poate fi calculată conform poziţiei
înregistrării. Un tabel poate avea una sau mai multe chei.

21
Tipurile de Tabele
• Tabele neordonate
Elementele unei astfel de tabel nu sunt ordonate de valoarea cheii.
Pentru a căuta un element cu o cheie dată, folosim algoritmul de căutare
secvenţială.
• Tabele ordonate
Într-un astfel de tabel, toate elementele sunt ordonate în ordine crescătoare
a valorii cheii. Pentru a căuta un element cu o cheie dată în tabelele
ordonate, se utilizează algoritmii căutării secvenţiale, binare, prin
interpolare şi după metoda lui Fibonacci. După operaţia de inserare a
elementelor, elementele tabelului trebuie să rămână ordonate. Deci
înainte de efectuarea operaţiei de inserare, trebuie de găsit elementul
după care trebuie să adăugăm noul element.

Tabelele Hash  — tabelul Hash este un tabel în care poziţia adresei unui
element este determinată prin utilizarea unei funcţii H (funcţie Hash),
argumentul căruia este valoarea cheii elementului.
Tabele neordonate
• Tabelul neordonat– este un tabel ale cărui elemente sunt
aranjate în ordinea în care sunt incluse în tabel.

• Într-un tabel neordonat, căutarea unui element va fi efectuată


în medie după n/2 comparaţii, deoarece căutarea constă în
vizualizarea secvenţială a elementelor tabelului (numărul maxim
de comparaţii este n).

• Includerea unui element într-un tabel neordonat este adăugarea


unui element în tabel în următorul spaţiu liber (dacă n <N).

23
Tabelul neordonat
• Acesta este cel mai simplu mod de organizare a tabelelor.
Elementele sunt amplasate consecutiv unul după altul, fără
spaţii. Procesul de căutare a elementului dorit este foarte
simplu - căutarea secvenţială a elementelor din tabel pornind
de la primul element. În acest caz, este analizat câmpul cheie
şi, în cazul în care condiţia de căutare este îndeplinită, este
localizat elementul dorit.

24
Operaţii logice asupra tabelelor. Căutarea

• Cea mai simplă metodă de căutare constă în următoarele:


Cuvântul de intrare este comparat cu fiecare element stocat în
memoria unui tabel sau o listă de cuvinte, până când există o
potrivire (dacă este posibil). Elementele respective sunt
adăugate la sfârşitul secţiunii curente completate a tabelului
sau la ultimul element din listă.
• Această metodă are un singur dezavantaj: căutarea într-un
tabel va dura mult timp în cazul tabelelor cu un număr mare de
înregistrări! Dacă în tabel există N elemente, atunci numărul
estimat de comparări necesare pentru a detecta un element
selectat aleator este (N+1)/2.

25
Căutarea secvenţială sau liniară

• Cea mai simplă metodă de căutare a unui element dintr-un set


de date neordonate, în baza valorii cheii sale, este de a analiza
secvenţial fiecare element al mulţimii. Căutarea continuă până
când se găseşte elementul dorit. Dacă întreaga mulţime este
analizată, dar elementul nu este găsit, atunci cheia de căutare
lipseşte în mulţime.
• Pentru o căutare secvenţială, sunt necesare în mediu (N+1)/2
comparaţii. Astfel, complexitatea algoritmului este liniară - O
(N).

26
Problema de căutare
• Problema de căutare poate fi formulată după cum urmează: să se
găsească unul sau mai multe elemente din mulţimea dată; este
important ca elementele căutate să posede o anumită proprietate.
Această proprietatea poate fi absolută sau relativă.
• Proprietatea relativă caracterizează elementul în raport cu alte
elemente: de exemplu, elementul minim din mulţimea de numere.
• Un exemplu al sarcinii de a căutare a unui element cu proprietate
absolută: să se găsească elementul cu nr. 13 într-o mulţime finită
de elemente indexate, dacă aşa element există.

27
Problema de căutare
Astfel, în sarcina de căutare sunt importante următoarele sarcini:
1) calcularea proprietăţii elementului; adesea aceasta presupune doar obţinerea
"valorii" elementului, sau cheia elementului, etc.;
2) compararea proprietăţii elementului cu etalonul de referinţă (pentru
proprietăţile absolute) sau compararea proprietăţilor a două elemente
(pentru proprietăţile relative);
3) enumerarea elementelor mulţimii, adică parcurgerea elementelor mulţimii.
Primele două etape sunt relativ simple. Întreaga esenţă a diferitor metode de
căutare este concentrată în metodele de căutare, în strategia de căutare, şi
aici apar o serie de întrebări:
• Cum să procedăm aşa încât să nu parcurgem toate elementele mulţimii?
• Dacă problema necesită parcurgerea repetată a tuturor elementelor
mulţimii, atunci cum să reducem numărul de parcurgeri?
Răspunsurile la aceste întrebări depind de structura de date în care este
stocată mulţimea de elemente. Prin impunerea unor restricţii
nesemnificative asupra structurii datelor iniţiale, se pot obţine o varietate
de strategii de căutare de diferite grade de eficienţă şi complexitate.
28
Căutarea secvenţială
Căutarea înregistrării dorite în lista neordonată este redusă la vizualizarea întregii
liste de elemente până la găsirea înregistrării dorite. “A se începe de la începutul
listei şi a se continua până la găsirea cheii căutate, apoi procedura se termină“ –
acesta este cel mai simplu algoritm de căutare. Acest algoritm nu este foarte eficient,
dar funcţionează pentru orice listă arbitrară.
•O sarcină importantă pentru algoritmul de căutare este localizarea cheii
elementului, astfel încât returnează indexul înregistrării care conţine cheia necesară.
În cazul în care căutarea nu a reuşit (valoarea cheie nu a fost găsită), atunci
algoritmul de căutare de obicei, returnează o valoare a indexului care depăşeşte limita
superioară a tabloului.
•Aici şi în continuare se presupune că tabloul A constă din înregistrări şi
descrierea ei şi sarcina este executată în afara procedurii (tabloul se declară global în
raport cu Procedura). Singurul lucru pe care trebuie să-l cunoaştem despre tipul de
înregistrări este acela că în  componenţa înregistrării se include şi câmpul cheie -
cheia în raport cu care se efectuează căutarea. Înregistrările se fac în tablou în mod
consecutiv şi nu există lacune între ele. Numerele înregistrărilor urmează de la 1 la n
- numărul total de înregistrări. Acest lucru ne va permite să returnăm valoarea 0 dacă
elementul căutat nu este prezent în listă. Pentru simplitate, presupunem că valorile
cheie nu se repetă.
29
Căutarea secvenţială

Procedura SequentialSearch efectuează căutarea


secvenţială a elementului z în tabloul A[1..n].
SequentialSearch(A, z, n)
(1) for i ←1 to n
(2) do if z = A[i].key
(3) then return i
(4) return 0

30
Căutarea secvenţială 
• Analiza celui mai rău caz. Pentru Algoritmul Căutării Secvenţiale
există două cazuri cele mai grave. În primul caz, elementul căutat
este ultimul din listă. În al doilea caz – elementul nu este prezent în
listă. În ambele cazuri, algoritmul efectuează n comparaţii, unde n
este numărul elementelor din listă.
• Analiza cazului mediu. Valoarea căutată poate fi una dintre
poziţiile existente. Presupunem că toate aceste poziţii sunt
echiprobabile, adică probabilitatea întâlnirii fiecăreia dintre ele este
egală. Prin urmare, pentru a găsi elementul A[i],  sunt necesare i
comparaţii. Ca urmare, pentru complexitatea în cazul mediu se
obţine egalitatea:

31
Concluzii
•De obicei, căutarea liniară este foarte uşor de implementat şi se
aplică dacă lista conţine puţine elemente sau cazul unei singure
căutări într-o listă neordonată.

•Dacă se presupune că în aceeaşi listă se efectuează un număr mare de


căutări, atunci deseori este logic ca lista sa fie prelucrată anterior. De
exemplu, să se facă sortarea, iar în continuare să se aplice căutarea
binară. Sau să se construiască o altă structură de date mai eficientă
pentru căutare.

•Un număr mare de modificări frecvente ale listei pot, de asemenea,


influenţa nefavorabil asupra alegerii acţiunilor ulterioare. O listă cu un
volum mare de înregistrări neordonate necesită restructurarea datelor în
structuri de date ajustate condiţiilor de căutare.

32
Lucrarea de laborator nr.1
„Metode de căutare în tabele”
Termen 3 săptămâni
Să se creeze un fişier textual care conţine cel puţin 50 de
înregistrări, cu cel puţin 5 câmpuri şi are cel puţin 2 tipuri de date,
iar câmpul cheie trebuie să fie unic şi neordonat. Tematica
structurii de date se stabileşte împreună cu profesorul la lecţiile de
laborator.
Să fie realizat un program în C++, în care sunt implementate cel
puţin două metode de căutare în tabele ordonate şi neordonate
după câmpul cheie din fişierul textual creat anterior. Pentru fiecare
metodă de căutare de analizat lungimea medie teoretică şi lungimea
practică de căutare.
De descris algoritmul metodelor de căutare pe paşi.
1 Metoda secvenţială de căutare
3 Metoda de căutarea în tabele neordonate structurate arborescent
2 Metoda binară de căutare
3 Metoda de căutare în tabele ordonate
Un referat la tema „Metode şi procedee de căutare”, prezentat în
1
faţa colegilor

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