यह समझना कि पुनरावर्ती कार्य कैसे कार्य करते हैं


115

जैसा कि शीर्षक बताता है कि मेरे पास एक बहुत ही मौलिक प्रोग्रामिंग प्रश्न है जो मैं अभी तक नहीं कर सका हूं। सभी (अत्यंत चतुर) को फ़िल्टर करना "पुनरावृत्ति को समझने के लिए, आपको पहले पुनरावृत्ति को समझना होगा।" विभिन्न ऑनलाइन थ्रेड्स के उत्तर मुझे अभी भी नहीं मिल रहे हैं।

यह समझते हुए कि जब हमें यह नहीं पता होता है कि हम क्या जानते हैं, हम गलत सवाल पूछ सकते हैं या गलत सवाल पूछ सकते हैं, तो मैं वह साझा करूंगा जो मैं समझता हूं कि मेरा सवाल इस उम्मीद में है कि एक समान दृष्टिकोण वाला कोई व्यक्ति कुछ साझा कर सकता है थोड़ा सा ज्ञान जो मेरे लिए पुनरावर्ती प्रकाश बल्ब को चालू करने में मदद करेगा!

यहाँ फ़ंक्शन है (स्विफ्ट में वाक्य रचना लिखी गई है):

func sumInts(a: Int, b: Int) -> Int {
    if (a > b) {
        return 0
    } else {
        return a + sumInts(a: a + 1, b: b)
    }
}

हम अपने तर्क के रूप में 2 और 5 का उपयोग करेंगे:

println(sumInts(a: 2, b: 5))

स्पष्ट रूप से उत्तर 14. है लेकिन मैं इस बात पर स्पष्ट नहीं हूं कि उस मूल्य को कैसे प्राप्त किया जाता है।

ये मेरे 2 हैंगअप हैं:

  1. किसी शर्त के पूरा होने तक फ़ंक्शन को पुनरावर्ती कहा जाता है। वह दशा क> ख है। जब यह स्थिति पूरी हो जाती है, तो वापस लौटें। 0. पहली नज़र में, मैं वापसी मान 0 होने की उम्मीद करूँगा जो कि स्पष्ट रूप से गलत है।

  2. प्रत्येक पुनरावृत्ति पर 'a' के मान को प्रिंट करने से एक मान निकलता है जिसकी मैं अपेक्षा करता हूं: 2, 3, 4, 5 (जिस बिंदु पर 5 + 1> b जो पहली शर्त को पूरा करता है: a> b) लेकिन मैं अभी भी डॉन ' टी देखें कि 14 का मूल्य कैसे प्राप्त किया जाता है।

मेरा पहला विचार यह है कि निम्नलिखित के समान कुछ जादुई तरीके से हो रहा है:

var answer = a;
answer += a+1 until a > b;
return answer;   

तो जादू से बाहर, मैं सिर्फ कुछ नहीं पा रहा हूं। मुझे यह समझने में अच्छा लगेगा कि केवल निहितार्थ से अधिक क्या हो रहा है।

अगर कोई इस तरह के फंक्शन के दौरान तकनीकी रूप से बता सकता है और इसका परिणाम 0 नहीं है, तो आखिरकार a + sumInts(a: a + 1, b: b) = 14, मैं हमेशा आपके कर्ज में कैसे रहूंगा।


7
रिकर्सन उन प्रोग्रामिंग अवधारणाओं में से एक है जो कोड की तुलना में गणितीय शब्दों को समझना बहुत आसान है; यहाँ
blgt

5
LearnYouARecursion, विश्व स्तरीय प्रोफेसर से पूरी समस्या सेट!
recursion.ninja

15
मैं तो बस है गूगल सर्च बॉक्स में "Recursion" टाइप करने के लिए आप से आग्रह करता हूं करने के लिए। उन ईस्टर अंडे में से एक। मैं तुम्हारे लिए आश्चर्य को खराब नहीं करूंगा।
फ्लोरिस

7
के संभावित डुप्लिकेट stackoverflow.com/questions/25676961/...
नील McGuigan

जवाबों:


107

मुझे लगता है कि भ्रम को "एक ही कार्य" के रूप में कई बार कहा जा रहा है। यदि आप इसे "एक ही फ़ंक्शन की कई प्रतियां कहा जा रहा है" के रूप में सोचते हैं, तो यह स्पष्ट हो सकता है:

फ़ंक्शन की केवल एक प्रति कभी 0 लौटती है, और यह पहला नहीं है (यह अंतिम है)। तो पहले वाले को कॉल करने का परिणाम 0 नहीं है।

दूसरे भ्रम की स्थिति के लिए, मुझे लगता है कि अंग्रेजी में पुनरावृत्ति को दूर करना आसान होगा। इस लाइन को पढ़ें:

return a + sumInts(a + 1, b: b)

जैसा कि 'a' प्लस का मान लौटाते हैं (फ़ंक्शन की दूसरी कॉपी का रिटर्न वैल्यू, जो 'a' प्लस की कॉपी वैल्यू है) (फ़ंक्शन की दूसरी कॉपी का रिटर्न वैल्यू, जो दूसरी कॉपी की वैल्यू है ' एक 'प्लस (... "), फ़ंक्शन की प्रत्येक प्रति के साथ 1 की वृद्धि के साथ खुद की एक नई प्रति पैदा करता है, जब तक कि एक> बी शर्त पूरी नहीं होती है।

जब तक आप पहुंचते हैं तब तक a> b स्थिति सही होती है, आपके पास फ़ंक्शन के प्रतियों की एक लंबी (संभावित मनमानी) दौड़ के बीच में सभी की लंबी स्टैक होती है, सभी अगली कॉपी के परिणाम का इंतजार करते हुए पता लगाते हैं कि वे क्या हैं 'ए' में जोड़ना चाहिए।

(संपादित करें: यह भी पता होना चाहिए कि मेरे द्वारा बताए गए फ़ंक्शन की प्रतियों का ढेर असली चीज़ है जो वास्तविक मेमोरी को लेता है, और यदि यह बहुत बड़ा हो जाता है तो आपके प्रोग्राम को क्रैश कर देगा। कंपाइलर इसे कुछ में ऑप्टिमाइज़ कर सकता है। मामलों, लेकिन स्टैकिंग स्पेस को समाप्त करना कई भाषाओं में पुनरावर्ती कार्यों का एक महत्वपूर्ण और दुर्भाग्यपूर्ण सीमा है)


7
कैटफ़िश_मन: मुझे लगता है कि आपने इसे रद्द कर दिया है! एक ही फ़ंक्शन की कई "प्रतियाँ" के रूप में सोचने से कुल अर्थ निकलता है। मैं अभी भी इसके चारों ओर अपना सिर लपेट रहा हूं, लेकिन मुझे लगता है कि आपने मुझे सही रास्ते पर भेज दिया है! एक साथी प्रोग्रामर की मदद करने के लिए अपने व्यस्त दिन से समय निकालने के लिए धन्यवाद! मैं आपके उत्तर को सही उत्तर के रूप में चिह्नित करूंगा। आपका दिन अच्छा रहे!
जेसन एलवुड

13
यह एक अच्छा सादृश्य है - हालांकि सावधान रहें कि इसे शाब्दिक रूप से न लें क्योंकि प्रत्येक "कॉपी" वास्तव में एक ही कोड है। प्रत्येक प्रतिलिपि के लिए अलग-अलग है वह सभी डेटा है जिस पर वह काम कर रहा है।
टिम बी

2
मैं इसे कॉपी समझकर बहुत खुश नहीं हूं। मुझे लगता है कि एक अधिक सहज स्पष्टीकरण फ़ंक्शन को स्वयं (कोड, यह क्या करता है) और एक फ़ंक्शन इनवोकेशन (उस फ़ंक्शन का तात्कालिकता) में अंतर करने के लिए है जिसमें एक स्टैक फ्रेम / निष्पादन संदर्भ जुड़ा हुआ है। फ़ंक्शन को उसके स्थानीय चर के स्वामी नहीं होते हैं, उन्हें तुरंत बुलाया जाता है क्योंकि फ़ंक्शन को बुलाया जाता है (इनवोक)। लेकिन मुझे लगता है कि यह पुनरावृत्ति के लिए एक परिचय के रूप में करेगा
थॉमस

5
सही शब्दावली यह है कि फ़ंक्शन के कई चालान हैं । प्रत्येक आह्वान के चर के अपने उदाहरण हैं aऔर b
थियोडोर नॉरवेल

6
हां, इसमें एक महत्वपूर्ण मात्रा सटीक है जिसे इस उत्तर में जोड़ा जा सकता है। मैंने जानबूझकर "एक फ़ंक्शन के उदाहरण" और "एक फ़ंक्शन के चालान के सक्रियण रिकॉर्ड" के बीच अंतर को छोड़ दिया, क्योंकि यह अतिरिक्त वैचारिक भार था जो वास्तव में समस्या को समझने में मदद नहीं करता है। यह अन्य समस्याओं को समझने में मदद करता है, इसलिए यह अभी भी उपयोगी जानकारी है, बस कहीं और। ये टिप्पणियां इसके लिए एक अच्छी जगह की तरह लगती हैं :)
कैटफ़िश_मैन

130

1. जब तक किसी शर्त को पूरा नहीं किया जाता है, फ़ंक्शन को पुनरावर्ती कहा जाता है। वह शर्त है a > b। जब यह स्थिति पूरी हो जाती है, तो वापस लौटें। 0. पहली नज़र में, मैं वापसी मान 0 होने की उम्मीद करूँगा जो स्पष्ट रूप से गलत है।

यहाँ कंप्यूटर कंप्यूटिंग sumInts(2,5)सोचता है कि क्या यह करने में सक्षम था:

I want to compute sumInts(2, 5)
for this, I need to compute sumInts(3, 5)
and add 2 to the result.
  I want to compute sumInts(3, 5)
  for this, I need to compute sumInts(4, 5)
  and add 3 to the result.
    I want to compute sumInts(4, 5)
    for this, I need to compute sumInts(5, 5)
    and add 4 to the result.
      I want to compute sumInts(5, 5)
      for this, I need to compute sumInts(6, 5)
      and add 5 to the result.
        I want to compute sumInts(6, 5)
        since 6 > 5, this is zero.
      The computation yielded 0, therefore I shall return 5 = 5 + 0.
    The computation yielded 5, therefore I shall return 9 = 4 + 5.
  The computation yielded 9, therefore I shall return 12 = 3 + 9.
The computation yielded 12, therefore I shall return 14 = 2 + 12.

जैसा कि आप देखते हैं, फ़ंक्शन को कुछ कॉल sumIntsवास्तव में 0 देता है, हालांकि यह अंतिम मान नहीं है क्योंकि कंप्यूटर को अभी भी 5 को उस 0 में जोड़ना है, फिर परिणाम में 4, फिर 3, फिर 2, जैसा कि चार अंतिम वाक्यों द्वारा वर्णित है हमारे कंप्यूटर के विचार। ध्यान दें कि पुनरावर्ती में, कंप्यूटर को केवल पुनरावर्ती कॉल की गणना करने की आवश्यकता नहीं है, यह भी याद रखना होगा कि पुनरावर्ती कॉल द्वारा लौटाए गए मूल्य के साथ क्या करना है। कंप्यूटर की मेमोरी का एक विशेष क्षेत्र है जिसे स्टैक कहा जाता है जहां इस तरह की जानकारी बचाई जाती है, यह स्थान सीमित है और ऐसे कार्य जो बहुत अधिक पुनरावर्ती हैं, स्टैक को समाप्त कर सकते हैं: यह स्टैक ओवरफ्लो हमारी सबसे प्रिय वेबसाइट को अपना नाम देता है।

आपके कथन से यह अनुमान लगता है कि कंप्यूटर यह भूल जाता है कि पुनरावर्ती कॉल करते समय वह क्या था, लेकिन ऐसा नहीं है, यही कारण है कि आपका निष्कर्ष आपके अवलोकन से मेल नहीं खाता है।

2. प्रत्येक पुनरावृत्ति पर 'a' के मान को निकालने से एक मान निकलता है जिसकी मुझे उम्मीद थी: 2, 3, 4, 5 (जिस बिंदु पर 5 + 1> b जो पहली शर्त को पूरा करता है: a> b) लेकिन मैं अभी भी यह नहीं देखें कि 14 का मूल्य कैसे प्राप्त होता है।

ऐसा इसलिए है क्योंकि रिटर्न वैल्यू अपने आप में नहीं aहै, बल्कि aरिकर्सिव कॉल द्वारा दिए गए वैल्यू और वैल्यू का योग है ।


3
इस महान उत्तर को लिखने के लिए समय निकालने के लिए धन्यवाद माइकल! +1!
जेसन एलवुड

9
यदि आप संशोधित करते हैं sumIntsतो @JasonElwood शायद यह मददगार है कि यह वास्तव में "कंप्यूटर विचार" लिखता है। एक बार जब आप इस तरह के कार्यों का एक हाथ लिख चुके हैं, तो आप शायद "मिल गया" होगा!
माइकल ले बारबियर ग्रुएनवाल्ड

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

1
@EricLippert जबकि पुनरावृत्ति को लागू करने के लिए इस्तेमाल की जाने वाली तकनीक प्रति सेगमेंट एक दिलचस्प विषय है , मुझे यकीन नहीं है कि यह ओपी के लिए उपयोगी होगा - जो यह समझना चाहता है कि "यह कैसे काम करता है" - जिसका उपयोग विभिन्न प्रकार के तंत्र के संपर्क में किया जा सकता है। निरंतरता शैली या विस्तार आधारित भाषाओं (जैसे टेक्स और एम 4) से गुजर रहे हैं नहीं आंतरिक रूप से कठिन और अधिक सामान्य प्रोग्रामिंग मानदंड से करते हैं, मैं करूँगा इन "विदेशी" और एक छोटे से लेबल करके किसी को भी अपराध नहीं सफेद झूठ की तरह "यह हमेशा पर होता है ढेर" चाहिए ओपी को अवधारणा को समझने में मदद करें। (और एक प्रकार का स्टैक हमेशा शामिल होता है।)
माइकल ले बारबियर ग्रुएनवाल्ड

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

48

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

आपको हर बार याद रखना चाहिए कि फ़ंक्शन स्वयं को पुन: कॉल करता है यह समस्या के सबसेट के साथ एक नया संदर्भ बनाता है, एक बार उस भाग को हल करने पर यह वापस आ जाता है ताकि पिछली पुनरावृत्ति पूरी हो सके।

मैं आपको चरण दिखाऊंगा:

sumInts(a: 2, b: 5) will return: 2 + sumInts(a: 3, b: 5)
sumInts(a: 3, b: 5) will return: 3 + sumInts(a: 4, b: 5)
sumInts(a: 4, b: 5) will return: 4 + sumInts(a: 5, b: 5)
sumInts(a: 5, b: 5) will return: 5 + sumInts(a: 6, b: 5)
sumInts(a: 6, b: 5) will return: 0

एक बार समनट (a: 6, b: 5) निष्पादित हो गया है, तो परिणाम की गणना की जा सकती है ताकि आपके द्वारा प्राप्त परिणामों के साथ श्रृंखला वापस जा सके:

 sumInts(a: 6, b: 5) = 0
 sumInts(a: 5, b: 5) = 5 + 0 = 5
 sumInts(a: 4, b: 5) = 4 + 5 = 9
 sumInts(a: 3, b: 5) = 3 + 9 = 12
 sumInts(a: 2, b: 5) = 2 + 12 = 14.

पुनरावृत्ति की संरचना का प्रतिनिधित्व करने का एक और तरीका:

 sumInts(a: 2, b: 5) = 2 + sumInts(a: 3, b: 5)
 sumInts(a: 2, b: 5) = 2 + 3 + sumInts(a: 4, b: 5)  
 sumInts(a: 2, b: 5) = 2 + 3 + 4 + sumInts(a: 5, b: 5)  
 sumInts(a: 2, b: 5) = 2 + 3 + 4 + 5 + sumInts(a: 6, b: 5)
 sumInts(a: 2, b: 5) = 2 + 3 + 4 + 5 + 0
 sumInts(a: 2, b: 5) = 14 

2
बहुत अच्छी तरह से, रोब। आपने इसे एक ऐसे तरीके से रखा है जो बहुत स्पष्ट और समझने में आसान है। समय लेने के लिए शुक्रिया!
जेसन एलवुड

3
यह जो चल रहा है, उसका सबसे स्पष्ट निरूपण है, बिना सिद्धांत और तकनीकी विवरण के, निष्पादन के प्रत्येक चरण को स्पष्ट रूप से दर्शाता है।
ब्रायन

2
मैं खुश हूँ। :) इन बातों को समझाना हमेशा आसान नहीं होता। प्रशंसा के लिए धन्यवाद।
रोब

1
+1। इस तरह मैं इसका वर्णन करूंगा, विशेष रूप से संरचना के अपने अंतिम उदाहरण के साथ। यह दृष्टिहीन होने में सहायक है कि क्या हो रहा है।
KChaloux

40

पुनरावृत्ति समझने के लिए एक मुश्किल विषय है और मुझे नहीं लगता कि मैं इसे पूरी तरह से यहाँ न्याय कर सकता हूं। इसके बजाय, मैं आपके द्वारा यहां दिए गए कोड के विशेष टुकड़े पर ध्यान केंद्रित करने की कोशिश करूंगा और यह जानने की कोशिश करूंगा कि समाधान कैसे काम करता है और कोड के मैकेनिक इसके परिणाम की गणना कैसे करते हैं।

आपके द्वारा यहां दिया गया कोड निम्नलिखित समस्या को हल करता है: आप सभी पूर्णांकों का योग a से b, समावेशी जानना चाहते हैं। अपने उदाहरण के लिए, आप संख्याओं का योग 2 से 5, समावेशी चाहते हैं, जो है

2 + 3 + 4 + 5

किसी समस्या को पुनरावर्ती रूप से हल करने का प्रयास करते समय, पहले चरण में से एक यह पता लगाना चाहिए कि समस्या को उसी संरचना के साथ छोटी समस्या में कैसे तोड़ा जाए। तो मान लीजिए कि आप संख्याओं को 2 से 5 तक जोड़ना चाहते थे, समावेशी। इसे सरल बनाने का एक तरीका यह है कि उपरोक्त योग को फिर से लिखा जा सकता है

2 + (3 + 4 + 5)

यहाँ, (3 + 4 + 5) सभी पूर्णांकों का योग 3 और 5 के बीच होता है, समावेशी होता है। दूसरे शब्दों में, यदि आप 2 और 5 के बीच के सभी पूर्णांकों का योग जानना चाहते हैं, तो 3 और 5 के बीच के सभी पूर्णांकों की राशि की गणना करके शुरू करें, फिर 2 को जोड़ें।

तो आप 3 और 5 के बीच सभी पूर्णांकों के योग को कैसे सम्मिलित करते हैं? खैर, वह योग है

3 + 4 + 5

जिसके बदले सोचा जा सकता है

3 + (4 + 5)

यहां, (4 + 5) 4 और 5 के बीच के सभी पूर्णांकों का योग है। इसलिए, यदि आप 3 और 5 के बीच सभी संख्याओं के योग की गणना करना चाहते हैं, तो आप 4 और 5 के बीच के सभी पूर्णांकों का योग गणना करेंगे, फिर 3 जोड़ेंगे।

यहाँ एक पैटर्न है! यदि आप एक और बी के बीच पूर्णांकों के योग की गणना करना चाहते हैं, तो आप निम्न कार्य कर सकते हैं। सबसे पहले, पूर्णांक + a और b के बीच पूर्णांकों के योग की गणना कीजिए। इसके बाद, उस कुल में एक जोड़ें। आप देखेंगे कि "पूर्णांक 1 और b के बीच पूर्णांक की राशि की गणना, समावेशी" से होती है, एक ही तरह की समस्या है जो हम पहले से ही हल करने की कोशिश कर रहे हैं, लेकिन थोड़ा अलग मापदंडों के साथ। A से b, समावेशी से कंप्यूटिंग के बजाय, हम + 1 से b, समावेशी से कंप्यूटिंग कर रहे हैं। वह पुनरावर्ती कदम है - बड़ी समस्या ("योग से बी, समावेशी") को हल करने के लिए, हम समस्या को खुद के एक छोटे संस्करण में कम करते हैं ("योग + एक से 1 तक, समावेशी।")।

यदि आप ऊपर दिए गए कोड पर एक नज़र डालते हैं, तो आप देखेंगे कि इसमें यह चरण है:

return a + sumInts(a + 1, b: b)

यह कोड उपर्युक्त तर्क का एक अनुवाद है - यदि आप a से b, समावेशी में योग करना चाहते हैं, a + 1 to b, समावेशी (जो कि पुनरावर्ती कॉल sumInts करने के लिए है ) से शुरू करें, फिर जोड़ें a

बेशक, अपने आप से यह दृष्टिकोण वास्तव में काम नहीं करेगा। उदाहरण के लिए, आप 5 से 5 के बीच सभी पूर्णांकों के योग को कैसे सम्मिलित करेंगे? ठीक है, हमारे वर्तमान तर्क का उपयोग करते हुए, आप 6 और 5 के बीच सभी पूर्णांकों का योग, समावेशी की गणना करेंगे, फिर 5 जोड़ेंगे। तो आप 6 और 5 के बीच के सभी पूर्णांकों के योग को कैसे सम्मिलित करते हैं? ठीक है, हमारे वर्तमान तर्क का उपयोग करते हुए, आप 7 और 5 के बीच के सभी पूर्णांकों का योग, समावेशी की गणना करेंगे, फिर 6. जोड़ें। आपको यहाँ एक समस्या दिखाई देगी - यह सिर्फ और सिर्फ चलता रहता है!

पुनरावर्ती समस्या को हल करने में, समस्या को सरल बनाने से रोकने के लिए कुछ उपाय करने की आवश्यकता है और इसके बजाय बस इसे सीधे हल करें। आमतौर पर, आपको एक सरल मामला मिलेगा जहां उत्तर को तुरंत निर्धारित किया जा सकता है, फिर सीधे सरल मामलों को हल करने के लिए अपने समाधान की संरचना करें जब वे उत्पन्न होते हैं। इसे आम तौर पर बेस केस या पुनरावर्ती आधार कहा जाता है ।

तो इस विशेष समस्या में आधार मामला क्या है? जब आप पूर्णांक को b से, समावेशी से जोड़ते हैं, यदि ऐसा होता है, तो b से बड़ा होना है, तो इसका उत्तर है 0 - श्रेणी में कोई संख्या नहीं है! इसलिए, हम अपना समाधान इस प्रकार करेंगे:

  1. अगर a> b, तो उत्तर 0 है।
  2. अन्यथा ((b), इस प्रकार उत्तर प्राप्त करें:
    1. पूर्णांकों के योग की गणना + 1 और b के बीच करें।
    2. उत्तर पाने के लिए a जोड़ें।

अब, इस छद्मकोड की अपने वास्तविक कोड से तुलना करें:

func sumInts(a: Int, b: Int) -> Int {
    if (a > b) {
        return 0
    } else {
        return a + sumInts(a + 1, b: b)
    }
}

ध्यान दें कि स्यूडोकोड और इस वास्तविक कोड में उल्लिखित समाधान के बीच लगभग एक-से-एक नक्शा है। पहला चरण आधार मामला है - उस स्थिति में जब आप संख्याओं की एक खाली सीमा का योग पूछते हैं, आपको 0. प्राप्त होता है, + 1 और b के बीच योग की गणना करें, फिर एक जोड़ दें।

अब तक, मैंने कोड के पीछे सिर्फ एक उच्च-स्तरीय विचार दिया है। लेकिन आपके पास दो अन्य प्रश्न थे, बहुत अच्छे प्रश्न। सबसे पहले, यह हमेशा 0 क्यों नहीं लौटाता, यह देखते हुए कि फ़ंक्शन 0 को लौटाने के लिए कहता है यदि a> b? दूसरा, 14 वास्तव में कहां से आता है? आइए इन्हें बारी-बारी से देखें।

आइए, एक बहुत ही सरल मामले की कोशिश करते हैं। पुकारे तो क्या होगा sumInts(6, 5)? इस मामले में, कोड के माध्यम से ट्रेस करते हुए, आप देखते हैं कि फ़ंक्शन केवल 0. लौटाता है - यह करने के लिए सही बात है, - सीमा में कोई संख्या नहीं है। अब, कुछ कठिन प्रयास करें। जब आप कॉल करते हैं तो क्या होता है sumInts(5, 5)? खैर, यहाँ क्या होता है:

  1. तुम बुलाओ sumInts(5, 5)। हम elseशाखा में आते हैं , जो `a + sumInts (6, 5) का मान लौटाते हैं।
  2. यह sumInts(5, 5)निर्धारित करने के लिए कि sumInts(6, 5)हमें क्या करना है, हम क्या कर रहे हैं और कॉल करने की आवश्यकता है sumInts(6, 5)
  3. sumInts(6, 5)कहा जाता है। यह ifशाखा में प्रवेश करता है और लौटता है 0। हालांकि, इस उदाहरण को sumIntsइसके द्वारा कहा गया था sumInts(5, 5), इसलिए रिटर्न वैल्यू का संचार वापस किया जाता है sumInts(5, 5), न कि शीर्ष स्तर के कॉलर को।
  4. sumInts(5, 5)अब 5 + sumInts(6, 5)वापस पाने के लिए गणना कर सकते हैं 5। इसके बाद यह शीर्ष स्तर के कॉलर को वापस कर देता है।

ध्यान दें कि यहां मूल्य 5 का गठन कैसे किया गया था। हमने एक सक्रिय कॉल के साथ शुरुआत की sumInts। इसने एक और पुनरावर्ती कॉल को निकाल दिया, और उस कॉल द्वारा लौटाए गए मूल्य ने सूचना को वापस संचारित किया sumInts(5, 5)। तब कॉल sumInts(5, 5)ने बदले में कुछ गणना की और कॉल करने वाले को वापस मान दिया।

यदि आप इसके साथ प्रयास करते हैं sumInts(4, 5), तो यहां क्या होगा:

  • sumInts(4, 5)लौटने की कोशिश करता है 4 + sumInts(5, 5)। ऐसा करने के लिए, यह कॉल करता है sumInts(5, 5)
    • sumInts(5, 5)लौटने की कोशिश करता है 5 + sumInts(6, 5)। ऐसा करने के लिए, यह कॉल करता है sumInts(6, 5)
    • sumInts(6, 5)वापस 0 रिटर्न sumInts(5, 5).</li> <li>समनट (5, 5) now has a value forसमनट (6, 5) , namely 0. It then returns5 + 0 = 5` पर।
  • sumInts(4, 5)अब के लिए एक मूल्य है sumInts(5, 5), अर्थात् 5. यह फिर लौटता है 4 + 5 = 9

दूसरे शब्दों में, जो मूल्य लौटाया जाता है वह एक समय में एक मान को sumIntsजोड़कर बनता है, प्रत्येक बार किसी विशेष पुनरावर्ती कॉल द्वारा लौटाए गए मूल्य और वर्तमान मूल्य पर जोड़कर a। जब रिकर्सन बॉटम आउट हो जाता है, तो सबसे गहरी कॉल 0. लौटाती है, हालांकि, वह मान तुरंत पुनरावर्ती कॉल श्रृंखला से बाहर नहीं निकलता है; इसके बजाय, यह केवल उसके ऊपर एक परत को पुनरावर्ती कॉल करने के लिए मान वापस करता है। इस तरह, प्रत्येक पुनरावर्ती कॉल सिर्फ एक और संख्या में जुड़ती है और श्रृंखला में उच्चतर रिटर्न करती है, समग्र योग के साथ समापन होता है। एक अभ्यास के रूप में, इस बात का पता लगाने की कोशिश करें sumInts(2, 5)कि आप किस चीज से शुरुआत करना चाहते हैं।

उम्मीद है की यह मदद करेगा!


3
इस तरह के व्यापक उत्तर को साझा करने के लिए अपने व्यस्त दिन से समय निकालने के लिए धन्यवाद! यहां एक बड़ी जानकारी है, जो मुझे पुनरावर्ती कार्यों के आसपास अपना सिर लाने में मदद कर रही है और निश्चित रूप से दूसरों की मदद करेगी जो भविष्य में इस पद पर ठोकर खाते हैं। फिर से शुक्रिया आज का दिन अच्छा हो आपके लिए!
जेसन एलवुड

22

आपको यहां अब तक कुछ अच्छे उत्तर मिले हैं, लेकिन मैं एक और जोड़ूंगा जो एक अलग तरह का व्यवहार करता है।

सबसे पहले, मैंने सरल पुनरावर्ती एल्गोरिदम पर कई लेख लिखे हैं जो आपको दिलचस्प लग सकते हैं; देख

http://ericlippert.com/tag/recursion/

http://blogs.msdn.com/b/ericlippert/archive/tags/recursion/

वे सबसे नए शीर्ष क्रम में हैं, इसलिए नीचे से शुरू करें।

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

मुझे अपने फ़ंक्शन को थोड़े अधिक कॉम्पैक्ट रूप में फिर से लिखने दें; किसी विशेष भाषा में होने के नाते ऐसा मत सोचो।

s = (a, b) => a > b ? 0 : a + s(a + 1, b)

मुझे उम्मीद है कि इसका कोई अर्थ है। यदि आप सशर्त ऑपरेटर से परिचित नहीं हैं, तो यह फॉर्म का है condition ? consequence : alternativeऔर इसका अर्थ स्पष्ट हो जाएगा।

अब हम मूल्यांकन करना चाहते हैं कि s(2,5) हम ऐसा फंक्शन बॉडी के साथ कॉल की एक टेक्स्ट रिप्लेसमेंट करके करते हैं, फिर उसके aसाथ 2और उसके bसाथ 5:

s(2, 5) 
---> 2 > 5 ? 0 : 2 + s(2 + 1, 5)

अब सशर्त का मूल्यांकन करें। हम मूल रूप से प्रतिस्थापित 2 > 5करते हैं false

---> false ? 0 : 2 + s(2 + 1, 5)

अब वैकल्पिक रूप से सभी झूठी शर्तों को वैकल्पिक और सभी वास्तविक सशर्तियों को परिणाम के साथ बदलें। हम केवल झूठे सशर्त है, इसलिए हम किसी तरह से टेक्स्ट विकल्प के साथ कि अभिव्यक्ति की जगह:

---> 2 + s(2 + 1, 5)

अब, मुझे उन सभी +चिह्नों को टाइप करने के लिए सहेजने के लिए , अपने मूल्य के साथ लगातार अंकगणित की जगह ले लें। (यह एक धोखा है, लेकिन मैं सभी कोष्ठकों का ट्रैक रखना नहीं चाहता!)

---> 2 + s(3, 5)

अब सर्च-एंड-रिप्लेसमेंट, इस बार कॉल, 3फॉर aऔर 5बी के लिए बॉडी के साथ । हम कोष्ठक में कॉल के लिए प्रतिस्थापन डालेंगे:

---> 2 + (3 > 5 ? 0 : 3 + s(3 + 1, 5))

और अब हम केवल उन्हीं पाठ प्रतिस्थापन चरणों को करते रहते हैं:

---> 2 + (false ? 0 : 3 + s(3 + 1, 5))  
---> 2 + (3 + s(3 + 1, 5))                
---> 2 + (3 + s(4, 5))                     
---> 2 + (3 + (4 > 5 ? 0 : 4 + s(4 + 1, 5)))
---> 2 + (3 + (false ? 0 : 4 + s(4 + 1, 5)))
---> 2 + (3 + (4 + s(4 + 1, 5)))
---> 2 + (3 + (4 + s(5, 5)))
---> 2 + (3 + (4 + (5 > 5 ? 0 : 5 + s(5 + 1, 5))))
---> 2 + (3 + (4 + (false ? 0 : 5 + s(5 + 1, 5))))
---> 2 + (3 + (4 + (5 + s(5 + 1, 5))))
---> 2 + (3 + (4 + (5 + s(6, 5))))
---> 2 + (3 + (4 + (5 + (6 > 5 ? 0 : s(6 + 1, 5)))))
---> 2 + (3 + (4 + (5 + (true ? 0 : s(6 + 1, 5)))))
---> 2 + (3 + (4 + (5 + 0)))
---> 2 + (3 + (4 + 5))
---> 2 + (3 + 9)
---> 2 + 12
---> 14

यहाँ हमने जो कुछ भी किया, वह सीधे-सीधे पाठकीय प्रतिस्थापन था । वास्तव में मुझे "2 + 1" के लिए "3" को प्रतिस्थापित नहीं करना चाहिए और इसी तरह जब तक मुझे करना था, लेकिन शैक्षणिक रूप से इसे पढ़ना मुश्किल हो जाता।

फ़ंक्शन सक्रियण कॉल की बॉडी के साथ फ़ंक्शन कॉल को बदलने और औपचारिक मापदंडों को उनके संगत तर्कों के साथ बदलने से ज्यादा कुछ नहीं है। आपको समझदारी से लघुकोष्ठक शुरू करने के बारे में सावधान रहना होगा, लेकिन इससे अलग, यह सिर्फ पाठ प्रतिस्थापन है।

बेशक, अधिकांश भाषाएं वास्तव में पाठ प्रतिस्थापन के रूप में सक्रियण को लागू नहीं करती हैं , लेकिन तार्किक रूप से यही है।

तो फिर एक अबाधित पुनरावृत्ति क्या है? एक पुनरावृत्ति जहाँ पाठ प्रतिस्थापन नहीं रुकता है! ध्यान दें कि आखिरकार हमें एक ऐसा कदम कैसे मिला जहां sबदलने के लिए कोई और नहीं था , और हम तब अंकगणित के नियमों को लागू कर सकते थे।


अच्छा उदाहरण लेकिन यह आपके दिल को तोड़ देता है जब आप अधिक जटिल संगणना करने के लिए आगे बढ़ते हैं। उदाहरण के लिए। एक बाइनरी ट्री में आम पूर्वज ढूँढना।
कोडयोगी

11

जिस तरह से मैं आमतौर पर यह पता लगाता हूं कि आधार मामले को देखने और पीछे की ओर काम करने से एक पुनरावर्ती कार्य कैसे होता है। इस तकनीक को इस फ़ंक्शन पर लागू किया गया है।

पहला आधार मामला:

sumInts(6, 5) = 0

उसके बाद कॉल स्टैक में बस ऊपर का कॉल :

sumInts(5, 5) == 5 + sumInts(6, 5)
sumInts(5, 5) == 5 + 0
sumInts(5, 5) == 5

उसके बाद कॉल स्टैक में बस ऊपर का कॉल:

sumInts(4, 5) == 4 + sumInts(5, 5)
sumInts(4, 5) == 4 + 5
sumInts(4, 5) == 9

और इसी तरह:

sumInts(3, 5) == 3 + sumInts(4, 5)
sumInts(3, 5) == 3 + 9
sumInts(3, 5) == 12

और इसी तरह:

sumInts(2, 5) == 2 + sumInts(3, 5)
sumInts(4, 5) == 2 + 12
sumInts(4, 5) == 14

ध्यान दें कि हम अपने मूल कॉल पर फंक्शन में आ चुके हैं sumInts(2, 5) == 14

जिस क्रम में ये कॉल निष्पादित होते हैं:

sumInts(2, 5)
sumInts(3, 5)
sumInts(4, 5)
sumInts(5, 5)
sumInts(6, 5)

जिस क्रम में ये कॉल वापस आते हैं:

sumInts(6, 5)
sumInts(5, 5)
sumInts(4, 5)
sumInts(3, 5)
sumInts(2, 5)

ध्यान दें कि हम इस बारे में एक निष्कर्ष पर आए थे कि वे उस क्रम में कॉल को ट्रेस करके कैसे कार्य करते हैं


5

मैं इसे जाने दूँगा।

समीकरण + a + sumInts (a + 1, b) को निष्पादित करते हुए, मैं दिखाऊंगा कि अंतिम उत्तर 14 कैसे है।

//the sumInts function definition
func sumInts(a: Int, b: Int) -> Int {
    if (a > b) {
        return 0
    } else {
        return a + sumInts(a + 1, b)
    }
}

Given: a = 2 and b = 5

1) 2 + sumInts(2+1, 5)

2) sumInts(3, 5) = 12
   i) 3 + sumInts(3+1, 5)
   ii) 4 + sumInts(4+1, 5)
   iii) 5 + sumInts(5+1, 5)
   iv) return 0
   v) return 5 + 0
   vi) return 4 + 5
   vii) return 3 + 9

3) 2 + 12 = 14.

यदि आगे आपके कोई भी प्रश्न हों, तो हमें बताएं।

निम्नलिखित उदाहरण में पुनरावर्ती कार्यों का एक और उदाहरण यहां दिया गया है।

एक आदमी ने अभी-अभी कॉलेज की पढ़ाई की है।

टी वर्षों में समय की राशि है।

सेवानिवृत्त होने से पहले काम करने वाले वर्षों की कुल वास्तविक संख्या की गणना निम्नानुसार की जा सकती है:

public class DoIReallyWantToKnow 
{
    public int howLongDoIHaveToWork(int currentAge)
    {
      const int DESIRED_RETIREMENT_AGE = 65;
      double collectedMoney = 0.00; //remember, you just graduated college
      double neededMoneyToRetire = 1000000.00

      t = 0;
      return work(t+1);
    }

    public int work(int time)
    {
      collectedMoney = getCollectedMoney();

      if(currentAge >= DESIRED_RETIREMENT_AGE 
          && collectedMoney == neededMoneyToRetire
      {
        return time;
      }

      return work(time + 1);
    }
}

और यह सिर्फ किसी को भी उदास करने के लिए पर्याप्त होना चाहिए, योग्य। ;-P


5

प्रत्यावर्तन। कंप्यूटर विज्ञान में पुनरावर्तन परिमित ऑटोमेटा के विषय के तहत गहराई से कवर किया गया है।

अपने सरलतम रूप में यह एक आत्म संदर्भ है। उदाहरण के लिए, यह कहना कि "मेरी कार एक कार है" एक पुनरावर्ती कथन है। समस्या यह है कि बयान एक अनंत पुनरावृत्ति है कि यह कभी खत्म नहीं होगा। एक "कार" के बयान में परिभाषा यह है कि यह एक "कार" है, इसलिए इसे प्रतिस्थापित किया जा सकता है। हालांकि, कोई अंत नहीं है क्योंकि प्रतिस्थापन के मामले में, यह अभी भी "मेरी कार एक कार है" बन जाता है।

यह भिन्न हो सकता है यदि कथन "मेरी कार बेंटले है। मेरी कार नीली है।" जिस स्थिति में कार के लिए दूसरी स्थिति में प्रतिस्थापन "बेंटले" हो सकता है, जिसके परिणामस्वरूप "मेरी बेंटली नीली है"। इस प्रकार के प्रतिस्थापन को गणितीय विज्ञान में प्रसंग-मुक्त व्याकरण के माध्यम से समझाया जाता है ।

वास्तविक प्रतिस्थापन एक उत्पादन नियम है। यह देखते हुए कि स्टेटमेंट एस द्वारा दर्शाया गया है और यह कार एक वैरिएबल है जो "बेंटले" हो सकता है, इस स्टेटमेंट को रिकर्सिवली बाधित किया जा सकता है।

S -> "my"S | " "S | CS | "is"S | "blue"S | ε
C -> "bentley"

इसका निर्माण कई तरीकों से किया जा सकता है, क्योंकि प्रत्येक |साधन का कोई विकल्प होता है। Sउन विकल्पों में से किसी एक के द्वारा प्रतिस्थापित किया जा सकता है, और एस हमेशा खाली शुरू होता है। εउत्पादन को समाप्त करने का साधन। जिस प्रकार Sप्रतिस्थापित किया जा सकता है, उसी प्रकार अन्य चर (केवल एक ही है और यह C"बेंटले" का प्रतिनिधित्व करेगा)।

तो के साथ शुरू Sखाली किया जा रहा है, और साथ पहली पसंद जगह "my"S Sहो जाता है

"my"S

Sअभी भी प्रतिस्थापित किया जा सकता है क्योंकि यह एक चर का प्रतिनिधित्व करता है। हम इसे समाप्त करने के लिए "मेरा" फिर से चुन सकते हैं, या "कर सकते हैं, लेकिन हमारे मूल कथन को जारी रखना चाहते हैं। हम उस स्थान को चुनते हैं जिसका अर्थ Sहै कि उसके साथ प्रतिस्थापित किया गया है" "S

"my "S

अगला C को चुनने देता है

"my "CS

और सी केवल प्रतिस्थापन के लिए एक विकल्प है

"my bentley"S

और एस के लिए फिर से जगह

"my bentley "S

और इसी तरह "my bentley is"S, "my bentley is "S, "my bentley is blue"S, "my bentley is blue"(ε के लिए एस की जगह उत्पादन समाप्त होता है) और हम रिकर्सिवली हमारे बयान "मेरी बेंटले नीला है" का निर्माण किया है।

इन प्रस्तुतियों और प्रतिस्थापन के रूप में पुनरावृत्ति के बारे में सोचें। प्रक्रिया का प्रत्येक चरण अंतिम परिणाम देने के लिए अपने पूर्ववर्ती को बदल देता है। 2 से 5 तक पुनरावर्ती योग के सटीक उदाहरण में, आप उत्पादन के साथ समाप्त होते हैं

S -> 2 + A
A -> 3 + B
B -> 4 + C
C -> 5 + D
D -> 0

यह बन जाता है

2 + A
2 + 3 + B
2 + 3 + 4 + C
2 + 3 + 4 + 5 + D
2 + 3 + 4 + 5 + 0
14

मुझे यकीन नहीं है कि परिमित राज्य ऑटोमेटा या संदर्भ-मुक्त व्याकरण सबसे अच्छे उदाहरण हैं जो किसी को पुनरावृत्ति के बारे में कुछ पहले अंतर्ज्ञान के निर्माण में मदद कर सकते हैं। वे अच्छे उदाहरण हैं, लेकिन शायद प्रोग्रामरों के लिए थोड़ा अपरिचित है जिनकी कोई पिछली सीएस पृष्ठभूमि नहीं है।
ची

4

मुझे लगता है कि पुनरावर्ती कार्यों को समझने का सबसे अच्छा तरीका यह है कि वे पुनरावर्ती डेटा संरचनाओं को संसाधित करने के लिए बने हैं। लेकिन अपने मूल कार्य में sumInts(a: Int, b: Int)गणना रिकर्सिवली से संख्याओं का योग है कि aकरने के लिए b, यह एक पुनरावर्ती डेटा संरचना ... आइए कोशिश एक थोड़ा संशोधित संस्करण होने के लिए नहीं लगता है sumInts(a: Int, n: Int)जहां nआप कितने संख्या जोड़ देंगे है।

अब, सारांश nएक प्राकृतिक संख्या पर पुनरावर्ती है । अभी भी एक पुनरावर्ती डेटा नहीं है, है ना? अच्छी तरह से, एक प्राकृतिक संख्या को पुनर्नवा डेटा संरचना का उपयोग माना जा सकता है जो पीनो एक्सिओम्स का उपयोग करता है:

enum Natural = {
    case Zero
    case Successor(Natural)
}

तो, 0 = शून्य, 1 = सक्सेसर (शून्य), 2 = सक्सेसर (सक्सेसर (शून्य)), और इसी तरह।

एक बार जब आपके पास एक पुनरावर्ती डेटा संरचना होती है, तो आपके पास फ़ंक्शन के लिए टेम्पलेट होता है। प्रत्येक गैर-पुनरावर्ती मामले के लिए, आप सीधे मूल्य की गणना कर सकते हैं। पुनरावर्ती मामलों के लिए आप मानते हैं कि पुनरावर्ती कार्य पहले से ही काम कर रहा है और मामले की गणना करने के लिए इसका उपयोग करता है, लेकिन तर्क को डिक्रिप्ट करना। प्राकृतिक के मामले में, इसका मतलब यह है कि Succesor(n)हम इसका उपयोग करेंगे n, या इसके बजाय, nहम इसका उपयोग करेंगे n - 1

// sums n numbers beginning from a
func sumInts(a: Int, n: Int) -> Int {
    if (n == 0) {
        // non recursive case
    } else {
        // recursive case. We use sumInts(..., n - 1)
    }
}

अब पुनरावर्ती कार्य कार्यक्रम के लिए सरल है। सबसे पहले, आधार के मामले में, n=0। यदि हम कोई संख्या नहीं जोड़ना चाहते हैं तो हमें क्या लौटना चाहिए? जवाब है, निश्चित रूप से 0।

पुनरावर्ती मामले के बारे में क्या? यदि हम nसंख्याओं को जोड़ना चाहते हैं aऔर हमारे पास पहले से ही एक कार्यशील sumIntsकार्य है जो इसके लिए काम करता है n-1? ठीक है, हमें जोड़ने की जरूरत है aऔर फिर sumIntsसाथ देना है a + 1, इसलिए हम इसके साथ समाप्त होते हैं:

// sums n numbers beginning from a
func sumInts(a: Int, n: Int) -> Int {
    if (n == 0) {
        return 0
    } else {
        return a + sumInts(a + 1, n - 1)
    }
}

अच्छी बात यह है कि अब आपको निम्न स्तर की पुनरावृत्ति में सोचने की आवश्यकता नहीं है। आपको बस यह सत्यापित करने की आवश्यकता है:

