Big O notācija ir algoritmu salīdzināšanas veids. Tā apraksta, kā algoritma izpildes laiks vai nepieciešamā atmiņa aug, palielinoties ievades datu apjomam. Big O parasti nosaka algoritma asimptotisko augšējo robežu — cik daudz resursu algoritms var prasīt sliktākajā gadījumā.

Kas tiek mērīts: laiks un atmiņa

Ar Big O var mērīt gan laika sarežģītību (cik daudz operāciju vai laika soļu nepieciešams), gan atmiņas sarežģītību (cik papildu atmiņas vietas algoritms izmanto). Laika sarežģītība parasti izsaka, kā izpildes laiks aug attiecībā pret ievades lielumu n, savukārt atmiņas sarežģītība — cik daudz papildus atmiņas (piem., masīvu, sarakstu) algoritms pieprasa.

Bieži sastopamās notācijas un piemēri

  • O(1) — konstanta laika: izpildes laiks nemainās, palielinoties n (piem., piekļuve masīva elementam pēc indeksa). O ( 1 ) {\displaystyle O(1)}{\displaystyle O(1)}
  • O(log n) — logaritmiska: piemēram, binārā meklēšana sakārtotā sarakstā.
  • O(n) — lineāra: algoritma darbības skaits proporcionāls ievades lielumam (piem., vienkārša skenēšana cauri sarakstam).
  • O(n log n) — efekti īstermiņā, piemēram, daudzas sadalīšanas un apvienošanas šķirošanas metodes (merge sort, heapsort).
  • O(n^2) — kvadrātiska: bieži parādās divkāršās cilpas (piem., vienkārša izvēles šķirošana vai burtveidīgs salīdzinājums pāros).
  • O(2^n) un O(n!) — eksponenciālas un faktoriālas: paraugpiemēri no kombinatorikas un izsmeļošu meklēšanas risinājumiem. O ( n ! ) {\displaystyle O(n!)}, {\displaystyle O(n!)}

Sliktākais, labākais un vidējais gadījums

Big O parasti apraksta sliktāko gadījumu (worst-case). Pastāv arī citas notācijas:

  • Ω (Big Omega) — apakšējā robeža (best-case).
  • Θ (Big Theta) — asimptotiska precīza robeža (augšējā un apakšējā robeža vienādas).

Piemēram, kārtošanas algoritmam QuickSort vidējā sarežģītība ir O(n log n), bet sliktākajā gadījumā — O(n^2), ja tiek izvēlēts neveiksmīgs pivot.

Kā aprēķina Big O — pamatprincipi

  • Definē mainīgo n kā ievades lielumu (elementu skaits, bitu skaits u. tml.).
  • Skaita pamatoperācijas atkarībā no n (cilpas, rekursijas izsaukumi, salīdzinājumi).
  • Noņem konstantu koeficientus (piem., 2n → O(n)).
  • Atmet zemākas pakāpes locekļus, kad n → ∞ (piem., n^2 + n → O(n^2)).

Ja ir vairāki secīgi posmi, ņem lielāko rangu (piem., ja viens posms ir O(n) un nākamais O(n^2), kopējais ir O(n^2)). Ja posmi izpildās paralēli (vai tiek izvēlēts viens no tiem), tad izmanto minimālo vai atbilstošo kombināciju atkarībā no konteksta.

Vienkārši kodu piemēri

1) Viena cilpa: for (i = 0; i < n; i++) → O(n).
2) Dubulta cilpa: for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { … } } → O(n^2).
3) Rekursīva dalīšana uz pusēm: T(n) = T(n/2) + O(1) → O(log n) (piem., binārā meklēšana).

Praktiski apsvērumi

Big O ignorē konstantu faktoru un zemākas pakāpes, tāpēc tas ir labs rīks, lai salīdzinātu algoritmu mērogojamību, bet ne vienmēr parāda reālo izpildes laiku mazam vai vidējam n. Konkrētā aparatūra, atmiņas piekļuves kavēšanās (cache), paralēlisms un implementācijas detaļas var būt būtiski. Tāpēc inženieri bieži ņem vērā arī laika komplekta mērījumus un praktisku profilēšanu.

Vēsture

Lielo O apzīmējumu 1896. gadā savas grāmatas "Analytische Zahlentheorie" otrajā izdevumā pirmo reizi izmantoja Pauls Bachmanns (1837–1920). To popularizēja Edmunds Landau (1877–1938), un tāpēc šo pierakstu mēdz saukt arī par Landau simboliem.

Secinājums

Big O notācija ir būtisks instruments datu struktūru un algoritmu analīzē — tā ļauj novērtēt, kā algoritms mērogojas, salīdzināt atšķirīgas pieejas un izprast robežas, kas saistītas ar laiku un atmiņu. Lai pieņemtu praktiskus lēmumus, to vislabāk kombinēt ar reāliem mērījumiem un domāšanu par konkrēto problēmu un aparatūru.