Sunteți pe pagina 1din 27

Algoritmi și structuri de date – curs 1

- Informatică Economică, an II –

Concepte de bază
Complexitatea algoritmilor
Metode de sortare de bază

Cristian Bologa
Cuprins
Conceptul de algoritm
Complexitatea algoritmilor. Analiza eficienței algoritmilor
Sortarea prin insertie
Sortare prin interclasare
Obiective
Deprinderea modului de proiectare si analiză a algortimilor
Studiul principalelor structuri de date utilizare in activitatea de
programare
Studiul unor probleme algoritmice clasice și furnizarea de solutii la
acestea
Imbunătățirea abilităților de programare utilizând limbajul C

Organizare

http:://bis.econ.ubbcluj.ro/moodle
Cursul Algoritmi si Structuri de date
Cerinţe, evaluare
Probă teoretică: 40% - Examen scris în sesiune

Probă practică: 40% -1 problema

Activitate 20% -intalniri fata in fata (18 ore) + activitati tutoriale la


distanta (16 ore)

Necesar: minim 5 la fiecare probă de examen


Bibliografie
 T.H. Cormen, C. Leiserson, R.R. Rivest, C. Stein, Introduction to
Algorithms, 3rd edition, The MIT Press, 2009

 Traducere in limba română


Algoritmi – definiții fundamentale (I)
Definiția conceptului de algoritm
O procedura de calcul bine definită, care primește ca și intrare un set de valori și
produce la ieșire un set de valori

Exemplu: definirea problemei de sortare a unui șir de numere:


Input: o secvență de n numere 𝑎1 , 𝑎2 , … , 𝑎𝑛
Output: o permutare (sau o reordonare) 𝑎′1 , 𝑎′2 , … , 𝑎′𝑛 a secvenței de
numere furnizată la intrare, astfel încât 𝑎′1 ≤ 𝑎′2 ≤ ⋯ ≤ 𝑎′𝑛

Un algoritm de sortare, pentru o anumită secvență de numere input 31, 41, 59,
26 va produce ca și output secvența 26, 31, 41, 59.
O instantă a problemei o constituie o secvență de intrare care satisface
condițiile problemei
Algoritmi – definiții fundamentale (II)
Un algoritm se spune că este corect dacă pentru orice secvență de intrare care
satisface condițiile problemei va produce la ieșire un rezultat (output) corect

Spunem că algoritmul respectiv rezolvă problema computațională furnizată.

O structură de date reprezintă un mod de a organiza și stoca datele astfel încât să


facilităm accesul la ele și modificarea acestora

Tehnici care vor fi acoperite în acest curs:


Tehnici de proiectare a algoritmilor
Tehnici de analiză a algoritmilor astfel încât să putem decide asupra
corectitudinii algoritmilor și
eficienței acestora
Pseudocod
Modalitate de a descrie algoritmi
Similar cu schemele logice
Un algoritm descris in pseudocod poate apoi sa fie implementat in orice
limbaj de programare (C, Pascal etc).
Convenții de notare
 Indentarea descrie o structura de tip bloc
 If-then-else, precum si structurile repetitive while, for, repeat-until au
semnificație similară cu cea din C
 // este utilizat pentru comentarii
 Variabilele sunt locale fiecarei proceduri
 Transmiterea parametrilor in proceduri se realizează intotdeauna prin
valoare
 Operatorii logici and si or se evaluează prin scurt-circuitare
Necesitatea studierii algoritmilor
Dacă calculatoarele ar avea o viteză de execuție infinită, atunci orice
metodă corectă de rezolvare a unei probleme ar fi potrivită

Calculatoarele au viteze de execuție limitate


Spațiile de memorare ale calculatoarelor sunt ieftine dar nu gratuite
=> Nu orice algoritm corect funcționează în mod utilizabil pe orice resurse
de calcul

Eficiența unui algoritm:


 se referă la resursele de calcul și memorie necesare pentru execuția
algoritmului
 Poate fi mult mai importantă decât capabilitățile hardware și software ale
