Saya mengerti notasi Big-O, tapi saya tidak tahu bagaimana cara menghitungnya untuk banyak fungsi. Secara khusus, saya telah mencoba untuk mencari kompleksitas komputasi dari versi naif dari deret Fibonacci:
int Fibonacci(int n)
{
if (n <= 1)
return n;
else
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Apa kompleksitas komputasi dari deret Fibonacci dan bagaimana cara menghitungnya?
Jawaban:
Anda memodelkan fungsi waktu untuk menghitung
Fib(n)
sebagai jumlah waktu untuk menghitungFib(n-1)
ditambah waktu untuk menghitungFib(n-2)
ditambah waktu untuk menambahkannya bersama-sama (O(1)
). Ini mengasumsikan bahwa evaluasi berulang yang samaFib(n)
membutuhkan waktu yang sama - yaitu tidak ada memoisasi yang digunakan.T(n<=1) = O(1)
T(n) = T(n-1) + T(n-2) + O(1)
Anda memecahkan hubungan perulangan ini (menggunakan fungsi menghasilkan, misalnya) dan Anda akan berakhir dengan jawabannya.
Atau, Anda dapat menggambar pohon rekursi, yang akan memiliki kedalaman
n
dan secara intuitif mengetahui bahwa fungsi ini asimtotik . Anda kemudian dapat membuktikan dugaan Anda dengan induksi.O(2
n
)
Basis:
n = 1
sudah jelasAsumsikan , oleh karena itu
T(n-1) = O(2
n-1
)
T(n) = T(n-1) + T(n-2) + O(1)
yang sama denganT(n) = O(2
n-1
) + O(2
n-2
) + O(1) = O(2
n
)
Namun, seperti disebutkan dalam komentar, ini bukan ikatan yang ketat. Fakta menarik tentang fungsi ini adalah bahwa T (n) asimtotik sama dengan nilai
Fib(n)
karena keduanya didefinisikan sebagaif(n) = f(n-1) + f(n-2)
.Daun dari pohon rekursi akan selalu kembali 1. Nilai
Fib(n)
adalah jumlah dari semua nilai yang dikembalikan oleh daun di pohon rekursi yang sama dengan jumlah daun. Karena setiap daun akan mengambil O (1) untuk menghitung,T(n)
sama denganFib(n) x O(1)
. Akibatnya, batas ketat untuk fungsi ini adalah deret Fibonacci itu sendiri (~ ). Anda dapat menemukan ikatan ketat ini dengan menggunakan fungsi pembangkit seperti yang saya sebutkan di atas.θ(1.6
n
)
sumber
Cukup tanyakan pada diri sendiri berapa banyak pernyataan yang perlu dieksekusi untuk
F(n)
menyelesaikan.Sebab
F(1)
, jawabannya adalah1
(bagian pertama dari kondisi).Sebab
F(n)
, jawabannya adalahF(n-1) + F(n-2)
.Jadi fungsi apa yang memenuhi aturan ini? Coba n (a> 1):
a n == a (n-1) + a (n-2)
Membagi melalui (n-2) :
a 2 == a +1
Pecahkan untuk
a
dan Anda dapatkan(1+sqrt(5))/2 = 1.6180339887
, atau dikenal sebagai rasio emas .Jadi butuh waktu yang eksponensial.
sumber
Saya setuju dengan pgaur dan rickerbh, kompleksitas Recursive-fibonacci adalah O (2 ^ n).
Saya sampai pada kesimpulan yang sama dengan alasan yang agak sederhana tapi saya percaya masih valid.
Pertama, ini semua tentang mencari tahu berapa kali fungsi fibonacci recursive (F () dari sekarang) dipanggil ketika menghitung nomor Nth fibonacci. Jika dipanggil sekali per angka dalam urutan 0 hingga n, maka kita memiliki O (n), jika dipanggil n kali untuk setiap angka, maka kita mendapatkan O (n * n), atau O (n ^ 2), dan seterusnya.
Jadi, ketika F () dipanggil untuk bilangan n, jumlah kali F () dipanggil untuk bilangan tertentu antara 0 dan n-1 bertambah ketika kita mendekati 0.
Sebagai kesan pertama, menurut saya jika kita meletakkannya secara visual, menggambar unit per waktu F () disebut dengan angka tertentu, basah mendapatkan semacam bentuk piramida (yaitu, jika kita memusatkan unit secara horizontal ). Sesuatu seperti ini:
Sekarang, pertanyaannya adalah, seberapa cepat dasar piramida ini membesar saat n tumbuh?
Mari kita ambil contoh nyata, misalnya F (6)
Kita melihat F (0) dipanggil 32 kali, yaitu 2 ^ 5, yang untuk kasus sampel ini adalah 2 ^ (n-1).
Sekarang, kita ingin tahu berapa kali F (x) dipanggil sama sekali, dan kita dapat melihat berapa kali F (0) dipanggil hanya sebagian saja.
Jika kita secara mental memindahkan semua baris * dari F (6) ke F (2) menjadi garis F (1), kita melihat bahwa garis F (1) dan F (0) sekarang memiliki panjang yang sama. Yang berarti, total kali F () dipanggil ketika n = 6 adalah 2x32 = 64 = 2 ^ 6.
Sekarang, dalam hal kompleksitas:
sumber
Ada diskusi yang sangat bagus tentang masalah khusus ini di MIT . Pada halaman 5, mereka menyatakan bahwa, jika Anda menganggap bahwa penambahan membutuhkan satu unit komputasi, waktu yang diperlukan untuk menghitung Fib (N) sangat terkait erat dengan hasil Fib (N).
Sebagai hasilnya, Anda dapat melompat langsung ke perkiraan yang sangat dekat dari seri Fibonacci:
dan mengatakan, oleh karena itu, bahwa kinerja kasus terburuk dari algoritma naif adalah
PS: Ada diskusi tentang ekspresi bentuk tertutup dari angka Fibonacci ke- lebih di Wikipedia jika Anda menginginkan informasi lebih lanjut.
sumber
Anda dapat mengembangkannya dan melakukan visualisasi
sumber
<
pada akhirnya? Bagaimana kau bisaT(n-1) + T(n-1)
?T(n-1) > T(n-2)
Jadi saya bisa berubahT(n-2)
dan menaruhT(n-1)
. Saya hanya akan mendapatkan batas yang lebih tinggi yang masih berlaku untukT(n-1) + T(n-2)
Itu dibatasi pada ujung bawah oleh
2^(n/2)
dan pada ujung atas oleh 2 ^ n (seperti yang disebutkan dalam komentar lain). Dan fakta yang menarik dari implementasi rekursif adalah bahwa ia memiliki ikatan Fib (n) asimptotik yang ketat. Fakta-fakta ini dapat diringkas:Ikatan yang rapat dapat dikurangi lebih jauh menggunakan bentuk tertutup jika diinginkan.
sumber
Jawaban buktinya bagus, tetapi saya selalu harus melakukan beberapa iterasi dengan tangan untuk meyakinkan diri saya sendiri. Jadi saya menggambar pohon panggilan kecil di papan tulis saya, dan mulai menghitung node. Saya membagi jumlah saya menjadi simpul total, simpul daun, dan simpul interior. Inilah yang saya dapatkan:
Yang segera terjadi adalah jumlah simpul daun
fib(n)
. Apa yang memerlukan beberapa iterasi lagi untuk diperhatikan adalah jumlah node interiorfib(n) - 1
. Oleh karena itu jumlah total node adalah2 * fib(n) - 1
.Karena Anda menjatuhkan koefisien ketika mengklasifikasikan kompleksitas komputasi, jawaban akhirnya adalah
θ(fib(n))
.sumber
1
waktu akumulator tunggalFib(n)
, tetapi menarik bahwa itu masih persis tepatθ(Fib(n))
.0
, meskipun: kasus dasar rekursi adalah0
dan1
, karena mereka melakukannyaFib(n-1) + Fib(n-2)
. Jadi mungkin jawaban3 * Fib(n) - 2
dari tautan ini saja lebih akurat untuk jumlah total node, bukan2 * Fib(n) - 1
.Kompleksitas waktu algoritma rekursif dapat diperkirakan dengan lebih baik dengan menggambar pohon rekursi, Dalam hal ini relasi perulangan untuk menggambar pohon rekursi adalah T (n) = T (n-1) + T (n-2) + O (1) perhatikan bahwa setiap langkah membutuhkan O (1) yang berarti waktu yang konstan, karena hanya melakukan satu perbandingan untuk memeriksa nilai n dalam jika blok. Pohon Pengembalian akan terlihat seperti
Di sini katakanlah setiap tingkat pohon di atas dilambangkan oleh i karenanya,
katakanlah pada nilai tertentu dari i, ujung pohon, kasus itu adalah ketika ni = 1, maka i = n-1, yang berarti bahwa ketinggian pohon adalah n-1. Sekarang mari kita lihat berapa banyak pekerjaan yang dilakukan untuk masing-masing dari n lapisan dalam pohon. Perhatikan bahwa setiap langkah membutuhkan O (1) waktu seperti yang dinyatakan dalam relasi perulangan.
karena i = n-1 adalah ketinggian pekerjaan pohon yang dilakukan pada setiap level
Maka total pekerjaan yang dilakukan akan menjumlahkan pekerjaan yang dilakukan pada setiap level, maka itu akan menjadi 2 ^ 0 + 2 ^ 1 + 2 ^ 2 + 2 ^ 3 ... + 2 ^ (n-1) karena i = n-1. Dengan deret geometri jumlah ini adalah 2 ^ n, maka kompleksitas waktu total di sini adalah O (2 ^ n)
sumber
Nah, menurut saya untuk itu
O(2^n)
karena dalam fungsi ini hanya rekursi yang mengambil waktu yang cukup lama (bagi dan taklukkan). Kita melihat bahwa, fungsi di atas akan berlanjut di pohon sampai daun mendekati ketika kita mencapai tingkatF(n-(n-1))
yaituF(1)
. Jadi, di sini ketika kita mencatat kompleksitas waktu yang dihadapi di setiap kedalaman pohon, seri penjumlahan adalah:itu adalah urutan
2^n [ O(2^n) ]
.sumber
Versi rekursi naif dari Fibonacci adalah eksponensial dengan desain karena pengulangan dalam perhitungan:
Pada dasarnya Anda menghitung:
F (n) tergantung pada F (n-1) dan F (n-2)
F (n-1) tergantung pada F (n-2) lagi dan F (n-3)
F (n-2) tergantung pada F (n-3) lagi dan F (n-4)
maka Anda mengalami setiap panggilan tingkat 2 rekursif yang membuang banyak data dalam perhitungan, fungsi waktu akan terlihat seperti ini:
T (n) = T (n-1) + T (n-2) + C, dengan konstanta C
T (n-1) = T (n-2) + T (n-3)> T (n-2)
T (n)> 2 * T (n-2)
...
T (n)> 2 ^ (n / 2) * T (1) = O (2 ^ (n / 2))
Ini hanya batas bawah yang untuk keperluan analisis Anda harus cukup tetapi fungsi real time adalah faktor konstanta dengan rumus Fibonacci yang sama dan bentuk tertutup diketahui eksponensial dari rasio emas.
Selain itu, Anda dapat menemukan versi Fibonacci yang dioptimalkan menggunakan pemrograman dinamis seperti ini:
Itu dioptimalkan dan hanya melakukan n langkah tetapi juga eksponensial.
Fungsi biaya ditentukan dari ukuran Input hingga jumlah langkah untuk menyelesaikan masalah. Saat Anda melihat versi dinamis Fibonacci ( n langkah untuk menghitung tabel) atau algoritma termudah untuk mengetahui apakah bilangan prima ( sqrt (n) untuk menganalisis pembagi angka yang valid). Anda mungkin berpikir bahwa algoritma ini adalah O (n) atau O (sqrt (n)) tetapi ini tidak benar karena alasan berikut: Input ke algoritma Anda adalah angka: n , menggunakan notasi biner ukuran input untuk suatu integer n adalah log2 (n) kemudian melakukan perubahan variabel
mari cari tahu jumlah langkah sebagai fungsi dari ukuran input
maka biaya algoritma Anda sebagai fungsi dari ukuran input adalah:
dan inilah mengapa biayanya eksponensial.
sumber
Sangat mudah untuk menghitung dengan membuat diagram panggilan fungsi. Cukup tambahkan pemanggilan fungsi untuk setiap nilai n dan lihat bagaimana jumlahnya tumbuh.
Big O adalah O (Z ^ n) di mana Z adalah rasio emas atau sekitar 1,62.
Baik angka Leonardo dan angka Fibonacci mendekati rasio ini saat kami meningkatkan n.
Tidak seperti pertanyaan Big O lainnya, tidak ada variabilitas dalam input dan algoritma dan implementasi algoritma didefinisikan dengan jelas.
Tidak perlu banyak matematika yang rumit. Cukup gambarkan fungsi panggilan di bawah ini dan paskan fungsi dengan angka.
Atau jika Anda terbiasa dengan rasio emas, Anda akan mengenalinya.
Jawaban ini lebih benar daripada jawaban yang diterima yang mengklaim akan mendekati f (n) = 2 ^ n. Tidak akan pernah. Ini akan mendekati f (n) = golden_ratio ^ n.
sumber
http://www.ics.uci.edu/~eppstein/161/960109.html
waktu (n) = 3F (n) - 2
sumber