Big O (Didysis O) – tai būdas palyginti algoritmus pagal tai, kiek jie reikalauja laiko ir atminties vykdymo metu. Big O nurodo, kaip algoritmo resursų poreikis auga priklausomai nuo duomenų dydžio (dažniausiai žymimo n). Tai leidžia įvertinti algoritmo efektyvumą nepriklausomai nuo konkrečios techninės įrangos.

Istoriškai Didįjį O pirmąkart panaudojo Paulas Bachmannas (1837–1920) 1896 m., o vėliau šią notaciją išpopuliarino Edmundas Landau (1877–1938). Dėl to kartais ši notacija vadinama Landau simboliais. Ji padeda priskirti problemas tam tikroms sudėtingumo klasėms pagal reikiamus resursus.

Intuityvus paaiškinimas

Big O nurodo funkcijos augimo tvarką — viršutinę ribą (didžiausią galimą dydį) kai n didėja. Kitaip tariant, jis atsako į klausimą: „Kaip ilgai (ar kiek atminties) užtruks algoritmas, kai įvesties dydis auga?“ Big O dažniausiai apibrėžia blogiausią atvejį (worst case), todėl suteikia konservatyvų, patikimą vertinimą.

"Big O" užrašas pavadintas pagal terminą "funkcijos tvarka", kuris reiškia funkcijų augimą. Big O užrašas naudojamas funkcijos augimo greičio viršutinei ribai (didžiausiam įmanomam dydžiui) rasti, t. y. nustatomas ilgiausias laikas, per kurį įvestis bus paversta išvestimi. Tai reiškia, kad algoritmą galima sugrupuoti pagal tai, kiek laiko jis gali užtrukti blogiausiu atveju, kai kiekvieną kartą bus pasirinktas ilgiausias kelias.

"Big O" - tai išraiška, kuria nustatomas blogiausio scenarijaus vykdymo laikas, parodantis, koks yra algoritmo efektyvumas, nepaleidžiant programos kompiuteryje. Tai naudinga ir todėl, kad skirtinguose kompiuteriuose gali būti skirtinga techninė įranga, todėl jai atlikti gali prireikti skirtingo laiko. Kadangi "Big O" visada numato blogiausią atvejį, galima nuosekliai išmatuoti greitį: nepriklausomai nuo jūsų techninės įrangos, "O ( 1 )" {\displaystyle O(1)}{\displaystyle O(1)} visada bus baigtas greičiau nei "O ( n ! )" {\displaystyle O(n!)}, {\displaystyle O(n!)}nes jų efektyvumas skiriasi.

Formalus apibrėžimas

Sakome, kad f(n) = O(g(n)), jei egzistuoja teigiama konstanta C ir skaičius n0 tokie, kad visiems n ≥ n0 yra f(n) ≤ C·g(n). Tai reiškia: kai n tampa pakankamai didelis, f(n) neauga greičiau nei konstantiniu koeficientu padauginta g(n).

Dažniausiai pasitaikančios sudėtingumo klasės (nuo geriausios iki blogiausios)

  • O(1) – konstantinė: vykdymo laikas nekinta augant n (pvz., prieiga prie masyvo elemento).
  • O(log n) – logaritminė: pvz., binarinė paieška suskaidant paieškos sritį per pusę.
  • O(n) – linijinė: pvz., vienas ciklas per visus elementus.
  • O(n log n) – daugumai efektyvių rūšiavimo algoritmų (pvz., merge sort, heap sort).
  • O(n^2) – kvadratinė: dažnai gaunama iš dviejų įdėtų ciklų (pvz., paprastas rūšiavimas).
  • O(2^n) – eksponentinė: dažnai susijusi su visų galimų kombinacijų tikrinimu.
  • O(n!) – faktorialinė: labai lėti algoritmai (pvz., permutacijų generavimas be heuristikų).

Pavyzdžiai ir taisyklės analizėje

  • Vienas ciklas per n elementų: O(n).
  • Dviejų įdėtų ciklų, kiekvienas nuo 1 iki n: O(n^2).
  • Konsektyvūs žingsniai: O(f(n) + g(n)) → imama didžiausia iš abiejų (pvz., O(n) + O(n^2) = O(n^2)).
  • Multiplikacija priklausoma nuo įdėtos struktūros: pvz., už kiekvieno iš n elementų atliekama log n operacija → O(n log n).
  • Ignoruojami konstantiniai koeficientai ir žemesnės eilės terminai: O(2n) = O(n), O(n + log n) = O(n).

Laiko ir atminties sudėtingumas

Big O gali taikyti ne tik vykdymo laikui, bet ir atminties naudojimui (space complexity). Pvz., algoritmas, kuris laikinai saugo papildomą masyvą dydžio n, turi O(n) atminties sudėtingumą.

Geriausias, vidutinis ir blogiausias atvejai

Analizė gali skirtis priklausomai nuo atvejo:

  • Best case – geriausias atvejis (pavyzdžiui, paieška randa elementą pirmame žingsnyje).
  • Average case – vidutinis atvejis (reikia apskaičiuoti vidutinį vykdymo laiką pagal visus galimus įvesties atvejus).
  • Worst case – blogiausias atvejis (dažnai naudojamas praktikoje, kadangi tai saugiausias įvertinimas).

Amortizuota sudėtingumo analizė

Kai kurios duomenų struktūros (pvz., dinaminių masyvų išplėtimas arba HashMap operacijos) turi amortizuotą laiką: pavienės operacijos gali būti brangios, bet ilgalaikė vidutinė kaina vienai operacijai yra mažesnė. Tokiu atveju nurodoma amortizuota sudėtingumo riba, pvz., push amortizuotai O(1).

Praktiniai patarimai, kaip skaičiuoti Big O

  • Suskaičiuok pagrindinius veiksmus arba ciklus, kurie auga su n.
  • Pabandyk supaprastinti: atsisakyk pastovių koeficientų ir mažesnės eilės terminų.
  • Analizuok rekursijas per rekurenčiųjų lygtis (recurrence), naudok Master teoremą, kai tinka.
  • Atkreip dėmesį į duomenų struktūrą – pasirinkimas (masyvas, sąrašas, rinkinys, žemėlapis) gali pakeisti sudėtingumą.

Trumpi pavyzdžiai

  • Lineinė paieška: for(i=0;i
  • Dviejų lygių ciklas: for(i=0;i
  • Binarinė paieška (rūšiuotame sąraše): O(log n).
  • Merge sort: O(n log n) laiko ir O(n) papildomos atminties.

Apibendrinant: Big O yra paprasta, bet galinga priemonė, leidžianti objektyviai palyginti algoritmus pagal jų elgesį augant duomenų kiekiui. Ji neatsako į visus praktinius klausimus (pvz., konkrečios mašinos greitį arba konstantų poveikį mažiems n), tačiau suteikia aiškų ir formalų būdą įvertinti ir pasirinkti efektyvesnius sprendimus.