Príklady

Prejdime si zopár príkladov programov a skúsme určiť ich časovú zložitosť v O-notácií.

1. príklad

x = 0
for i in range(4 * n):
    x = x + 2 * i
Riešenie Tento program má časovú zložitosť $O(n)$. Prejdime si riadky programu: - `x = 0`: Táto operácia sa vykoná len raz, a keďže ide o elementárnu operáciu, jej časová zložitosť je $O(1)$. - `for i in range(4 * n)`: Toto je hlavný cyklus programu. Určuje, koľkokrát sa zopakujú operácie vo vnútri. Cyklus sa vykoná $4n$ krát (pre $i$ od 0 po $4n-1$). Keďže počet opakovaní je $4n$ a konštantu zanedbávame, zložitosť tohto cyklu je $O(n)$. - `x = x + 2 * i`: Operácie vo vnútri cyklu (násobenie, sčítanie a priradenie) sú elementárne operácie, každá z nich trvá konštantný čas, teda $O(1)$. Keďže sa operácie vo vnútri cyklu opakujú $4n$-krát, celková časová zložitosť programu je daná počtom jeho opakovaní. V O-notácií zanedbávame konštanty, takže celková zložitosť programu je $O(n)$.

2. príklad

j = 1
while j*j <= n:
  j += 1
Riešenie Tento program má časovú zložitosť $O(\sqrt{n})$. Znovu, časová zložitosť bude závisieť od počtu opakovaní cyklu. Podmienka cyklu kontroluje, či je $j^2$ menšie alebo rovné $n$. Cyklus pokračuje, kým je táto podmienka splnená. - Premenná $j$ sa v každej iterácií zvyšuje o 1. - Cyklus sa zastaví, keď $j^2$ prekročí $n$, čiže $j \approx \sqrt{n}$. - Napríklad, pre $n=10$ cyklus pobeží až kým $j$ nebude 10. Ak potom $j$ dosiahne hodnotu 11, $11^2 = 121$, čo je väčšie ako $10^2$, a cyklus sa zastaví.

3. príklad

a = 0
k = n * n
while k > 1:
    for j in range(0, n * n, 1):
        a += 1
    k /= 2
Riešenie Tento program má zložitosť $O(n^2 log(n))$. Začnime analýzou vnútorného `for`-cyklu. Operácia v ňom (`a += 1`) trvá konštantný čas. Samotný cyklus sa vykoná $n^2$-krát, teda jeho celková časová zložitosť je $O(n^2)$. Vonkajší cyklus je o niečo komplexnejší. Premenná $k$ začne na hodnote $n^2$. V každej iterácií cyklu sa hodnota $k$ vydelí dvomi (`k /= 2`). Tento cyklus bude bežať pokým sa hodnota $k$ nezníži na 1 alebo menej. Koľkokrát musíme $n^2$ vydeliť dvomi, kým dostaneme $k = 1$? Je to ekvivalentné nájdeniu riešenia v rovnici $2^x = n^2$. Riešením tejto rovnice je $x=log_2(n^2)$. Pomocou vlastností logaritmov je to ekvivalentné s $x=2 log_2(n)$. Konštantný faktor 2 a základ logaritmu zanedbáme, takže vonkajší cyklus sa vykoná $O(log(n))$-krát. Celková časová zložitosť: Keďže vnútorný cyklus ($O(n^2)$) sa vykoná pri každej iterácií vonkajšieho cyklu ($O(log(n))$), celková zložitosť bude súčinom zložitostí týchto cyklov, teda $O(n^2 log(n))$.

4. príklad

arr = [...] # len(arr) = n
blocks = 0
i = 0
while i < len(arr):
    blocks += 1
    j = i + 1
    while j < len(arr) and arr[i] == arr[j]:
        j += 1
    i = j
Riešenie Tento program má časovú zložitosť $O(n)$. Začnime analýzou dvoch cyklov, ktoré vidíme: vonkajší while cyklus s premennou $i$ a vnútorný while cyklus s premennou $j$. Vnútorný cyklus: `while j < len(arr) and arr[i] == arr[j]` - Operácia vo vnútri cyklu (`j += 1`) trvá konštantný čas, teda $O(1)$. - Tento cyklus sa spúšťa pre každú iteráciu vonkajšieho cyklu. - Kľúčové pozorovanie: Premenná $j$ sa nikdy neresetuje na 0 v rámci vonkajšieho cyklu. Namiesto toho začína od $i + 1$ a pokračuje v posúvaní dopredu. Po skončení vnútorného cyklu sa hodnota $j$ priradí do premennej $i$. To znamená, že $i$ "preskočí" všetky prvky, ktoré už boli spracované vnútorným cyklom $j$. Vonkajší cyklus: `while i < len(arr)` - Operácie vo vnútri tohto cyklu (ako `blocks += 1`, `j = i + 1`) trvajú konštantný čas, teda $O(1)$. - Hlavným faktorom je to, koľkokrát sa vykoná vnútorný cyklus. Aj keď tu máme dva vnorené while cykly, celková časová zložitosť nie je $O(n^2)$. Prečo? Predstavte si, že ukazovatele $i$ a $j$ začínajú na nule a pohybujú sa smerom ku koncu poľa. Každý z týchto ukazovateľov ($i$ aj $j$) prejde celým poľom maximálne raz. - Ukazovateľ $j$ sa v každej iterácii vnútorného cyklu posúva dopredu o 1. Celkovo sa $j$ posunie od 0 po `len(arr) - 1)` len raz za celý beh algoritmu. - Ukazovateľ $i$ sa posúva na pozíciu, kde sa zastavil $j$, čo znamená, že aj $i$ prejde poľom len raz (preskakuje už spracované bloky). Pretože každý prvok poľa `arr` je navštívený a spracovaný len konštantný počet krát, celkový počet operácií je priamo úmerný dĺžke poľa $n$. Celková časová zložitosť tohto algoritmu je teda $O(n)$.

5. príklad

x = 0
for i in range(n):
    for j in range(m):
        x += 1
Riešenie Tento program má časovú zložitosť $O(nm)$. Rozoberme si jednotlivé časti: - `for i in range(n)`: Tento vonkajší cyklus sa vykoná $n$-krát. - `for j in range(m)`: Tento vnútorný cyklus sa vykoná $m$-krát pre každú iteráciu vonkajšieho cyklu. - `x += 1`: Operácia s konštantnou časovou zložitosťou $O(1)$. Celková časová zložitosť: Vzhľadom na to, že vnútorný cyklus beží $m$-krát pre každú z $n$ iterácií vonkajšieho cyklu, operácia `x += 1` sa vykoná celkovo $n \cdot m$ krát. Preto je celková časová zložitosť programu $O(nm)$.