logo

„Big O“ žymėjimo pamoka – „Big O“ analizės vadovas

Didelis O žymėjimas yra galingas įrankis, naudojamas kompiuterių moksle, apibūdinantis algoritmų sudėtingumą laike arba erdvėje. Tai standartizuotas būdas palyginti skirtingų algoritmų efektyvumą, atsižvelgiant į jų blogiausio atvejo veikimą. Supratimas Didelis O žymėjimas yra būtinas norint analizuoti ir kurti efektyvius algoritmus.

Šioje pamokoje apžvelgsime pagrindus Didelis O žymėjimas , jo reikšmę ir kaip analizuoti algoritmų sudėtingumą naudojant Didysis O .



Turinys

Kas yra „Big-O“ žymėjimas?

Didysis-O , paprastai vadinamas Užsakymas , yra būdas išreikšti viršutinė riba algoritmo sudėtingumo laike, nes jis analizuoja blogiausiu atveju algoritmo situacija. Tai suteikia an viršutinis limitas apie laiką, kurį algoritmas užima pagal įvesties dydį. Jis žymimas kaip O(f(n)) , kur f(n) yra funkcija, nurodanti operacijų (žingsnių), kuriuos algoritmas atlieka norėdamas išspręsti dydžio problemą, skaičių n .



Big-O žymėjimas naudojamas algoritmo veikimui ar sudėtingumui apibūdinti. Konkrečiai, jis apibūdina Blogiausias scenarijus kalbant apie laikas arba erdvės sudėtingumas.

Svarbus punktas:

  • Didelis O žymėjimas apibūdina tik asimptotinį funkcijos elgesį, o ne tikslią jos reikšmę.
  • The Didelis O žymėjimas gali būti naudojamas skirtingų algoritmų ar duomenų struktūrų efektyvumui palyginti.

Big-O žymėjimo apibrėžimas:

Suteiktos dvi funkcijos f(n) ir g(n) , mes taip sakome f(n) yra O(g(n)) jei egzistuoja konstantos c> 0 ir n 0 >= 0 toks f(n) <= c*g(n) visiems n>= n 0 .



Paprasčiau tariant, f(n) yra O(g(n)) jeigu f(n) auga ne greičiau kaip c*g(n) visiems n>= n0kur c ir n0yra konstantos.

Kodėl „Big O“ žymėjimas yra svarbus?

„Big O“ žymėjimas yra matematinis žymėjimas, naudojamas apibūdinti blogiausio atvejo algoritmo sudėtingumą arba efektyvumą arba blogiausią duomenų struktūros erdvės sudėtingumą. Tai suteikia galimybę palyginti skirtingų algoritmų ir duomenų struktūrų našumą ir numatyti, kaip jie elgsis didėjant įvesties dydžiui.

Didelis O žymėjimas svarbus dėl kelių priežasčių:

  • Big O žymėjimas yra svarbus, nes padeda analizuoti algoritmų efektyvumą.
  • Jame pateikiamas būdas apibūdinti, kaip vykdymo laikas arba erdvės reikalavimai algoritmo dydis didėja didėjant įvesties dydžiui.
  • Leidžia programuotojams palyginti skirtingus algoritmus ir pasirinkti efektyviausią konkrečiai problemai spręsti.
  • Padeda suprasti algoritmų mastelį ir numatyti, kaip jie veiks augant įvesties dydžiui.
  • Leidžia kūrėjams optimizuoti kodą ir pagerinti bendrą našumą.

Didžiojo O žymėjimo savybės:

Žemiau yra keletas svarbių „Big O“ žymėjimo savybių:

1. Refleksyvumas:

Bet kuriai funkcijai f(n) f(n) = O(f(n)).

Pavyzdys:

f(n) = n2, tada f(n) = O(n2).

2. Tranzityvumas:

Jei f(n) = O(g(n)) ir g(n) = O(h(n)), tai f(n) = O(h(n)).

Pavyzdys:

f(n) = n3, g(n) = n2, h(n) = n4. Tada f(n) = O(g(n)) ir g(n) = O(h(n)). Todėl f(n) = O(h(n)).

3. Pastovus koeficientas:

Bet kuriai konstantai c> 0 ir funkcijoms f(n) ir g(n), jei f(n) = O(g(n)), tai cf(n) = O(g(n)).

Pavyzdys:

f(n) = n, g(n) = n2. Tada f(n) = O(g(n)). Todėl 2f(n) = O(g(n)).

4. Sumos taisyklė:

