Complexitatea algoritmilor
				
 
				
				
				Introducere
				Studiul complexitǎţii algoritmilor a apǎrut din necesitatea oamenilor de a gǎsi o modalitate prin care 
				sǎ rezolve anumite probleme 
rapid. Deşi calculatoarele cu cele mai noi tehnologii pot executa într-un 
				timp extrem de scurt un set foarte mare de operaţii, anumite probleme, aparent banale, ce conţin multe variabile reale 
				şi cu multe cifre, necesitǎ câteva minute, ore sau chiar ani pentru a fi rezolvate. Deci, "dimensiunea" 
				problemei reprezintǎ un factor important în determinarea complexitǎţii ei.
				
				
Exemple: înmulţirea repetatǎ a unor matrice cu un numǎr foarte mare de elemente, diverse tehnici de prelucrare a imaginilor, ș.a.m.d.
				
				
				
Exprimarea complexității
				
				Fiind dat un anumit algoritm, se pune problema să găsim un indicator care să exprime 
complexitatea sa. 
				Acest indicator va face abstracție de calculatorul pe care rulează programul obținut în urma cuantificării algoritmului într-un limbaj de programare, 
				precum și de limbajul de programare ales. Altfel spus, indicatorul va exprima complexitatea unui algoritm care 
				poate fi redactat în pseudocod, schemă logică sau limbaj de programare.
				
				Presupunem că algoritmul are 
n date de intrare și acestea urmează să fie prelucrate. Indicatorul care exprimă complexitatea va ține cont de acest număr.
				
				
Exemple:
				
 a) Se cere să se calculeze valoarea maximă a unui șir de 
n numere reale;
				
 b) Să se determine dacă 
n numere reale sunt distincte. Se va compara primul număr cu toate celelalte, al doilea cu cele care îi urmează, etc.
				
				Un algoritm conține mai multe operații de atribuire, decizionale, scriere și citire. Acestea se execută de un număr de ori care depinde de 
n, 
				dar și de datele propriu-zise. Teoretic, ar trebui să se determine de câte ori se execută fiecare operație. Cum această cerință este imposibil de realizat în 
				practică, s-a preferat o altă metodă. Mai precis, se alege o operație de bază, se determină de câte ori se execută aceasta și se presupune că 
				restul operațiilor se execută de un număr de ori care este proporțional cu numărul de executări a operației de bază. De regulă, operația de bază aleasă este operația decizională (
if).
				
				
Exemple:
				
 a) Pentru a calcula valoarea maximă a unui șir de 
n numere reale se efectuează 
n-1 comparații.
				
 b) Pentru a determina, prin algoritmul de mai sus dacă 
n numere reale sunt distincte, se efectuează:  
				
				
				
				comparații.
				
				
Exprimarea complexității unui algoritm se face aproximativ. în cazul în care expresia care cuantifică numărul 
				de operații de bază este sub formă de polinom, ca în exemplele date, se precizează numai primul termen al acestuia, 
				fără coeficient. Pentru a preciza că este vorba de o cuantificare aproximativă, vom nota complexitatea prin 
O(f(n)).
				
				
Exemple:
				
 a) Algoritmul care calculează maximul a 
n numere reale are complexitatea 
O(n), deși se efectuează doar 
n-1 comparații. 
				
 b) Algoritmul care decide dacă 
n numere reale sunt distincte are complexitatea 
O(n2), deși se efectuează cel mult 
n(n-1)/2 comparații.
				
				
Algoritmii de complexitate O(n) se mai numesc și algoritmi liniari.
				
				Algoritmii de complexitate O(nk) se mai numesc și algoritmi polinomiali.
				
				
				Complexitate exponențială
				Bineînțeles, există algoritmi care au 
complexitate exponențială, adică de forma 
O(an).
				
				
Exemplu: se cere să se afișeze toate submulțimile mulțimii 
{1,2,...,n}. 
				Avem 
2n submulțimi ale unei mulțimi de numere reale. Dacă considerăm ca operație principală afișarea unei submulțimi, înseamnă că 
				algoritmul are complexitatea 
O(2n).
				
				
În practică trebuie evitați algoritmii care nu au complexitate polinomială. Imaginați-vă că pentru un 
n dat, 
				un calculator performant rulează programul într-o oră. Dacă mărim pe 
