2012-01-03 13 views
5

Bu, my previous question izindir. Her Fibonacci numarası için fib yönteminin çağrılmasından beri Fibonacci sayılarını hesaplamak için aşağıdaki yöntem verimsizdir ve her çağrıldığında yeni bir akış oluşturur. Öte yandan (here olduğu gibi) kuyruk özyinelemeli yöntem üzerindeScala'da Akımlar oluşturmak için özgün yöntemler

def fib:Stream[Int] = 
    Stream.cons(1, Stream.cons(1, (fib zip fib.tail) map {case (x, y) => x + y}))

oldukça verimli görünüyor ve Şimdi Streams oluşturmak özyinelemeli yöntemler verimli olduklarını bitiriyorum O(1)

def fib(a:Int, b:Int):Stream[Int] = Stream.cons(a, fib(b, a+b));

her Fibonacci sayısını hesaplar eğer ve sadece ise bunlar özyinelemelidir. Doğru mu?

+1

Her iki örnek de yineleyici bir kuyruktur. –

+0

@ DanielC.Sobral 2. uygulamanın neden her bir Fibonacci numarasını hesapladığını açıklayabilir misiniz? O (1) 'de, ancak 1’i' O (N) '' – Michael

+0

Oops’de özür dilerim… İlkinden bahsediyordum .. Yorum yazmama izin ver ... –

cevap

4

Ben Andy 'ın answer geliştirmek için denedim deneyin görmek istiyorsanız, ama hemen hemen çivilenmiş. İlk çözüm, bir akarsu piramidi yaratıyor - her bir fib no'lu çağrı, başka bir fibonacci akışı yaratıyor ve bu yeni akışların her biri yeni akışları kendileri yaratacak, vb. (map tarafından oluşturulan fib zip fib.tail

  • One fib.tail yarattığı fib zip fib.tail
  • One fib yarattığı

    • Bir:

      Görüşme kaynaklanan üç akışları fib için vardır, Açık olmak gerekirse hatırla, map yeni bir koleksiyon hazırlar)

    İlk ikisi, fib numaralı telefona çağrı olduğu için, her birinde üç akış oluşturuyorlar.

    İşte kaba bunun "resmi" var:

          1 
              1 
          1    2    1 
          1    3  1  2  1 
        1  2  1  5  1  3 1 2 1 
        1  3 1 2 1 8 1 2 1 5 1 3 1 2 1       
    

    Ve bu uzayıp gider. Orta akış, sol ve sağında en yüksek akışlar kullanılarak hesaplanır (fib ve fib.tail). Bunların her biri sol ve sağ alt akışları kullanılarak hesaplanır. Bu alt akışların her biri, son satırda gösterilen akışlar kullanılarak hesaplanır.

    Bunu devam ettirebiliriz, ancak şunu görüyorsunuz, 8 hesaplandığında, diğer 14 fibonacci akımımız var.Eğer val için def onu değiştirirseniz fib ve fib.tail yerine yeni akışları oluşturmanın mevcut akımına atıfta çünkü

    , tüm bu yeni akışları kaybolur. Yeni bir akış oluşturulmayacağından, fib ve fib.tail numaralı telefonlara başka çağrı yapılmayacaktır.

    Şimdi, ikinci cevaba bakarsanız, tek bir fib çağrısı olduğunu ve map veya benzeri bir yöntem olduğunu fark edeceksiniz, bu nedenle çarpma efekti yoktur.

  • 7

    Hayır, özyinelemeli (global olarak) yığınlama yerine derleyici döngüsüne yardımcı olmaktır, bir derleme zamanı eniyilemesidir.

    Sorun, ilk uygulamadan, çeşitli aktarım yapılarına neden olan fib'un çeşitli aramalara yol açtığı ilk uygulamadan geldi, böylece aynı hesaplar tekrar yapıldı.

    fib zip fib.tail 
    //if we are at the 1000, it will compute million Streams 
    

    bunu izleyen

    var i = 0 
    def fib:Stream[Int] = { 
        i = i + 1 
        println("new Stream : " + i) 
        Stream.cons(1, Stream.cons(1, (fib zip fib.tail) map {case (x, y) => x + y})) 
    }