Treci la conținutul principal

Patru reguli simple

Transformarea întrebării „câți pași face acest cod” într-o clasă Big O se face cu patru reguli:

1. Păstrează cazul cel mai rău — numără cei mai mulți pași de care poate avea nevoie codul.
2. Renunță la constante — O(2n) și O(n/2) sunt amândouă O(n).
3. Renunță la termenii mai mici — O(n + n²) este O(n²).
4. Intrări diferite primesc litere diferite — două slice-uri diferite dau O(a · b), nu O(n²).

Fiecare regulă are câte un exemplu mai jos.


Regula 1: păstrează cazul cel mai rău

O căutare liniară poate avea noroc: dacă valoarea se află la început, un singur pas este de ajuns. Big O ignoră norocul și descrie cazul cel mai rău al slice-ului — valoarea este ultima sau lipsește, iar toate cele n elemente sunt verificate.

Așadar, o căutare liniară este O(n), chiar dacă de multe ori se termină mai devreme. Cazul cel mai rău este promisiunea pe care algoritmul o poate respecta întotdeauna.

Cazul cel mai bun și cazul cel mai rău ale unei căutări

Căutarea primului cuvânt ia 1 pas. Căutarea unui cuvânt care lipsește ia toți cei 5 pași. Big O păstrează cifra 5: căutarea liniară este O(n).

Prompt
Scrie un program Go cu o funcție de căutare care caută un cuvânt în slice-ul one, two, three, four, five, numărând pașii buclei și returnând numărul lor. Apeleaz-o o dată pentru primul cuvânt (cazul cel mai bun) și o dată pentru un cuvânt care lipsește (cazul cel mai rău) și afișează ambele numere de pași, cu etichete.
Ieșire: program Go și rezultatul capturat
Best case and worst case of a search

Regula 2: renunță la constante

O buclă care vizitează fiecare al doilea element face n/2 pași. Jumătate din muncă — dar forma creșterii rămâne aceeași: dublezi intrarea, se dublează și pașii.

Big O păstrează doar forma, așa că O(n/2), O(n) și O(2n) sunt toate din aceeași clasă: liniară.

Jumătate din pași înseamnă tot O(n)

Bucla sare din 2 în 2 și vizitează 4 din cele 8 elemente. Dacă slice-ul se dublează, se dublează și pașii — deci n/2 pași înseamnă tot creștere liniară, O(n).

Prompt
Scrie un program Go care parcurge slice-ul 3, 1, 4, 1, 5, 9, 2, 6 vizitând fiecare al doilea element (indexul sare din 2 în 2), afișând valorile vizitate și numărând pașii. La final afișează numărul de elemente și numărul de pași.
Ieșire: program Go și rezultatul capturat
Half the steps is still O(n)

Regula 3: renunță la termenii mai mici

Codul combină adesea părți cu costuri diferite: o buclă simplă (n pași) urmată de bucle imbricate (n² pași). Totalul este n + n².

Pe măsură ce n crește, partea n² înghite restul — la n = 1000 înseamnă un milion de pași față de o mie. Big O păstrează doar termenul care crește cel mai repede: O(n + n²) devine O(n²).

n + n² pași

Pentru 6 elemente, bucla simplă adaugă 6 pași, iar buclele imbricate adaugă 36 — 42 în total. Termenul la pătrat domină deja, iar avansul lui crește odată cu n.

Prompt
Scrie un program Go peste un slice de 6 numere întregi care mai întâi rulează o buclă simplă ce numără n pași, apoi două bucle imbricate care numără n ori n pași, toate într-un singur contor comun. Afișează n și numărul total de pași, ca să văd n + n*n.
Ieșire: program Go și rezultatul capturat
n + n² steps

Regula 4: intrări diferite, litere diferite

Când buclele imbricate parcurg două intrări diferite, numărul de pași este a · b — cele două lungimi înmulțite. Dacă am numi asta O(n²), ar fi greșit: intrările pot avea dimensiuni foarte diferite.

Clasa corectă este O(a · b). Devine O(n²) doar în cazul special în care ambele intrări sunt una și aceeași.

Două slice-uri diferite

3 culori ori 2 animale înseamnă 6 pași. Complexitatea este O(a · b) — dacă slice-ul de animale crește, iar cel de culori nu, contează doar b.

Prompt
Scrie un program Go cu un slice de 3 culori și un slice de 2 animale. Folosește bucle imbricate peste cele două slice-uri diferite, numărând pașii. Afișează cele două lungimi și numărul total de pași, ca să se vadă forma a ori b.
Ieșire: program Go și rezultatul capturat
Two different slices

Limitele notației Big O

Big O este, în mod intenționat, un instrument aproximativ și merită să știi ce ascunde.

Vede doar cazul cel mai rău. Un algoritm cu un caz nefavorabil înspăimântător poate fi excelent în practică, dacă acel caz este rar. Uneori, cazul mediu este cifra care contează.

Ignoră constantele. Pe hârtie, 1000 · n și n sunt din aceeași clasă. Pentru intrări mici, un algoritm „mai lent”, O(n²), cu pași mărunți, poate să învingă unul „mai rapid”, O(n), cu pași grei.

Folosește Big O ca să compari cum scalează algoritmii. Pentru viteză reală pe date reale, măsoară.