2011-12-24 23 views
6

Scala'da backtracking algoritması ile stream tanımlamak için herhangi bir yolu var mı? Örneğin, aşağıdaki backtracking algoritması, belirli bir boyuttaki tüm "ikili" dizeleri yazdırır.Geri izleme algoritması akışa nasıl dönüştürülür?

def binaries(s:String, n:Int) { 
    if (s.size == n) 
    println(s) 
    else { 
    binaries(s + '0', n) 
    binaries(s + '1', n) 
    } 
}

ben başka yinelemeli algoritması kullanarak belirli bir boyutta "ikili" dizeleri bir stream tanımlayabilirsiniz inanıyoruz. Ancak yukarıdaki geri izleme algoritmasını yukarıdaki stream'a dönüştürebilir miyim merak ediyorum.

cevap

11

Bu oldukça düz ileri:

def binaries(s: String, n: Int): Stream[String] = 
    if (s.size == n) Stream(s) 
    else binaries(s + "0", n) append binaries(s + "1", n) 

Not append kullanımı - bu yöntemin diğeri için standart dışı olduğunu Bir gereksinim olan koleksiyonlar, kendi adına parametresini alması gerektiğinden.

+0

Teşekkürler, tam olarak aradığım şey budur :) Orijinal geri izleme sürümüne göre daha verimli (yığın bellek tüketimi açısından) gibi görünüyor değil mi? – Michael

+0

@Michael Belki de. "Stream" kullanarak kodun analiz verimliliğini çok rahat kullanmıyorum. Bunları kullanmak için gerekli bulursam, taşmadığından emin olmak için REPL üzerindeki kodu test ettiğinizden emin oluyorum. –

+0

@Michael, akış sürümü yığın çerçeve kullanımı açısından daha az verimlidir. Her bir özyinelemeli arama, sürümünüzde yalnızca bir tanesine göre 4 adet yığın çerçevesi kullanır. Pratikte, bu örnek için bir sorun olmamalı. Yığın bellek kullanımıyla ilgili olarak, Aktarım sınıfı depolanan referans başına bellek kullanımı açısından en az etkili olan scala koleksiyonlarından biridir ancak kazara akıntının başına tutunmazsanız genellikle sorun yoktur. – huynhjl

3

yapabilirsiniz, ancak lazily değerlendirmek olmaz: Mesela

def bin(s: String, n: Int): Stream[String] = { 
    if (s.length == n) { 
    println("got " + s) // for figuring out when it's evaluated 
    Stream(s) 
    } else { 
    val s0 = s + '0' 
    val s1 = s + '1' 
    bin(s0, n) ++ bin(s1, n) 
    } 
} 

, bin("", 2).take(2).foreach(println) çalıştırırken, aşağıdaki çıktıyı alırsınız:

scala> bin("", 2).take(2).foreach(println) 
got 00 
got 01 
got 10 
got 11 
00 
01 

Eğer sakıncası yoksa TraversableView kullanarak, burada açıklanan dönüştürmeyi kullanabilirsiniz https://stackoverflow.com/a/3816012/257449. Öyleyse kod olur: Sonra

def toTraversable[T](func : (T => Unit) => Unit) = new Traversable[T] { 
    def foreach[X](f : T => X) = func(f(_) : Unit)      
} 

def bin2(str: String, n: Int) = { 
    def recurse[U](s: String, f: (String) => U) { 
    if (s.length == n) { 
     println("got " + s) // for figuring out when it's evaluated 
     f(s) 
    } else { 
     recurse(s + '0', f) 
     recurse(s + '1', f) 
    } 
    } 
    toTraversable[String](recurse(str, _)) view 
} 

scala> bin2("", 2).take(2).foreach(println) 
got 00 
00 
got 01 
01 
got 10 
+0

Birazcık ScalaDoc scrounging uzun bir yol kat edebilir ... :-) –

+0

@ DanielC.Sobral, aslında, daha önce hiç kullanmam ya da görmedim. – huynhjl

İlgili konular