n cu 
10, avem 
2n+10 operații elementare, 
				adică 
1024 × 2n operații. Prin urmare, programul va rula pe același calculator 
1024 de ore. Dar dacă mărim pe 
n cu 
1000? 
				Practic, pentru valori nu prea mari ale lui 
n, 
algoritmii exponențiali sunt de neutilizat.
				
				Există și algoritmi care sunt asimilați celor exponențiali, precum cei 
factoriali.
				
				
Exemplu: se cere să se afișeze toate permutările mulțimii 
{1,2,...n}. Avem 
n! permutări. 
				Dacă considerăm ca operație de bază afișarea unei permutări, avem 
n! operații elementare, deci algoritmul are complexitatea 
O(n!). 
				Dar 
n!=1×2×3×...×n > 1×2×2×...×x2=2n-1.
				
				
				
Complexitate logaritmică
				Există și algoritmi care au complexități de forma 
O(log(n)), 
O(n×log(n)), 
O(n2×log(n)), unde prin 
log(n) înțelegem 
log2(n).
				Rețineți: 
				
				
				
				Cu alte cuvinte, prin 
logaritm în baza 2 din 
x (
log2(x)) înțelegem 
puterea la care trebuie ridicat numărul 2 astfel încât 
2n=x. 
				
				
Exemplu: log2(1024) = 10 < 1024.				
				
				
				
Nedeterminist Polinomial
				În anii 1960 deja apǎruserǎ anumite probleme, aparent simple, care nu se puteau rezolva în timp polinomial. 
				Astfel, s-a decis ca, pentru a afirma cǎ o problemǎ se poate rezolva în timp polinomial, 
o soluţie corectǎ trebuie sǎ poatǎ 
				fi verificatǎ în timp polinomial de algoritmul propus.
				
				Acest procedeu se numeşte 
certificarea soluţiei şi a impus apariţia unei noi clase, 
NP. 
				O clasǎ de probleme pentru care se pot verifica rǎspunsurile corecte în timp polinomial se numeşte 
NP (
Nedeterminist Polinomial).
				
				O problemǎ este 
NP-dificilǎ dacǎ un algoritm pentru rezolvarea sa poate rezolva oricare altǎ problemǎ din clasa 
NP. 
				Cu alte cuvinte, 
orice problemǎ NP se reduce polinomial la ea.
				
				Anumite probleme 
NP sunt 
extrem de dificile şi 
S. Cook a demonstrat cǎ dacǎ una 
				dintre ele se poate rezolva în timp polinomial, atunci toate problemele 
NP pot fi rezolvate în timp polinomial (1971). 
				Acestǎ afirmaţie poartǎ denumirea de "
Teorema lui Cook", iar clasa acestor probleme se numeşte 
				
NP-completǎ. Acest rezultat a fost descoperit şi publicat (1973), independent, de cǎtre 
Leonid Levin în U.R.S.S.
				
				O problemǎ este 
NP-completǎ dacǎ orice problemǎ 
NP-dificilǎ se reduce polinomial la ea.
				
				Existǎ o serie de probleme 
NP-complete pentru care încǎ nu au fost descoperite soluţii...
				
				
				
Bibliografie
				1. "
Tehnici de Optimizare - Aplicații", autori: Călin SOARE, Vlad TUDOR, ISBN: 978-973-7658-09-8, Editura L&S Infomat, București.
				
				2. "
Bioinformatica", autor: Victor MITRANA, ISBN: 978-973-7658-22-7, Editura L&S Infomat, București.
				
				3. "
Manual de Informatică pentru clasa a IX-a, profilul real intensiv (varianta C++)", autor: Tudor Sorin, ISBN: 978-973-7658-30-2, Editura L&S Infomat, București.
				
				
				
					
					Articolul s-a încheiat acum.
					
					
				 
				
				
					Cărțile editurii noastre
				
				
				
				
				O parte dintre manualele și culegerile de probleme se găsește și [
în format electronic] 
				securizat sub formă 
de fișier *.pdf.
				
				
				
				"
O cameră fără cărţi este ca un corp fără suflet." 
(G. K. Chesterton)
				
				
				
					Cursanții au mai cumpărat ...
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				
				[
vezi lista completă a cărților]