Fibonacci Sayıları
Fibonacci sayılarıânın akıÅı Åu formüle göredir: Fn = Fn-1 + Fn-2. Anlamı, bir sonraki sayı kendinden önce gelen iki sayının toplamıdır.
İlk iki sayı 1âdir, sonra 2(1+1), sonra 3(1+2), 5(2+3) Åeklinde devam eder: 1, 1, 2, 3, 5, 8, 13, 21...
Fibonacci sayıları Altın oran ile ilgilidir ve birçok doÄal olay bunun etrafında gerçekleÅir.
fib(n) fonksiyonu yazını ve bu fonksiyon n. fibonacci sayisini dönsün.
Ãrnek:
function fib(n) { /* kodunuz */ }
alert(fib(3)); // 2
alert(fib(7)); // 13
alert(fib(77)); // 5527939700884757
Not: Ãözüm çok hızlı olmalıdır. fib(77) 1 saniyeden uzun sürmemelidir.
İlk olarak özçaÄrı çözümü denenebilir.
Fibonacci sayıları tanım olarak özçaÄrıya uygundur:
function fib(n) {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
alert( fib(3) ); // 2
alert( fib(7) ); // 13
// fib(77); // aÅırı derecede yavaÅ olacaktır!
⦠nâin büyük deÄerleri için oldukça yavaÅtır. ÃrneÄin fib(77) JavaScript motorunun durmasına bile neden olabilir, tüm CPU kaynaÄını harcayabilir.
Bunun nedeni fonksiyonun çok fazla alt çaÄrı yapmasıdır. Aynı deÄerler defalarca hesaplanır ve hesaplanır.
ÃrneÄin fib(5) Åu Åekilde hesaplanır:
...
fib(5) = fib(4) + fib(3)
fib(4) = fib(3) + fib(2)
...
GörüldüÄü gibi burada fib(3), fib(4) ve fib(5) için gereklidir. Bundan dolayı fib(5) iki defa bir birinden baÄımsız olarak çalıÅacaktır.
AÅaÄıda tüm özçaÄrı aÄacını görebilirsiniz.
GördüÄünüz gibi fib(3) iki defa fib(2) ise üç defa çalıÅtırılır. Toplamda hesaplama n den daha hızlı bir Åekilde büyür. n=77 için bu sayı çok büyük olur.
Bu daha önceden hesaplanmıŠdeÄerleri hatırlayarak çözülebilir: EÄer fib(3) bir defa hesaplanırsa, bu gelecekteki hesaplamalar için tekrar kullanılabilir.
DiÄer bir yöntem ise özçaÄrıyı hiç kullanmayıp döngü bazlı bir algoritma geliÅtirmektir.
nâden daha küçüÄe giden sayılar yerine 1 den ve 2 den baÅlayıp bunları fib(3)ün deÄeri olarak tanımlamak mümkündür. Sonrasında fib(4) bir iki önceki deÄerin toplamı olur. Bu Åekilde gerekli olan n deÄerine kadar gider. Her bir adımda sadece iki önceki deÄeri hatırlamak yeterli olacaktır.
Yeni algoritmanın basamakları aÅaÄıdaki gibi olacaktır
BaÅlangıç:
// a = fib(1), b = fib(2), bunlar 1'in tanımıdır.
let a = 1, b = 1;
// c'yi al = fib(3) toplamı
let c = a + b;
/* Åimdi fib(1), fib(2), fib(3)'e sahibiz.
a b c
1, 1, 2
*/
EÄer fib(4) istenirse bu fib(4) = fib(2) + fib(3)'tür.
DeÄiÅkenlere kaydırılırsa: a,b , fib(2),fib(3) alacaktır, c ise toplamı olacaktır:
a = b; // Åimdi a = fib(2)
b = c; // Åimdi b = fib(3)
c = a + b; // c = fib(4)
/* akıŠÅu Åekildedir:
a b c
1, 1, 2, 3
*/
Bir sonraki adım, sıradaki sayıyı vermektir:
a = b; // Åimdi a = fib(3)
b = c; // Åimdi b = fib(4)
c = a + b; // c = fib(5)
/* Åimdiki akıŠ( 1 sayı fazla ):
a b c
1, 1, 2, 3, 5
*/
⦠Bu Åekilde istenen sayıya kadar devam eder. ÃzçaÄrıâdan daha hızlıdır ve aynı iÅlemi tekrar yapmaz.
Kodun tamamı:
function fib(n) {
let a = 1;
let b = 1;
for (let i = 3; i <= n; i++) {
let c = a + b;
a = b;
b = c;
}
return b;
}
alert( fib(3) ); // 2
alert( fib(7) ); // 13
alert( fib(77) ); // 5527939700884757
Döngü i=3 ile baÅlar çünkü birinci ve ikinci deÄerler a=1 ve b=1 Åeklinde elle atanmıÅtır.
Bu yaklaÅıma dinamik alttan yukarı programlama denir.