calculatorului care rulează algoritmul
Necesitatea studierii algoritmilor (II)
n O(n) O(n*ln(n) O(n2) O(n3) O(2n)
2 2 1,38 4 8 4
5 5 8,04 25 125 32
10 10 23 100 1.000 1.024
20 20 59 400 8.000 1.048.576
30 30 102 900 27.000 1.073.741.824
40 40 147 1.600 64.000 1,09E+12
50 50 195 2.500 125.000 1,12E+15
100 100 460 10.000 1.000.000 1,26E+30
1000 1.000 6.907 1.000.000 1.000.000.000 1,07E+301

-calculator capabil să efectueze 109 instrucţiuni/secundă:


n O(n) O(n*ln(n)) O(n2) O(n3) O(n4) O(n10) O(2n)
1 10 1 3,2*1013 3,2*10283
s s
1.000 1.000.000 1.000.000 1.000 1s 17 min ani ani
s
10 130 100
s s
10.000 1.000.000 1.000.000 1.000 17 116 ? () ? ()
s min zile
1 20 3*107
6 s s
10 1.000 1.000 17 32 ani ani ? () ? ()
min
Analiza unui algoritm
Inseamnă să identificăm resursele necesare execuției algoritmului
 Memorie, latime de bandă pentru comunicații, hardware necesar etc.
Utilizarea unui model generic de calculator
 Un singur procesor
 Model random-access machine pentru procesor: instructiunile se execută
secvențial (una după alta), și nu există posibilitate de concurență
 Se presupune că instrucțiunile permise pe procesor se execută toate intr-un
timp constant
 Presupunem că procesorul poate lucra cu date de tip intreg sau flotant, fără
ca precizia să fie de larg interes (in demersul nostru de analiză a
algoritmului)
Complexitatea algoritmilor
Un algoritm liniar are complexitatea O(n), unul pătratic O(n2) iar
unul cubic O(n3).

Un algoritm se numeşte polinomial dacă are o complexitate


egală cu O(p(n)) unde p(n) este o funcţie polinomială.

Altă clasă de algoritmi sunt cei exponenţiali. Sunt asimilaţi


algoritmilor exponenţiali şi cei de forma n*ln(n) deşi matematic
nu sunt nici polinomiali nici exponenţiali.
Complexitatea algoritmilor (II)
Rata de creștere a timpului de execuție: ne interesează doar termenul
cel mai semnificativ din T(n), adică 𝑎𝑛2 .
=>complexitatea Θ(𝑛2 )

Un algoritm este mai eficient decât altul dacă are o rată de creștere
mai mică, pentru cazul cel mai defavorabil

Eficiența asimptotică a algoritmilor: atunci când rata de creștere a


timpului de execuție devine esențială considerând mărimi mari ale
setului de date de intrare
Notiuni despre sortare
Algoritmi de sortare:
 Ascendentă
 Descendentă

 Interni
 Externi

Sortare stabilă

Sortare “in situ”


Sortarea prin inserție
Ideea de sortare:
Pornim cu un sir gol de
numere
Luăm câte un număr din șirul
inițial și il plasăm in sirul
sortat la poziția
corespunzătoare
Plasarea numărului in șir la
poziția corespunzătoare se
face prin comparare succesivă
de la stânga la dreapta sau
invers
Sortarea prin inseție

Loop invariant: la fiecare început al iterației for, subșirul A[1..j-1] este format din
exact aceleași elemente care se alfă la inceputul sortării în subșirul A[1..j-1], dar într-
o ordine sortată
Inițializare: condiția Loop invariant este adevărată înainte de execuția buclei for
Mentenanță: condiția Loop invariant este adevărată înaintea inceperii unei iterații din
bucla for și rămâne adevărată inaintea inceperii următoarei iterații
Terminare: condiția Loop invariant este adevărată după execuția buclei for – astfel,
ne furnizează o proprietate esențială pentru a demonstra că algoritmul este corect
Analiza sortării prin inseție
Mărimea datelor de intrare (input size): in general, este numărul de
itemi din setul de intrare
Timpul de execuție: reprezintă numărul de operații primitive necesar a
se executa pentru ca algoritmul să ajungă la soluție
 Este necesar să se definească operația primitivă într-un mod independent
de mașina de calcul
Analiza sortării prin inseție
Cazul cel mai favorabil (best case): sirul este deja sortat. =>𝑡𝑗 = 1
 𝑇 𝑛 = 𝑎𝑛 + 𝑏
Cazul cel ma idefavorabil (worst case): sirul este in ordine inversă: 𝑡𝑗 =j
 𝑇 𝑛 = 𝑎𝑛2 + 𝑏𝑛 + 𝑐
În majoritatea cazurilor, la analiza unui algoritm trebuie să ne concentrăm
pe analiza cazului cel mai defavorabil

Cazul cel mai defavorabil: pentru o anume dimensiune n a datelor de


intrare, reprezintă acele date de intrare care generează timpul de execuție
maxim al algoritmului
 furnizează o limită superioară pentru timpul de execuție
 Analiza cazului cel mai defavorabil ne garantează că timpul de execuție nu va fi
nicicând mai rău

Cazul mediu (average): 𝑡𝑗 = 𝑗/2. => timp de execuție funcție pătratică


Recursivitate
Mecanism prin care un subprogram (procedură, funcţie) se
autoapelează.

Un algoritm recursiv poate avea un echivalent nerecursiv şi invers.

Implementarea recursivităţii are la bază structura de date denumită


stivă.
 Stiva este acea formă de organizare a datelor (structură de date) cu proprietatea că
operaţiile de introducere şi scoatere a datelor se fac în vârful ei.
 O stivă funcţionează după principiul LIFO („Last in First Out”, în traducere „Ultimul
intrat, primul ieşit”).

Din punct de vedere al modului în care se realizează autoapelul, există


două tipuri de recursivitate:
 Directă :procedura (sau funcţia) se autoapelează (în corpul său). Exemplul clasic este
definirea funcţiei factorial: n!=(n-1)!n, 0!=1, nN.
 Indirectă: are loc atunci când o procedură (funcţie) apelează o altă procedură
(funcţie), care la rândul ei o apelează pe ea. Ex: 2 valori reale, pozitive a0,b0 şi n un
număr natural. Definim şirurile: an=(an-1+bn-1)/2 bn=an-1bn-1
Recursivitate

Exemplu: 3! Exemplu: 5!
Exemplu: Sirul lui Fibonacci

PERECHI
de perechi
Recursivitate / divide-and-conquer
Abordare divide-and-conquer (divide et impera):
 problema initială se sparge in subprobleme cu structură similară cu
problema originală, dar de dimeniune mai mică.
 aceste subprobleme sunt rezolvate recursiv
 solutiile recursive sunt combinate pentru a produce solutia problemei initiale

Metoda se poate aplica în rezolvarea unei probleme care îndeplineşte


următoarele condiţii:
 se poate descompune în două sau mai multe subprobleme
 aceste suprobleme sunt independente una faţă de alta (o subproblemă nu se rezolvă
pe baza alteia şi nu foloseşte rezultatele celeilalte)
 aceste subprobleme sunt similare cu problema iniţială
 la rândul lor subproblemele se pot descompune (dacă este necesar) în alte
subprobleme mai simple
 aceste subprobleme simple se pot soluţiona imediat prin algoritmul simplificat
Sortare prin interclasare (Merge Sort)
Divide: sirul A de n elemente se imparte in 2 subsiruri de n/2 elemente
Conquer: se sortează recursiv cele 2 subsiruri
Combine: se combină prin interclasare cele 2 siruri sortate obtinute la
pasul conquer

Recursivitatea se incheie la sirurile de lungime 1, care implicit sunt deja


sortate

Merge(A, p, q, r): interclasarea subsirurilor sortate A[p,q] și A[q+1, r]


Complexitatea procedurii Merge: Θ(𝑛), unde 𝑛 = 𝑟 − 𝑝 + 1
Sortare prin interclasare (Merge Sort)

16529473

1652 9473

16 52 94 73

1 6 5 2 9 4 7 3

16 25 49 37

1256 3479

12345679
Procedura de interclasare
Loop invariant
La inceputul buclei for
din linia 12 au simultan
loc următoarele condiții:
1. A[p..k-1] conține k-p
cele mai mici elemente
din L și R
2. L[i] și R[j] sunt cele mai
mici elemente din L și R
Sortare prin interclasare - pseudocod
Complexitatea algoritmilor
divide-and-conquer
Problema de dimensiune 𝑛 se imparte in 𝑎 subprobleme de dimensiune
1/𝑏 din problema originală
𝐷(𝑛) – timpul de execuție necesar pentru pasul divide
𝐶(𝑛) – timpul de execuție necesar pentru pasul combine

Pentru a calcula T(n) se rezolvă recurența de mai jos:

Θ 1 , 𝑑𝑎𝑐ă 𝑛 ≤ 𝑐
𝑇 𝑛 =ቐ 𝑛
𝑎𝑇 + 𝐷 𝑛 + 𝐶 𝑛 , 𝑖𝑛 𝑐𝑎𝑧 𝑐𝑜𝑛𝑡𝑟𝑎𝑟
𝑏
Complexitatea sortarii prin interclasare
Pasul divide: 𝐷 𝑛 = 1
Pasul combine: procedura Merge: 𝐶 𝑛 = Θ(𝑛)
Pasul conquer: problema se imparte in 2 subprobleme de mărime 𝑛/2,
𝑛
deci acestea contribuie cu 2𝑇(2 )

Trebuie rezolvată recurența:


Θ(1) 𝑑𝑎𝑐ă 𝑛 = 1
𝑇 𝑛 =ቐ 𝑛
2𝑇 + Θ(𝑛) 𝑑𝑎𝑐ă 𝑛 > 1
2
Rezultă:
𝑇 𝑛 = Θ(𝑛𝑙𝑜𝑔2 𝑛)

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