Ce înseamnă eficiența unui algoritm?
Imaginează-ți că vrei să găsești un cuvânt într-un dicționar cu 1.000.000 de cuvinte:
- 🐢 Verifici pagină cu pagină de la început → maxim 1.000.000 pași → O(n)
- 🚀 Cauți la mijloc, elimini jumătate (căutare binară) → maxim 20 pași → O(log n)
Pe 1 miliard de elemente: O(n) = 1 miliard de operații, O(log n) = doar 30. Eficiența contează enorm!
Analizăm două tipuri:
Numărul de operații elementare executate
Memoria suplimentară utilizată de algoritm
Notații asimptotice: O, Ω, Θ
Notațiile asimptotice descriu comportamentul unui algoritm pentru n → ∞, ignorând constantele și termenii de ordin inferior.
Limita superioară (worst case)
f(n) ≤ c · g(n) pentru n ≥ n₀
Limita inferioară (best case)
f(n) ≥ c · g(n) pentru n ≥ n₀
Limita exactă (tight bound)
c₁·g(n) ≤ f(n) ≤ c₂·g(n)
Reguli de simplificare
Clase de complexitate
| Clasă | n = 10 | n = 100 | n = 1000 | n = 10⁶ |
|---|---|---|---|---|
| O(1) | 1 | 1 | 1 | 1 |
| O(log n) | ~3 | ~7 | ~10 | ~20 |
| O(n) | 10 | 100 | 1 000 | 1 000 000 |
| O(n log n) | ~33 | ~664 | ~10 000 | ~2×10⁷ |
| O(n²) | 100 | 10 000 | 10⁶ | 10¹² |
| O(2ⁿ) | 1 024 | 10³⁰ | 10³⁰⁰ | ∞ |
📈 Grafic interactiv Big-O
Complexitate timp — exemple practice
O(1) — Acces la element în tablou
int x = v[5]; // O(1) — acces direct, indiferent de n int suma = a + b; // O(1) — operație aritmetică
O(n) — Parcurgere simplă
for (int i = 0; i < n; i++) { cout << v[i]; // executat de n ori → O(n) }
O(n²) — Bucle imbricate
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) suma += v[i] * v[j]; // n × n = n² operații
O(log n) — Căutare binară
int cautareBinara(int v[], int n, int x) { int st = 0, dr = n - 1; while (st <= dr) { int mij = (st + dr) / 2; if (v[mij] == x) return mij; else if (v[mij] < x) st = mij + 1; else dr = mij - 1; } return -1; // la fiecare pas intervalul se înjumătățește → O(log n) }
Analiza corectă — cazuri speciale
// Două bucle SEPARATE (nu imbricate) → O(n) + O(n) = O(n) for (int i = 0; i < n; i++) suma1 += v[i]; for (int i = 0; i < n; i++) suma2 += v[i]; // Total: O(n), nu O(n²)
// Jumătate din n la fiecare pas → log₂n pași → O(log n) while (n > 1) n /= 2;
Complexitate spațiu
Complexitatea spațiu se referă la memoria suplimentară folosită de algoritm (nu se numără inputul în sine).
Algoritmul folosește doar câteva variabile auxiliare, indiferent de n
Exemplu: bubble sort in-placeSe alocă un tablou auxiliar de dimensiune n
Exemplu: merge sort (tablou temp)// O(1) spațiu — sortare prin selecție, in-place for (int i = 0; i < n-1; i++) { int minIdx = i; for (int j = i+1; j < n; j++) if (v[j] < v[minIdx]) minIdx = j; swap(v[i], v[minIdx]); // O(1) memorie extra }
// O(n) spațiu — copiere tablou int copie[100001]; for (int i = 0; i < n; i++) copie[i] = v[i]; // n elemente suplimentare
Algoritmi de sortare — comparație
| Algoritm | Best | Average | Worst | Spațiu | Stabil |
|---|---|---|---|---|---|
| Bubble Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ |
| Selection Sort | O(n²) | O(n²) | O(n²) | O(1) | ❌ |
| Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | ✅ |
| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | ✅ |
| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | ❌ |
| Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | ❌ |
| Counting Sort | O(n+k) | O(n+k) | O(n+k) | O(k) | ✅ |
📊 Comparație algoritmi de sortare
Bubble Sort — implementare C++
void bubbleSort(int v[], int n) { for (int i = 0; i < n-1; i++) { bool swap_facut = false; for (int j = 0; j < n-i-1; j++) { if (v[j] > v[j+1]) { swap(v[j], v[j+1]); swap_facut = true; } } if (!swap_facut) break; // optimizare: șirul deja sortat } // Complexitate: O(n²) worst/average, O(n) best }
Selection Sort — implementare C++
void selectionSort(int v[], int n) { for (int i = 0; i < n-1; i++) { int minIdx = i; for (int j = i+1; j < n; j++) if (v[j] < v[minIdx]) minIdx = j; if (minIdx != i) swap(v[i], v[minIdx]); } // Complexitate: O(n²) în toate cazurile }
Animație — Bubble Sort
Apasă Start pentru a vedea cum funcționează Bubble Sort pas cu pas. Barele de culoare portocalie sunt comparate, cele verzi sunt la locul final.
Probleme tip BAC — rezolvate
for(i=1; i<=n; i++) for(j=1; j<=i; j++) s = s + i*j;
i = n; while(i > 1) i = i / 2;
int freq[1001] = {0}; bool duplicat = false; for(int i = 0; i < n; i++) { freq[v[i]]++; if(freq[v[i]] > 1) { duplicat = true; break; } } // O(n) timp, O(k) spațiu unde k = domeniu valori
Referințe și resurse
UPB — Facultatea de Automatică
UniBuc — Facultatea de Matematică-Informatică
UBB Cluj — Informatică
TUIASI Iași — Calculatoare
pbinfo.ro — probleme BAC & olimpiadă
infoarena.ro — concursuri RO
LeetCode — pregătire interviuri IT
HackerRank — exerciții structurate
VisuAlgo — animații algoritmi
bigocheatsheet.com
cppreference.com — referință C++
Khan Academy