2011-12-24 11 views
6

क्या stream को स्कैला में backtracking एल्गोरिदम के साथ परिभाषित करने का कोई तरीका है?बैकट्रैकिंग एल्गोरिदम को स्ट्रीम करने के लिए कैसे परिवर्तित करें?

उदाहरण के लिए, निम्नलिखित backtracking एल्गोरिदम किसी दिए गए आकार के सभी "बाइनरी" तारों को प्रिंट करता है।

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

मेरा मानना ​​है कि मैं किसी दिए गए आकार एक और पुनरावृत्ति एल्गोरिथ्म का उपयोग कर के "बाइनरी" तार के एक stream परिभाषित कर सकते हैं। हालांकि मुझे आश्चर्य है कि क्या मैं एल्गोरिदम को stream पर बैकट्रैकिंग कर सकता हूं।

उत्तर

11

यह सुंदर सीधी-सपाट है:

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

नोट append के उपयोग - इस विधि अन्य के लिए गैर मानक है संग्रह, जो एक आवश्यकता है क्योंकि इसे अपना पैरामीटर नाम से लेना है।

+0

धन्यवाद, यह वही है जो मैं ढूंढ रहा हूं :) यह मूल बैकट्रैकिंग संस्करण की तुलना में अधिक कुशल (स्टैक मेमोरी खपत के मामले में) जैसा दिखता है, है ना? – Michael

+0

@ माइकल शायद। मैं 'स्ट्रीम' का उपयोग कर कोड की सहज विश्लेषण दक्षता नहीं हूं। अगर मुझे उनका उपयोग करना आवश्यक लगता है, तो मैं यह सुनिश्चित करने के लिए आरईपीएल पर कोड का परीक्षण करना सुनिश्चित करता हूं कि यह अतिप्रवाह नहीं है। –

+0

@ माइकल, स्टैक फ्रेम उपयोग के संदर्भ में स्ट्रीम संस्करण कम कुशल है। प्रत्येक रिकर्सिव कॉल आपके संस्करण में केवल एक की तुलना में 4 स्टैक फ्रेम का उपयोग करता है। अभ्यास में, यह इस उदाहरण के लिए एक समस्या नहीं होनी चाहिए। ढेर मेमोरी उपयोग के संबंध में, स्ट्रीम क्लास संग्रहित प्रति संदर्भ स्मृति उपयोग की अवधि में स्कैला संग्रह के कम से कम कुशल में से एक है, लेकिन आमतौर पर यह ठीक है अगर आप गलती से स्ट्रीम के सिर पर नहीं जाते हैं ... – huynhjl

3

आप कर सकते हैं, लेकिन यह lazily का मूल्यांकन नहीं होगा:

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) को क्रियान्वित करने, आपको निम्न उत्पादन मिल जाएगा:

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

आप कोई आपत्ति नहीं है TraversableView का उपयोग करके आप यहां वर्णित रूपांतरण का उपयोग कर सकते हैं https://stackoverflow.com/a/3816012/257449। तो फिर कोड हो जाता है:

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

स्कैलाडॉक स्क्रॉन्गिंग का एक छोटा सा लंबा सफर तय कर सकता है ... :-) –

+0

@ डैनियल सी। सोब्राल, वास्तव में, मैंने पहले कभी 'एपेंड' का उपयोग या देखा नहीं है। – huynhjl

संबंधित मुद्दे