  • पुनरावर्ती डेटा के आधार मामलों के लिए, यह पुनरावर्तन का उपयोग किए बिना उत्तर की गणना करता है।
  • पुनरावर्ती डेटा के पुनरावर्ती मामलों के लिए, यह विनाशकारी डेटा पर पुनरावृत्ति का उपयोग करके उत्तर की गणना करता है।

4

आपको निसान और शॉकेन के कार्यों के कार्यान्वयन में रुचि हो सकती है । लिंक्ड पीडीएफ एक मुफ्त ऑनलाइन कोर्स का हिस्सा है। यह एक वर्चुअल मशीन कार्यान्वयन के दूसरे भाग का वर्णन करता है जिसमें छात्र को वर्चुअल-मशीन-भाषा-से-मशीन-भाषा संकलक लिखना चाहिए। उनके द्वारा प्रस्तावित कार्य कार्यान्वयन पुनरावृत्ति में सक्षम है क्योंकि यह स्टैक-आधारित है।

आपको फ़ंक्शन कार्यान्वयन से परिचित कराने के लिए: निम्नलिखित वर्चुअल मशीन कोड पर विचार करें:

यहां छवि विवरण दर्ज करें

यदि स्विफ्ट इस आभासी मशीन भाषा में संकलित है, तो स्विफ्ट कोड के निम्नलिखित ब्लॉक:

mult(a: 2, b: 3) - 4

करने के लिए नीचे संकलन होगा

push constant 2  // Line 1
push constant 3  // Line 2
call mult        // Line 3
push constant 4  // Line 4
sub              // Line 5

वर्चुअल मशीन भाषा एक वैश्विक स्टैक के चारों ओर डिज़ाइन की गई है । push constant nइस वैश्विक स्टैक पर पूर्णांक को धकेलता है।

1 और 2 लाइनों को निष्पादित करने के बाद, स्टैक ऐसा दिखता है:

256:  2  // Argument 0
257:  3  // Argument 1

256और 257मेमोरी पते हैं।

call mult स्टैक पर रिटर्न लाइन नंबर (3) को धक्का देता है और फ़ंक्शन के स्थानीय चर के लिए स्थान आवंटित करता है।

256:  2  // argument 0
257:  3  // argument 1
258:  3  // return line number
259:  0  // local 0

... और यह लेबल पर जाता है function mult। अंदर कोड multनिष्पादित किया गया है। उस कोड को निष्पादित करने के परिणामस्वरूप हम 2 और 3 के उत्पाद की गणना करते हैं, जो फ़ंक्शन के 0 वें स्थानीय चर में संग्रहीत होता है।

256:  2  // argument 0
257:  3  // argument 1
258:  3  // return line number
259:  6  // local 0

returnबहु से आईएनजी से पहले , आप लाइन को नोटिस करेंगे:

push local 0  // push result

हम स्टैक पर उत्पाद को आगे बढ़ाएंगे।

256:  2  // argument 0
257:  3  // argument 1
258:  3  // return line number
259:  6  // local 0
260:  6  // product

जब हम लौटते हैं, तो निम्न होता है:

  • स्टैक पर अंतिम मान को 0 वें तर्क (इस मामले में 256) के मेमोरी पते पर पॉप करें। इसे लगाने के लिए यह सबसे सुविधाजनक जगह है।
  • 0 वें तर्क के पते पर स्टैक पर सब कुछ त्यागें।
  • गो-टू रिटर्न लाइन नंबर (इस मामले में 3) और फिर अग्रिम।

लौटने के बाद हम लाइन 4 को अंजाम देने के लिए तैयार हैं, और हमारा स्टैक इस तरह दिखता है:

256:  6  // product that we just returned

अब हम स्टैक पर 4 पुश करते हैं।

256:  6
257:  4

subवर्चुअल मशीन भाषा का एक आदिम कार्य है। यह दो तर्क लेता है और अपना परिणाम सामान्य पते में देता है: 0 वें तर्क का।

अब हमारे पास है

256:  2  // 6 - 4 = 2

अब जब आप जानते हैं कि एक फ़ंक्शन कॉल कैसे काम करता है, तो यह समझना सरल है कि पुनरावृत्ति कैसे काम करती है। कोई जादू नहीं , सिर्फ एक ढेर।

मैंने आपके sumIntsकार्य को इस आभासी मशीन भाषा में लागू किया है :

function sumInts 0     // `0` means it has no local variables.
  label IF
    push argument 0
    push argument 1
    lte              
    if-goto ELSE_CASE
    push constant 0
    return
  label ELSE_CASE
    push constant 2
    push argument 0
    push constant 1
    add
    push argument 1
    call sumInts       // Line 15
    add                // Line 16
    return             // Line 17
// End of function

अब मैं इसे कॉल करूंगा:

push constant 2
push constant 5
call sumInts           // Line 21

कोड निष्पादित करता है और हम स्टॉपिंग पॉइंट पर सभी रास्ते प्राप्त करते हैं जहां lteरिटर्न होता है false। यह वही है जो इस बिंदु पर दिखता है:

// First invocation
256:  2   // argument 0
257:  5   // argument 1
258:  21  // return line number
259:  2   // augend
// Second
260:  3   // argument 0
261:  5   // argument 1
262:  15  // return line number
263:  3   // augend
// Third
264:  4   // argument 0
265:  5   // argument 1
266:  15  // return line number
267:  4   // augend
// Fourth
268:  5   // argument 0
269:  5   // argument 1
270:  15  // return line number
271:  5   // augend
// Fifth
272:  6   // argument 0
273:  5   // argument 1
274:  15  // return line number
275:  0   // return value

अब चलो हमारी पुनरावृत्ति "खोल"। return0 और गोटो लाइन 15 और अग्रिम।

271:  5
272:  0

लाइन 16: add

271:  5

लाइन 17: return5 और गोटो लाइन 15 और अग्रिम।

267:  4
268:  5

लाइन 16: add

267:  9

लाइन 17: return9 और गोटो लाइन 15 और अग्रिम।

263:  3
264:  9

लाइन 16: add

263:  12

लाइन 17: return12 और गोटो लाइन 15 और अग्रिम।

259:  2
260:  12

लाइन 16: add

259:  14

लाइन 17: return14 और गोटो लाइन 21 और अग्रिम।

256:  14

ये लो। पुनरावृत्ति: गौरवशाली goto


4

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

मैंने http://www.htdp.org/ का अनुसरण किया , जो एक योजना ट्यूटोरियल होने के साथ-साथ वास्तुकला और डिजाइन के संदर्भ में कार्यक्रमों को डिजाइन करने के तरीके पर भी एक शानदार परिचय है।

लेकिन मूल रूप से, आपको कुछ समय निवेश करने की आवश्यकता है। पुनरावृत्ति कुछ एल्गोरिदम के 'फर्म' समझ के बिना, जैसे कि बैकट्रैकिंग, हमेशा आपको 'कठिन' या यहां तक ​​कि 'जादू' प्रतीत होगा। तो, दृढ़ रहें। :-D

मुझे आशा है इससे मदद मिलेगी और भाग्य आपका साथ दे!


3

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

पुनरावर्ती कॉल के लिए, एक ही फ़ंक्शन एक से अधिक मेमोरी-स्पेस को एक दूसरे पर ढेर कर देता है। बस इतना ही। कंप्यूटर की स्मृति में स्टैक कैसे काम करता है इसका सरल विचार आपको इस विचार के माध्यम से प्राप्त करना चाहिए कि कार्यान्वयन में कैसे पुनरावृत्ति होती है।


3

एक छोटा सा विषय, मुझे पता है, लेकिन ... Google में पुनरावृत्ति देखने का प्रयास करें ... आप उदाहरण से देखेंगे कि इसका क्या मतलब है :-)


Google के पूर्व संस्करणों ने निम्नलिखित पाठ लौटाया (स्मृति से उद्धृत):

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