Jei f(n) = O(g(n)) ir h(n) = O(g(n)), tai f(n) + h(n) = O(g(n)).

Pavyzdys:

f(n) = n2, g(n) = n3, h(n) = n4. Tada f(n) = O(g(n)) ir h(n) = O(g(n)). Todėl f(n) + h(n) = O(g(n)).

5. Gaminio taisyklė:

Jei f(n) = O(g(n)) ir h(n) = O(k(n)), tai f(n) * h(n) = O(g(n) * k(n)) .

Pavyzdys:

f(n) = n, g(n) = n2, h(n) = n3, k(n) = n4. Tada f(n) = O(g(n)) ir h(n) = O(k(n)). Todėl f(n) * h(n) = O(g(n) * k(n)) = O(n)5).

6. Sudėties taisyklė:

Jei f(n) = O(g(n)) ir g(n) = O(h(n)), tai f(g(n)) = O(h(n)).

Pavyzdys:

f(n) = n2, g(n) = n, h(n) = n3. Tada f(n) = O(g(n)) ir g(n) = O(h(n)). Todėl f(g(n)) = O(h(n)) = O(n3).

Įprasti „Big-O“ žymėjimai:

Big-O žymėjimas yra būdas išmatuoti algoritmo laiko ir erdvės sudėtingumą. Jame aprašoma viršutinė sudėtingumo riba pagal blogiausią scenarijų. Pažvelkime į skirtingus laiko sudėtingumo tipus:

1. Linijinis laiko sudėtingumas: didelis O(n) sudėtingumas

Linijinis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas didėja tiesiškai didėjant įvesties dydžiui.

Pavyzdžiui, apsvarstykite algoritmą, kuris eina per masyvą, kad surastų konkretų elementą :

Kodo fragmentas
bool findElement(int arr[], int n, int key) {  for (int i = 0; i < n; i++) {  if (arr[i] == key) {  return true;  }  }  return false; }>

2. Logaritminis laiko sudėtingumas: didelis O(log n) sudėtingumas

Logaritminis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas yra proporcingas įvesties dydžio logaritmui.

Pavyzdžiui, a dvejetainis paieškos algoritmas turi logaritminį laiko sudėtingumą:

Kodo fragmentas
int binarySearch(int arr[], int l, int r, int x) {  if (r>= l) { int mid = l + (r - l) / 2;  if (arr[mid] == x) return mid;  if (arr[mid]> x) return binarySearch(arr, l, mid - 1, x);  return binarySearch(arr, mid + 1, r, x);  } grįžti -1; }>

3. Kvadratinis laiko sudėtingumas: didelis O(n2) Sudėtingumas

Kvadratinis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas yra proporcingas įvesties dydžio kvadratui.

Pavyzdžiui, paprastas burbulų rūšiavimo algoritmas turi kvadratinį laiko sudėtingumą:

Kodo fragmentas
void bubbleSort(int arr[], int n) {  for (int i = 0; i < n - 1; i++) {  for (int j = 0; j < n - i - 1; j++) {  if (arr[j]>arr[j + 1]) { apsikeitimas(&arr[j], &arr[j + 1]);  } } } }>

4. Kubinio laiko sudėtingumas: didelis O(n3) Sudėtingumas

Kubinis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas yra proporcingas įvesties dydžio kubui.

Pavyzdžiui, naivuolis matricos daugybos algoritmas turi kubinį laiko sudėtingumą:

Kodo fragmentas
void multiply(int mat1[][N], int mat2[][N], int res[][N]) {  for (int i = 0; i < N; i++) {  for (int j = 0; j < N; j++) {  res[i][j] = 0;  for (int k = 0; k < N; k++)  res[i][j] += mat1[i][k] * mat2[k][j];  }  } }>

5. Polinominis laiko sudėtingumas: didelis O(nk) Sudėtingumas

Polinominis laiko sudėtingumas reiškia algoritmo sudėtingumą laike, kuris gali būti išreikštas kaip įvesties dydžio daugianario funkcija n . Didelėje O Sakoma, kad algoritmas turi daugianario laiko sudėtingumą, jei jo sudėtingumas yra toks O (n k ) , kur k yra konstanta ir reiškia daugianario laipsnį.

Dauginamo laiko sudėtingumo algoritmai paprastai laikomi efektyviais, nes didėjant įvesties dydžiui, veikimo laikas auga protingai. Įprasti daugianario laiko sudėtingumo algoritmų pavyzdžiai: tiesinis laiko sudėtingumas O(n) , kvadratinis laiko sudėtingumas O(n 2 ) , ir kubinis laiko sudėtingumas O(n 3 ) .

6. Eksponentinis laiko sudėtingumas: didelis O(2n) Sudėtingumas

Eksponentinis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas padvigubėja kiekvieną kartą papildant įvesties duomenų rinkinį.

normalizavimas duomenų bazėje

Pavyzdžiui, problema generuojant visus aibės poaibius yra eksponentinio laiko sudėtingumo:

Kodo fragmentas
void generateSubsets(int arr[], int n) {  for (int i = 0; i < (1 << n); i++) {  for (int j = 0; j < n; j++) {  if (i & (1 << j)) {  cout << arr[j] << ' ';  }  }  cout << endl;  } }>

Faktinis laiko sudėtingumas: didelis O(n!) sudėtingumas

Faktinis laiko sudėtingumas reiškia, kad algoritmo veikimo laikas didėja priklausomai nuo įvesties dydžio. Tai dažnai pastebima algoritmuose, kurie generuoja visas duomenų rinkinio permutacijas.

Štai faktorinio laiko sudėtingumo algoritmo, kuris generuoja visas masyvo permutacijas, pavyzdys:

Kodo fragmentas
void permute(int* a, int l, int r) {  if (l == r) {  for (int i = 0; i <= r; i++) {  cout << a[i] << ' ';  }  cout << endl;  }  else {  for (int i = l; i <= r; i++) {  swap(a[l], a[i]);  permute(a, l + 1, r);  swap(a[l], a[i]); // backtrack  }  } }>

Jei pavaizduotume dažniausiai pasitaikančius Big O žymėjimo pavyzdžius, gautume tokį grafiką:

asimtotinė analizė

Kaip nustatyti didžiąją O žymą?

Didelis O žymėjimas yra matematinis žymėjimas, naudojamas apibūdinti asimptotinis elgesys funkcijos, nes jos įvestis tampa be galo didelė. Tai yra būdas apibūdinti algoritmų ir duomenų struktūrų efektyvumą.

Veiksmai, skirti nustatyti didžiąją O žymą:

1. Nustatykite dominuojantį terminą:

  • Išnagrinėkite funkciją ir nustatykite terminą su didžiausiu augimo laipsniu, kai įvesties dydis didėja.
  • Nepaisykite jokių pastovių veiksnių arba žemesnės eilės terminų.

2. Nustatykite augimo tvarką:

  • Dominuojančio termino augimo tvarka lemia Big O žymėjimą.

3. Parašykite didžiąją O žymą:

  • Didysis O žymėjimas rašomas kaip O(f(n)), kur f(n) reiškia dominuojantį terminą.
  • Pavyzdžiui, jei dominuojantis terminas yra n^2, Big O žymėjimas būtų O(n^2).

4. Supaprastinkite žymėjimą (nebūtina):

  • Kai kuriais atvejais, Big O prekės ženklas n galima supaprastinti pašalinus pastovius veiksnius arba naudojant glaustesnį žymėjimą.
  • Pavyzdžiui, O(2n) galima supaprastinti iki O(n).

Pavyzdys:

Funkcija: f(n) = 3n3+ 2n2+ 5n + 1

  1. Dominuojantis terminas: 3n3
  2. Augimo tvarka: kubinis (n3)
  3. Didelis O žymėjimas: O (n3)
  4. Supaprastintas žymėjimas: O(n3)

Matematiniai vykdymo laiko analizės pavyzdžiai:

Žemiau esančioje lentelėje parodyta skirtingų algoritmų eilių vykdymo analizė, kai didėja įvesties dydis (n).

nžurnalas (n)nn * log(n)n^22^nn!
101101010010243628800
dvidešimt2 996dvidešimt59.940010485762.432902e+1818

Algoritminiai vykdymo laiko analizės pavyzdžiai:

Žemiau esančioje lentelėje algoritmai skirstomi į kategorijas pagal jų vykdymo sudėtingumą ir pateikiami kiekvieno tipo pavyzdžiai.

TipasŽymėjimasAlgoritmų pavyzdžiai
LogaritminisO(log n)Dvejetainė paieška
LinijinisO(n)Linijinė paieška
SupertiesinisO(n log n)Rūšiuoti į krūvą, sujungti rūšiavimą
PolinomasO(n^c)Strasseno matricos daugyba, burbulų rūšiavimas, atrankos rūšiavimas, įterpimo rūšiavimas, rūšiavimas pagal segmentą
EksponentinisO(c^n)Hanojaus bokštas
FaktorinisO (n!)Determinantinis plėtra nepilnamečių, žiaurios jėgos paieškos algoritmas keliaujant pardavėjo problemai

Algoritmų klasės su operacijų skaičiumi ir vykdymo laiku:

Žemiau pateikiamos algoritmų klasės ir jų vykdymo laikas vykdomame kompiuteryje 1 milijonas operacijų per sekundę (1 sek. = 10 6 μs = 10 3 msek) :

Didelės O žymėjimo klasės

f(n)

Didžiojo O analizė (operacijų skaičius), kai n = 10

Vykdymo laikas (1 instrukcija/μsek.)

pastovus

O(1)

1

1 μsek

logaritminis

O (prisijungti)

3.32

sujungimo rūšiavimo algoritmas

3 μsek

linijinis

O(n)

10

10 μs

O (neprisijungęs)

O (neprisijungęs)

33.2

33 μsek

kvadratinis

O (n2)

102

100 μs

kub

O (n3)

103

1 ms

eksponentinis

O(2n)

1024

10 ms

faktorinis

O (n!)

10!

3,6288 sek

Didžiojo O žymėjimo, didžiojo Ω (Omega) žymėjimo ir didžiojo θ (teta) žymėjimo palyginimas:

Žemiau yra lentelė, kurioje lyginami Big O, Ω (Omega) ir θ (Theta) žymėjimai:

ŽymėjimasApibrėžimasPaaiškinimas
Didelis O (O)f(n) ≤ C * g(n) visiems n ≥ n0Apibūdina viršutinę algoritmo veikimo laiko ribą blogiausiu atveju .
Ω (Omega)f(n) ≥ C * g(n) visiems n ≥ n0Apibūdina apatinę algoritmo veikimo laiko ribą geriausiu atveju .
θ (teta)C1* g(n) ≤ f(n) ≤ C2* g(n), kai n ≥ n0Apibūdina ir viršutinę, ir apatinę algoritmo ribas veikimo laikas .

Kiekviename užraše:

  • f(n) reiškia analizuojamą funkciją, paprastai algoritmo sudėtingumą laiku.
  • g(n) reiškia konkrečią funkciją, kuri ribojasi f(n) .
  • C, C1, ir C2 yra konstantos.
  • n 0 yra mažiausias įvesties dydis, už kurį galioja nelygybė.

Šie žymėjimai naudojami analizuojant algoritmus, pagrįstus jais blogiausias atvejis (Big O) , geriausiu atveju (Ω) , ir vidutinė raidė (θ) scenarijai.

Dažnai užduodami klausimai apie „Big O“ žymėjimą:

1 klausimas. Kas yra Big O žymėjimas?

Atsakymas: Big O žymėjimas yra matematinis žymėjimas, naudojamas apibūdinti algoritmo laiko sudėtingumo viršutinę ribą, atsižvelgiant į tai, kaip jis auga, palyginti su įvesties dydžiu.

2 klausimas. Kodėl Big O žymėjimas yra svarbus?

Atsakymas: Tai padeda mums analizuoti ir palyginti algoritmų efektyvumą sutelkiant dėmesį į blogiausią scenarijų ir suprasti, kaip jų našumas keičiasi atsižvelgiant į įvesties dydį.

3 klausimas. Kaip apskaičiuojamas didelis O žymėjimas?

Atsakymas: Didysis O žymėjimas nustatomas identifikuojant dominuojančią algoritmo operaciją ir išreiškiant jos laiko sudėtingumą n, kur n reiškia įvesties dydį.

4 klausimas. Ką reiškia O(1) didžiajame O žymėjime?

Atsakymas: O (1) reiškia pastovų laiko sudėtingumą, o tai rodo, kad algoritmo vykdymo laikas nesikeičia nepriklausomai nuo įvesties dydžio.

5 klausimas. Kokią reikšmę turi skirtingi dideli O sudėtingumai, tokie kaip O(log n) arba O(n^2)?

Atsakymas: Įvairūs sudėtingumo rodikliai, pvz., O(log n) arba O(n^2), rodo, kaip didėja algoritmo našumas didėjant įvesties dydžiui, o tai suteikia įžvalgų apie jo efektyvumą ir mastelį.

6 klausimas. Ar Big O žymėjimas gali būti pritaikytas ir erdvės sudėtingumui?

Atsakymas: Taip, Big O notation taip pat gali būti naudojamas algoritmo erdvės sudėtingumui analizuoti ir apibūdinti, nurodant, kiek atminties jam reikia, palyginti su įvesties dydžiu.

Susijęs straipsnis: