खोज…


पुनरावर्ती कार्य

आइए एक सरल एल्गोरिथ्म से शुरू करते हैं, यह देखने के लिए कि रूबी में रिकर्सन कैसे लागू किया जा सकता है।

एक बेकरी में बेचने के लिए उत्पाद हैं। उत्पाद पैक में हैं। यह पैक में ही ऑर्डर देता है। पैकेजिंग सबसे बड़े पैक आकार से शुरू होती है और फिर शेष मात्रा अगले पैक आकारों में उपलब्ध होती है।

उदाहरण के लिए, यदि 16 का आदेश प्राप्त होता है, तो बेकरी 5 से 2 पैक और 3 पैक से 2 आवंटित करता है। 2 5 + 2 3 = 16. आइए देखें कि यह कैसे पुनरावृत्ति में लागू किया जाता है। "आवंटित" यहाँ पुनरावर्ती कार्य है।

#!/usr/bin/ruby

class Bakery
  attr_accessor :selected_packs

  def initialize
    @packs = [5,3] # pack sizes 5 and 3
    @selected_packs = []
  end

  def allocate(qty)
    remaining_qty = nil

    # ==============================================
    # packs are allocated in large packs first order
    # to minimize the packaging space
    # ==============================================
    @packs.each do |pack|
      remaining_qty = qty - pack

      if remaining_qty > 0
        ret_val = allocate(remaining_qty)
        if ret_val == 0
          @selected_packs << pack
          remaining_qty = 0
          break
        end
      elsif remaining_qty == 0
        @selected_packs << pack
        break
      end
    end

    remaining_qty
  end
end

bakery = Bakery.new
bakery.allocate(16)
puts "Pack combination is: #{bakery.selected_packs.inspect}"

आउटपुट है:

पैक संयोजन है: [३, ३, ५, ५]

पूंछ की पुनरावृत्ति

पुनरावृत्ति का उपयोग करके कई पुनरावर्ती एल्गोरिदम व्यक्त किए जा सकते हैं। उदाहरण के लिए, सबसे बड़ा सामान्य भाजक फ़ंक्शन को पुनरावर्ती लिखा जा सकता है :

def gdc (x, y)
  return x if y == 0
  return gdc(y, x%y)
end

या पुनरावृति:

def gdc_iter (x, y)
  while y != 0 do
    x, y = y, x%y
  end

  return x
end

दो एल्गोरिदम सिद्धांत में बराबर हैं, लेकिन पुनरावर्ती संस्करण एक SystemStackError को जोखिम में डालते हैं । हालाँकि, चूंकि पुनरावर्ती पद्धति स्वयं कॉल के साथ समाप्त होती है, इसलिए इसे स्टैक ओवरफ़्लो से बचने के लिए अनुकूलित किया जा सकता है। इसे लगाने का एक और तरीका: पुनरावर्ती एल्गोरिथ्म में पुनरावृत्ति के समान मशीन कोड हो सकता है यदि कंपाइलर विधि के अंत में पुनरावर्ती विधि कॉल की तलाश करना जानता है। रूबी डिफ़ॉल्ट रूप से पूंछ कॉल अनुकूलन नहीं करता है, लेकिन आप इसे चालू कर सकते हैं :

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}

टेल-कॉल ऑप्टिमाइज़ेशन को चालू करने के अलावा, आपको इंस्ट्रक्शन ट्रेसिंग को भी बंद करना होगा। दुर्भाग्य से, इन विकल्पों में केवल संकलन समय पर लागू होते हैं, तो आप या तो जरूरत require किसी अन्य फ़ाइल से पुनरावर्ती विधि या eval विधि परिभाषा:

RubyVM::InstructionSequence.new(<<-EOF).eval
  def me_myself_and_i
    me_myself_and_i
  end
EOF
me_myself_and_i # Infinite loop, not stack overflow

अंत में, अंतिम रिटर्न कॉल को विधि और केवल विधि वापस करनी चाहिए। इसका मतलब है कि आपको मानक फैक्टरियल फ़ंक्शन को फिर से लिखना होगा:

def fact(x)
  return 1 if x <= 1
  return x*fact(x-1)
end

कुछ इस तरह से:

 def fact(x, acc=1)
   return acc if x <= 1
   return fact(x-1, x*acc)
 end

यह संस्करण एक दूसरे (वैकल्पिक) तर्क के माध्यम से संचित राशि को पारित करता है जो 1 को चूकता है।

आगे पढ़ने: रूबी और टेलिन रूबी में टेल कॉल ऑप्टिमाइज़ेशन



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow