2009-07-07 18 views
13

संभावित डुप्लिकेट:
Is there a problem that has only a recursive solution?
Can every recursion be converted into iteration?
“Necessary” Uses of Recursion in Imperative Languagesक्या कोई समस्या है जिसमें केवल एक पुनरावर्ती समाधान है?

वहाँ एक समस्या केवल एक पुनरावर्ती समाधान, वह है, एक समस्या एक पुनरावर्ती समाधान है, लेकिन एक सतत समाधान है कि है अभी तक पाया गया है, या बेहतर अभी तक, अस्तित्व में साबित हुआ है (जाहिर है, यह एक पूंछ-रिकर्सन नहीं है)?

+3

जो कि आप रिकर्सिव कहलाते हैं पर निर्भर करता है। प्रत्येक रिकर्सिव फ़ंक्शन को स्टैक को लागू करके गैर-रिकर्सिव में अनुवाद किया जा सकता है .. – yairchu

+65

हां; इसे यहां विस्तार से वर्णित किया गया है: http://stackoverflow.com/questions/1094679/ –

+0

@Marc Gravell: यह बिल्कुल बढ़िया है! –

उत्तर

9

Ackermann function प्रत्यावर्तन

+0

+1। अच्छा लगा। मुझे लगता है कि यह यहां पर एकमात्र वास्तविक उत्तर है (ठीक है, मार्क की टिप्पणी के अलावा)। –

+13

काउंटर: "एकरमेन फ़ंक्शन को कॉनवे चेन एरो नोटेशन का उपयोग करके गैर-कर्कश रूप से व्यक्त किया जा सकता है" (विकिपीडिया देखें) –

+0

और "हाइपर ऑपरेटर" और "न्यूथ के अप-तीर नोटेशन का अनुक्रमित संस्करण" –

4

सभी गैर एनपी-पूर्ण समस्याओं को केवल अनुक्रम, निर्णय और पुनरावृत्ति के साथ हल किया जा सकता है। रिकर्सन की आवश्यकता नहीं होनी चाहिए, हालांकि यह आमतौर पर समस्या को बहुत सरल बनाता है।

+1

तो एनपी-पूर्ण वाले लोग क्या कर सकते हैं। यह बस अधिक समय लगता है। – Ian

+1

यह उत्तर गलत है। अपरिहार्य समस्याएं एनपी-पूर्ण नहीं हैं (और उन्हें पुनरावृत्ति या पुनरावृत्ति के साथ हल नहीं किया जा सकता है)। – Paulpro

19

फ़ंक्शन कॉल को स्टैक पर धक्का देने के साथ प्रतिस्थापित करता है, और स्टैक को पॉप-अप करने के साथ लौटाता है, और आपने रिकर्सन को समाप्त कर दिया है।

संपादित करें: प्रतिक्रिया पुनरावर्ती एल्गोरिदम लगातार अंतरिक्ष में दिखाया जा सकता है "एक ढेर का उपयोग कर अंतरिक्ष की लागत में कमी नहीं करता" करने के लिए

में, यह एक पूंछ पुनरावर्ती ढंग से लिखा जा सकता है। यदि यह पूंछ-पुनरावर्ती प्रारूप में लिखा गया है, तो कोई भी सभ्य संकलक ढेर को ध्वस्त कर सकता है। हालांकि, इसका मतलब है कि "कन्वर्ट फ़ंक्शन कॉल को स्पष्ट स्टैक-पुश पर कॉल करता है" विधि भी स्थिर स्थान लेती है। एक उदाहरण के रूप में, चतुर लेते हैं।

भाज्य:

def fact_rec(n): 
    ' Textbook Factorial function ' 
    if n < 2: return 1 
    else:  return n * f(n-1) 


def f(n, product=1): 
    ' Tail-recursive factorial function ' 
    if n < 2: return product 
    else:  return f(n-1, product*n) 

def f(n): 
    ' explicit stack -- otherwise same as tail-recursive function ' 
    stack, product = [n], 1 
    while len(stack): 
     n = stack.pop() 
     if n < 2: pass 
     else: 
      stack.append(n-1) 
      product *= n 
    return product 

क्योंकि stack.pop() पाश में stack.append() इस प्रकार है, ढेर उस में एक से अधिक आइटम है कभी नहीं, और इसलिए यह लगातार अंतरिक्ष को पूरा आवश्यकता। यदि आप 1-लंबाई के ढेर के बजाय एक अस्थायी चर का उपयोग करने की कल्पना करते हैं, तो यह आपके मानक पुनरावृत्त-फैक्टोरियल एल्गोरिदम बन जाता है।

बेशक, रिकर्सिव फ़ंक्शन हैं जिन्हें पूंछ-पुनरावर्ती प्रारूप में नहीं लिखा जा सकता है। आप अभी भी किसी प्रकार के ढेर के साथ पुनरावर्तक प्रारूप में परिवर्तित कर सकते हैं, लेकिन अगर अंतरिक्ष-जटिलता पर कोई गारंटी थी तो मुझे आश्चर्य होगा।

+2

यह रिकर्सन उन्मूलन नहीं है। जब कोई रिकर्सिव फ़ंक्शन को गैर-रिकर्सिव के साथ प्रतिस्थापित करता है तो इसे सैद्धांतिक रूप से असीमित स्टैक की बजाय सीमित मेमोरी का उपयोग करना होता है। –

+3

"स्मृति की सीमित मात्रा का उपयोग करने की गारंटी" एक गैर-कार्यशील कार्य की परिभाषा नहीं है। यह एक वांछनीय संपत्ति हो सकती है, लेकिन यह एक निश्चित आवश्यकता नहीं है। एक स्मृति रिसाव के साथ एक पुनरावृत्त एल्गोरिदम स्मृति की संभावित असीमित मात्रा का उपयोग करेगा, लेकिन कोई भी तर्क नहीं देगा कि अकेले एल्गोरिदम रिकर्सिव बनाता है। – Chuck

+2

@ jia3ep: यह रिकर्सन उन्मूलन है। वास्तव में, ऑपरेटिंग सिस्टम के कॉल स्टैक (जो कि कई आर्किटेक्चर में सीमित स्थान है) से भार को ले जाने से, और फ़ंक्शन कॉल के ओवरहेड से परहेज करते हुए, कुछ स्थितियों में इसका पहले से ही एक वास्तविक लाभ होता है। – Jimmy

3

यह कितने कोड की लाइनें यह समस्या को हल करने के लिए ले जा रहा है करने के लिए नीचे आता है ...

सूची सभी अपने सी पर फ़ाइलें: \ बिना प्रत्यावर्तन और उसके बाद का उपयोग कर। निश्चित रूप से आप इसे दोनों तरीकों से कर सकते हैं - लेकिन एक तरीका समझने और डीबग करने के लिए बहुत आसान होगा।

+0

एक पेड़ में खोजें गहराई या पहली बार हो सकता है। पूर्व का स्वाभाविक रूप से रिकर्सन के साथ अनुवाद किया जाता है, लेकिन बाद में एक पुनरावृत्ति विधि के साथ कार्यान्वित करना अधिक स्वाभाविक है। –

0

नहीं। रिकर्सन स्टैक से अधिक कुछ नहीं है और आप स्पष्ट रूप से एक ढेर को लागू करके एक ही परिणाम प्राप्त कर सकते हैं।

यह एक विशेष रूप से संतोषजनक उत्तर नहीं हो सकता है, लेकिन आपको बेहतर उत्तर प्राप्त करने के लिए एक और अधिक विशिष्ट प्रश्न पूछना होगा। उदाहरण के लिए, सिद्धांत निर्देश देता है कि कंप्यूटिंग के स्तर में समस्याओं की सीमा में काफी अंतर होता है जिसे हल किया जा सकता है यदि आपके पास थोड़ी देर लूप बनाम केवल लूप के लिए पारंपरिक (पारंपरिक) हो।

मैंने वहां "पारंपरिक" रखा क्योंकि वे वास्तव में उन लूपों का मतलब करते हैं जो एक निश्चित संख्या को फिर से सक्रिय करते हैं जबकि सी शैली (...; ...; ...) लूप छिपाने में लूप होते हैं।

6

प्रोग्रामिंग में, रिकर्सन वास्तव में पुनरावृत्ति का एक विशेष मामला है - एक जहां आप कॉल स्टैक का उपयोग राज्य के भंडारण के विशेष साधन के रूप में करते हैं।आप किसी भी पुनरावर्ती विधि को पुनरावृत्त करने के लिए पुनः लिख सकते हैं। यह अधिक जटिल या कम सुरुचिपूर्ण हो सकता है, लेकिन यह बराबर है। कुछ उदाहरण हैं खोजने जड़ों (Newton's Method), कंप्यूटिंग अभाज्य संख्या, ग्राफ अनुकूलन, आदि हालांकि, यहां भी, वहाँ का सवाल है -

गणित में, वहाँ कुछ समस्याओं कि एक जवाब पर पहुंचने के लिए पुनरावर्ती तकनीक की आवश्यकता होती हैं आप "पुनरावृत्ति" और "रिकर्सन" शब्दों के बीच अंतर कैसे करते हैं।

संपादित करें: जैसा कि अन्य ने बताया है, वहां कई कार्य मौजूद हैं जिनकी परिभाषा रिकर्सिव है - पूर्व। Ackermann function। हालांकि, इसका मतलब यह नहीं है कि उन्हें पुनरावृत्त संरचनाओं का उपयोग करके गणना नहीं की जा सकती है - जब तक आपके पास ट्यूरिंग पूर्ण ऑपरेशन सेट और असीमित स्मृति हो।

8

बिना व्यक्त नहीं किया जा सकता आप प्रत्यावर्तन के बिना एक Turing Machine परिभाषित कर सकते हैं (है ना?) तो प्रत्यावर्तन एक भाषा Turing-complete होने के लिए आवश्यक नहीं है।

+0

से सहमत हूं, ट्यूरिंग मशीन स्टैक आधारित automatas से ऊपर है क्योंकि यह उनको अनुकरण कर सकती है (स्ट्रिप को स्टैक के रूप में उपयोग किया जा सकता है) – fortran

9

Ackermann function answer के जवाब में, यह एक बहुत सीधी कन्वर्ट-द-कॉल-स्टैक-इन-ए-रीयल-स्टैक समस्या है। यह पुनरावृत्त संस्करण का एक लाभ भी दिखाता है।

मेरे प्लेटफ़ॉर्म (पायथन 3.1 आरसी 2/Vista32) पर पुनरावृत्त संस्करण एके (3,7) = 1021 ठीक की गणना करता है, जबकि रिकर्सिव संस्करण स्टैक ओवरफ्लो। एनबी: यह एक अलग मशीन पर पायथन 2.6.2/Vista64 पर स्टैक ओवरफ्लो नहीं था, इसलिए यह प्लेटफार्म-निर्भर,

(सामुदायिक विकी क्योंकि यह वास्तव में किसी अन्य उत्तर पर टिप्पणी है [अगर केवल टिप्पणियां समर्थित हैं कोड स्वरूपण ....])

def ack(m,n): 
    s = [m] 
    while len(s): 
    m = s.pop() 
    if m == 0: 
     n += 1 
    elif n == 0: 
     s.append(m-1) 
     n = 1 
    else: 
     s.append(m-1) 
     s.append(m) 
     n -= 1 
    return n 
+0

मुझे लगता है कि 'एपेंड' वास्तव में 'पुश' है? –

+0

अच्छी तरह से, यह अजगर हेह में एक सूची है। – Jimmy

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