Dwa programy mogą dawać ten sam wynik, ale jeden policzy go w milisekundę, a drugi — dla dużych danych — będzie liczył godzinami. Złożoność obliczeniowa to sposób opisania, jak czas (lub pamięć) potrzebny na wykonanie algorytmu rośnie wraz z rozmiarem danych wejściowych n.
Opisuje górne ograniczenie tempa wzrostu liczby operacji w najgorszym przypadku, w miarę jak n rośnie do nieskończoności. Nie interesuje nas dokładna liczba kroków — interesuje nas kształt wzrostu.
| Notacja | Nazwa | Przykład | n = 1 000 000 → liczba operacji (orientacyjnie) |
|---|---|---|---|
| O(1) | Stała | Dostęp do elementu tablicy po indeksie | 1 |
| O(log n) | Logarytmiczna | Wyszukiwanie binarne | ~20 |
| O(n) | Liniowa | Przejście przez wszystkie elementy tablicy | 1 000 000 |
| O(n log n) | Liniowo-logarytmiczna | MergeSort, QuickSort (śr.) | ~20 000 000 |
| O(n²) | Kwadratowa | Dwie zagnieżdżone pętle po tej samej tablicy | 10¹² |
| O(2ⁿ) | Wykładnicza | Naiwna rekurencja Fibonacciego bez memoizacji | astronomiczna |
Jedna pętla przechodząca przez n elementów wykonuje n operacji — złożoność liniowa.
Pętla wewnętrzna wykonuje się n razy dla każdego przebiegu pętli zewnętrznej — razem n × n = n² operacji.
Jeśli w każdym kroku rozmiar problemu zmniejsza się o połowę, liczba kroków potrzebnych do dojścia do 1 wynosi log₂(n) — stąd wyszukiwanie binarne jest tak szybkie.
Dwie pętle jedna po drugiej (nie zagnieżdżone!) to nadal O(n), a nie O(n²) — bo n + n = 2n, a stałe mnożniki pomijamy w notacji O.
Jaka jest złożoność poniższego fragmentu?
O(n²). Mimo że pętla wewnętrzna skraca się z każdym przebiegiem (od i do n), suma liczby kroków to w przybliżeniu n²/2 — a stałe (½) pomijamy w notacji O, więc nadal jest to klasa kwadratowa.
Napisz w Pythonie funkcję suma_liniowa(n) sumującą liczby od 1 do n w pętli, oraz porównaj jej czas działania z wbudowanym wzorem n*(n+1)//2 dla n = 10 000 000, korzystając z modułu time. Zanotuj różnicę czasów — to praktyczna ilustracja różnicy między O(n) a O(1).
1. Jaka jest złożoność algorytmu z jedną pętlą przechodzącą przez wszystkie n elementów tablicy?
2. Dwie zagnieżdżone pętle, obie po n elementów, dają złożoność:
3. Algorytm, który w każdym kroku dzieli dane na pół, ma złożoność:
4. MergeSort ma złożoność czasową: