Saya akan melakukan yang terbaik untuk menjelaskannya di sini dengan persyaratan yang sederhana, tetapi diingatkan bahwa topik ini membutuhkan siswa saya beberapa bulan untuk akhirnya memahami. Anda dapat menemukan informasi lebih lanjut tentang Bab 2 Struktur Data dan Algoritma di buku Java .
Tidak ada prosedur mekanis yang dapat digunakan untuk mendapatkan BigOh.
Sebagai "buku masak", untuk mendapatkan BigOh dari sepotong kode, pertama-tama Anda harus menyadari bahwa Anda sedang membuat rumus matematika untuk menghitung berapa banyak langkah perhitungan yang dijalankan dengan input ukuran tertentu.
Tujuannya sederhana: untuk membandingkan algoritma dari sudut pandang teoretis, tanpa perlu mengeksekusi kode. Semakin sedikit jumlah langkah, semakin cepat algoritma.
Misalnya, katakan Anda memiliki kode ini:
int sum(int* data, int N) {
int result = 0; // 1
for (int i = 0; i < N; i++) { // 2
result += data[i]; // 3
}
return result; // 4
}
Fungsi ini mengembalikan jumlah semua elemen array, dan kami ingin membuat rumus untuk menghitung kompleksitas komputasi dari fungsi itu:
Number_Of_Steps = f(N)
Jadi kita punya f(N), fungsi untuk menghitung jumlah langkah komputasi. Input dari fungsi adalah ukuran struktur untuk diproses. Ini berarti bahwa fungsi ini disebut seperti:
Number_Of_Steps = f(data.length)
Parameter Nmengambil data.lengthnilainya. Sekarang kita membutuhkan definisi fungsi yang sebenarnya f(). Ini dilakukan dari kode sumber, di mana setiap baris yang menarik diberi nomor dari 1 hingga 4.
Ada banyak cara untuk menghitung BigOh. Dari titik ini ke depan kita akan mengasumsikan bahwa setiap kalimat yang tidak tergantung pada ukuran data input mengambil konstantaC langkah perhitungan angka .
Kita akan menambahkan jumlah individu dari langkah-langkah fungsi, dan deklarasi variabel lokal atau pernyataan pengembalian tidak tergantung pada ukuran dataarray.
Itu berarti bahwa baris 1 dan 4 masing-masing mengambil jumlah langkah C, dan fungsinya agak seperti ini:
f(N) = C + ??? + C
Bagian selanjutnya adalah mendefinisikan nilai forpernyataan. Ingat bahwa kami menghitung jumlah langkah komputasi, yang berarti bahwa tubuh forpernyataan dieksekusi Nkali. Itu sama dengan menambahkan C, Nkali:
f(N) = C + (C + C + ... + C) + C = C + N * C + C
Tidak ada aturan mekanis untuk menghitung berapa kali tubuh fordieksekusi, Anda perlu menghitungnya dengan melihat apa yang dilakukan kode. Untuk menyederhanakan perhitungan, kami mengabaikan inisialisasi variabel, kondisi dan bagian kenaikan darifor pernyataan.
Untuk mendapatkan BigOh yang sebenarnya, kita perlu analisis fungsi asimptotik . Ini kira-kira dilakukan seperti ini:
- Singkirkan semua konstanta
C.
- Dari
f()dapatkan polinomium di dalamnya standard form.
- Bagilah persyaratan polinomium dan urutkan berdasarkan laju pertumbuhan.
- Usahakan yang tumbuh lebih besar saat
Nmendekati infinity.
Kami f()memiliki dua istilah:
f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1
Mengambil semua Ckonstanta dan bagian yang berlebihan:
f(N) = 1 + N ^ 1
Karena istilah terakhir adalah yang tumbuh lebih besar ketika f()mendekati tak terhingga (pikirkan batas ) ini adalah argumen BigOh, dan sum()fungsinya memiliki BigOh dari:
O(N)
Ada beberapa trik untuk menyelesaikan beberapa trik rumit: gunakan penjumlahan kapan saja Anda bisa.
Sebagai contoh, kode ini dapat dipecahkan dengan mudah menggunakan penjumlahan:
for (i = 0; i < 2*n; i += 2) { // 1
for (j=n; j > i; j--) { // 2
foo(); // 3
}
}
Hal pertama yang perlu Anda tanyakan adalah urutan eksekusi foo(). Sementara yang biasa terjadi O(1), Anda perlu bertanya kepada profesor Anda tentang hal itu. O(1)berarti (hampir, sebagian besar) konstan C, tidak tergantung ukuran N.
The forpernyataan di satu nomor kalimat rumit. Sementara indeks berakhir pada 2 * N, kenaikan dilakukan oleh dua. Itu berarti bahwa langkah pertama forhanya dijalankan N, dan kita perlu membagi hitungannya menjadi dua.
f(N) = Summation(i from 1 to 2 * N / 2)( ... ) =
= Summation(i from 1 to N)( ... )
Kalimat nomor dua bahkan lebih rumit karena tergantung pada nilai i. Lihatlah: indeks i mengambil nilai-nilai: 0, 2, 4, 6, 8, ..., 2 * N, dan yang kedua fordijalankan: N kali yang pertama, N - 2 yang kedua, N - 4 yang ketiga ... sampai ke tahap N / 2, di mana yang kedua fortidak pernah dieksekusi.
Pada formula, itu berarti:
f(N) = Summation(i from 1 to N)( Summation(j = ???)( ) )
Sekali lagi, kami menghitung jumlah langkah . Dan menurut definisi, setiap penjumlahan harus selalu dimulai dari satu, dan diakhiri dengan angka yang lebih besar atau sama dengan satu.
f(N) = Summation(i from 1 to N)( Summation(j = 1 to (N - (i - 1) * 2)( C ) )
(Kami menganggap itu foo()adalah O(1)dan mengambilC langkah-langkah.)
Kami memiliki masalah di sini: ketika imengambil nilai N / 2 + 1ke atas, Penjumlahan batin berakhir pada angka negatif! Itu tidak mungkin dan salah. Kita perlu membagi penjumlahan menjadi dua, menjadi titik penting saat idibutuhkan N / 2 + 1.
f(N) = Summation(i from 1 to N / 2)( Summation(j = 1 to (N - (i - 1) * 2)) * ( C ) ) + Summation(i from 1 to N / 2) * ( C )
Sejak momen penting i > N / 2, batinfor tidak akan dieksekusi, dan kami mengasumsikan kompleksitas eksekusi C konstan pada tubuhnya.
Sekarang penjumlahan dapat disederhanakan menggunakan beberapa aturan identitas:
- Penjumlahan (w dari 1 ke N) (C) = N * C
- Penjumlahan (w dari 1 ke N) (A (+/-) B) = Penjumlahan (w dari 1 ke N) (A) (+/-) Penjumlahan (w dari 1 ke N) (B)
- Penjumlahan (w dari 1 ke N) (w * C) = C * Penjumlahan (w dari 1 ke N) (w) (C adalah konstanta, independen dari
w )
- Penjumlahan (w dari 1 ke N) (w) = (N * (N + 1)) / 2
Menerapkan beberapa aljabar:
f(N) = Summation(i from 1 to N / 2)( (N - (i - 1) * 2) * ( C ) ) + (N / 2)( C )
f(N) = C * Summation(i from 1 to N / 2)( (N - (i - 1) * 2)) + (N / 2)( C )
f(N) = C * (Summation(i from 1 to N / 2)( N ) - Summation(i from 1 to N / 2)( (i - 1) * 2)) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2)( i - 1 )) + (N / 2)( C )
=> Summation(i from 1 to N / 2)( i - 1 ) = Summation(i from 1 to N / 2 - 1)( i )
f(N) = C * (( N ^ 2 / 2 ) - 2 * Summation(i from 1 to N / 2 - 1)( i )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N / 2 - 1) * (N / 2 - 1 + 1) / 2) ) + (N / 2)( C )
=> (N / 2 - 1) * (N / 2 - 1 + 1) / 2 =
(N / 2 - 1) * (N / 2) / 2 =
((N ^ 2 / 4) - (N / 2)) / 2 =
(N ^ 2 / 8) - (N / 4)
f(N) = C * (( N ^ 2 / 2 ) - 2 * ( (N ^ 2 / 8) - (N / 4) )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - ( (N ^ 2 / 4) - (N / 2) )) + (N / 2)( C )
f(N) = C * (( N ^ 2 / 2 ) - (N ^ 2 / 4) + (N / 2)) + (N / 2)( C )
f(N) = C * ( N ^ 2 / 4 ) + C * (N / 2) + C * (N / 2)
f(N) = C * ( N ^ 2 / 4 ) + 2 * C * (N / 2)
f(N) = C * ( N ^ 2 / 4 ) + C * N
f(N) = C * 1/4 * N ^ 2 + C * N
Dan BigOh adalah:
O(N²)