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 N
mengambil data.length
nilainya. 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 data
array.
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 for
pernyataan. Ingat bahwa kami menghitung jumlah langkah komputasi, yang berarti bahwa tubuh for
pernyataan dieksekusi N
kali. Itu sama dengan menambahkan C
, N
kali:
f(N) = C + (C + C + ... + C) + C = C + N * C + C
Tidak ada aturan mekanis untuk menghitung berapa kali tubuh for
dieksekusi, 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
N
mendekati infinity
.
Kami f()
memiliki dua istilah:
f(N) = 2 * C * N ^ 0 + 1 * C * N ^ 1
Mengambil semua C
konstanta 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 for
pernyataan di satu nomor kalimat rumit. Sementara indeks berakhir pada 2 * N
, kenaikan dilakukan oleh dua. Itu berarti bahwa langkah pertama for
hanya 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 for
dijalankan: N kali yang pertama, N - 2 yang kedua, N - 4 yang ketiga ... sampai ke tahap N / 2, di mana yang kedua for
tidak 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 i
mengambil nilai N / 2 + 1
ke atas, Penjumlahan batin berakhir pada angka negatif! Itu tidak mungkin dan salah. Kita perlu membagi penjumlahan menjadi dua, menjadi titik penting saat i
dibutuhkan 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²)