पुनरावृत्ति देखें

10 सितंबर 2014 को, पुनरावृत्ति के बारे में मजाक अपडेट किया गया है:

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

क्या आपका मतलब है: पुनरावृत्ति


किसी अन्य उत्तर के लिए, इस उत्तर को देखें ।


3

एक ही काम कर रहे कई क्लोन के रूप में पुनरावृत्ति के बारे में सोचो ...

आप क्लोन [1] से पूछते हैं: "2 और 5 के बीच की संख्या"

+ clone[1]               knows that: result is 2 + "sum numbers between 3 and 5". so he asks to clone[2] to return: "sum numbers between 3 and 5"
|   + clone[2]           knows that: result is 3 + "sum numbers between 4 and 5". so he asks to clone[3] to return: "sum numbers between 4 and 5"
|   |   + clone[3]       knows that: result is 4 + "sum numbers between 5 and 5". so he asks to clone[4] to return: "sum numbers between 5 and 5"
|   |   |   + clone[4]   knows that: result is 5 + "sum numbers between 6 and 5". so he asks to clone[5] to return: "sum numbers between 6 and 5"
|   |   |   |   clone[5] knows that: he can't sum, because 6 is larger than 5. so he returns 0 as result.
|   |   |   + clone[4]   gets the result from clone[5] (=0)  and sums: 5 + 0,  returning 5
|   |   + clone[3]       gets the result from clone[4] (=5)  and sums: 4 + 5,  returning 9
|   + clone[2]           gets the result from clone[3] (=9)  and sums: 3 + 9,  returning 12
+ clone[1]               gets the result from clone[2] (=12) and sums: 2 + 12, returning 14

और voilá !!


2

ऊपर दिए गए कई उत्तर बहुत अच्छे हैं। हालांकि पुनरावृत्ति को हल करने के लिए एक उपयोगी तकनीक है, सबसे पहले हम यह जानना चाहते हैं कि हम क्या करना चाहते हैं और एक मानव के रूप में इसे हल करेंगे। उपरोक्त मामले में, हम लगातार पूर्णांक (ऊपर से संख्याओं का उपयोग करते हुए) का एक क्रम जोड़ना चाहते हैं:

2, 3, 4, 5  //adding these numbers would sum to 14

अब, ध्यान दें कि ये लाइनें भ्रमित कर रही हैं (गलत नहीं हैं, लेकिन भ्रमित हैं)।

if (a > b) {
    return 0 
}

परीक्षण क्यों a>b? और क्योंreturn 0

आइए एक मानव क्या करता है और अधिक बारीकी से प्रतिबिंबित करने के लिए कोड को बदलें

func sumInts(a: Int, b: Int) -> Int {
  if (a == b) {
    return b // When 'a equals b' I'm at the most Right integer, return it
  }
  else {
    return a + sumInts(a: a + 1, b: b)
  }
}

क्या हम इसे और भी इंसानी पसंद कर सकते हैं? हाँ! आमतौर पर हम बाएं से दाएं (2 + 3 + ...) योग करते हैं। लेकिन उपरोक्त पुनरावृत्ति दाईं से बाईं ओर (... + 4 + 5) है। इसे दर्शाने के लिए कोड बदलें (यह -थोड़ा डराने वाला हो सकता है, लेकिन ज्यादा नहीं)

func sumInts(a: Int, b: Int) -> Int {
  if (a == b) {
    return b // When I'm at the most Left integer, return it
  }
  else {
    return sumInts(a: a, b: b - 1) + b
  }
}

कुछ इस फ़ंक्शन को और अधिक भ्रामक लग सकता है क्योंकि हम 'दूर' के अंत से शुरू कर रहे हैं, लेकिन अभ्यास करने से यह स्वाभाविक लग सकता है (और यह एक और अच्छी 'सोच' तकनीक है: पुनरावृत्ति को हल करते समय 'दोनों' पक्षों की कोशिश करना)। और फिर, फ़ंक्शन दर्शाता है कि एक मानव (सबसे?) क्या करता है: सभी बाएं पूर्णांकों का योग लेता है और पूर्णांक पूर्णांक जोड़ता है।


2

मुझे समझने में कठिन समय आ रहा था तब मुझे यह ब्लॉग मिला और मैंने यह प्रश्न पहले ही देख लिया था इसलिए मैंने सोचा कि मुझे साझा करना होगा। आप इस ब्लॉग को अवश्य पढ़ें, मुझे यह अत्यंत उपयोगी लगा जो इसे स्टैक के साथ समझाता है और यहाँ तक कि यह बताता है कि स्टेप स्टेप के साथ दो रिकर्सन कैसे काम करता है। मैं आपको सबसे पहले यह समझने की सलाह देता हूं कि स्टैक कैसे काम करता है जो इसे यहां बहुत अच्छी तरह से समझाता है: यात्रा-दर-स्टैक

then now you will understand how recursion works now take a look of this post: चरण दर चरण समझें

यहां छवि विवरण दर्ज करें

इसका एक कार्यक्रम:

def hello(x):
    if x==1:
        return "op"
    else:
        u=1
        e=12
        s=hello(x-1)
        e+=1
        print(s)
        print(x)
        u+=1
    return e

hello(3)

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें


2

जब मैंने दूसरों के बारे में क्या कहना या पढ़ना बंद कर दिया और कुछ ऐसा लिखा जिसे देखकर मैं बच सकता हूं और सिर्फ लिखा हुआ कोड पढ़कर मेरे लिए समझ में आने लगा। मुझे एक समाधान के साथ एक समस्या मिली और समाधान को बिना देखे नकल करने की कोशिश की। मैंने केवल समाधान को देखा जब मैं असहाय हो गया। फिर मैं इसे डुप्लिकेट करने की कोशिश में वापस चला गया। मैंने कई समस्याओं पर फिर से किया जब तक कि मैंने अपनी समझ और समझ विकसित नहीं की कि कैसे एक पुनरावर्ती समस्या की पहचान की जाए और उसे हल किया जाए। जब मैं इस स्तर पर पहुंच गया, तो मैंने समस्याओं को बनाना और उन्हें हल करना शुरू कर दिया। इससे मुझे और मदद मिली। कभी-कभी, चीजों को केवल अपने दम पर और संघर्ष करके इसे सीखा जा सकता है; जब तक आप इसे प्राप्त नहीं करेंगे।


0

मैं आपको फाइबोनैचि श्रृंखला के उदाहरण के साथ बताता हूं, फाइबोनैचि है

t (n) = t (n - 1) + n;

अगर n = 0 तो 1

तो देखते हैं कि कैसे काम करता है, मैं बस के साथ और इतने पर बदल nदेता हूं । यह लग रहा है:t(n)n-1

t (n-1) = t (n - 2) + n + 1;

t (n-1) = t (n - 3) + n + 1 + n;

t (n-1) = t (n - 4) + n + 1 + n + 2 + n;

t (n) = t (nk) + ... + (nk-3) + (nk-2) + (nk-1) + n;

हम जानते हैं कि अगर t(0)=(n-k)को बराबरी 1तो n-k=0इसलिए n=kहम बदलने के kसाथ n:

t (n) = t (nn) + ... + (n-n + 3) + (n-n + 2) + (n-n + 1) + n;

यदि हम n-nफिर छोड़ देते हैं :

t (n) = t (0) + ... + 3 + 2 + 1 + (n-1) + n;

इतनी 3+2+1+(n-1)+nप्राकृतिक संख्या है। यह गणना करता हैΣ3+2+1+(n-1)+n = n(n+1)/2 => n²+n/2

फाइब के लिए परिणाम है: O(1 + n²) = O(n²)

पुनरावर्ती संबंध को समझने का यह सबसे अच्छा तरीका है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.