पुनरावृत्ति को समझना [बंद]


225

मुझे स्कूल में पुनरावृत्ति समझने में बड़ी परेशानी हो रही है । जब भी प्रोफेसर इसके बारे में बात कर रहे होते हैं, मैं इसे प्राप्त करने लगता हूं लेकिन जैसे ही मैं इसे अपने दम पर आजमाता हूं यह पूरी तरह से मेरे दिमाग को उड़ा देता है।

मैं पूरी रात हनोई के टावर्स को हल करने की कोशिश कर रहा था और पूरी तरह से मेरे दिमाग को उड़ा दिया। मेरी पाठ्यपुस्तक में लगभग 30 पृष्ठ केवल पुनरावृत्ति में हैं इसलिए यह बहुत उपयोगी नहीं है। क्या किसी को पुस्तकों या संसाधनों के बारे में पता है जो इस विषय को स्पष्ट करने में मदद कर सकते हैं?


200
पुनरावृत्ति को समझने के लिए, आपको पहले पुनरावृत्ति को समझना होगा।
पॉल टॉम्बलिन

40
पुनरावृत्ति: पुनरावृत्ति देखें
लोरेन Pechtel

36
@Paul: मुझे मजाक मिल रहा है, लेकिन मैंने हमेशा सोचा है कि यह तकनीकी रूप से गलत है। एल्गोरिथ्म का कारण बनने वाली आधार स्थिति कहां है? यह पुनरावृत्ति के लिए एक मूलभूत आवश्यकता है। =)
सर्जियो अकोस्टा

70
मैं इसे एक शॉट दूँगा: "पुनरावृत्ति को समझने के लिए आपको पुनरावृत्ति को समझने की आवश्यकता है, जब तक आप इसे नहीं समझते।" =)
सर्जियो अकोस्टा

91
इस सवाल यह मदद कर सकता है पर एक नज़र डालें stackoverflow.com/questions/717725/understanding-recursion
उमर Kooheji

जवाबों:


597

आप पांच फूलों से युक्त फूलदान कैसे खाली करते हैं?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर आप फूलदान को चार फूलों से खाली करते हैं।

आप चार फूलों से युक्त फूलदान कैसे खाली करते हैं?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर आप फूलदान को तीन फूलों से खाली करते हैं।

आप तीन फूलों से युक्त फूलदान कैसे खाली करते हैं?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर आप फूलदान को दो फूलों से खाली करते हैं।

आप फूलदान को दो फूलों से कैसे खाली करते हैं?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर एक फूलदान युक्त फूलदान खाली करते हैं।

आप एक फूल से युक्त फूलदान को कैसे खाली करते हैं?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर आप फूलदान खाली कर देते हैं जिसमें कोई फूल नहीं होता है।

आप फूलदान कैसे खाली करते हैं जिसमें कोई फूल नहीं है?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं, लेकिन फूलदान खाली है इसलिए आप काम कर रहे हैं।

यह दोहराव है। आइए इसे सामान्य करें:

आप एन फूल वाले फूलदान को कैसे खाली करते हैं ?

उत्तर: यदि फूलदान खाली नहीं है, तो आप एक फूल निकालते हैं और फिर आप फूलदान को N-1 फूल से खाली करते हैं।

हम्म, क्या हम उसे कोड में देख सकते हैं?

void emptyVase( int flowersInVase ) {
  if( flowersInVase > 0 ) {
   // take one flower and
    emptyVase( flowersInVase - 1 ) ;

  } else {
   // the vase is empty, nothing to do
  }
}

हम्म, हम सिर्फ एक लूप में ऐसा नहीं कर सकते थे?

क्यों, हाँ, पुनरावृत्ति को पुनरावृत्ति से बदला जा सकता है, लेकिन अक्सर पुनरावृत्ति अधिक सुरुचिपूर्ण होती है।

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

कल्पना कीजिए कि एक नोड, अपने बच्चों के अलावा, एक मूल्य, एक संख्या है, और कल्पना करें कि हम किसी पेड़ में सभी मूल्यों को योग करना चाहते हैं।

किसी एक नोड में मूल्य का योग करने के लिए, हम नोड के मूल्य को उसके बाएं बच्चे के मूल्य में, यदि कोई हो, और उसके सही बच्चे के मूल्य में, यदि कोई हो, जोड़ देंगे। अब याद रखें कि बच्चे, यदि वे अशक्त नहीं हैं, तो वे भी नोड हैं।

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

इसलिए बाएं बच्चे के बाएं बच्चे के मूल्य का योग करने के लिए, हम अपने स्वयं के बाएं बच्चे के मूल्य में, यदि कोई हो, और उसके सही बच्चे के मूल्य, यदि कोई हो, के मूल्य को जोड़ देंगे।

शायद आपने अनुमान लगाया है कि मैं इसके साथ कहाँ जा रहा हूँ, और कुछ कोड देखना चाहेंगे? ठीक है:

struct node {
  node* left;
  node* right;
  int value;
} ;

int sumNode( node* root ) {
  // if there is no tree, its sum is zero
  if( root == null ) {
    return 0 ;

  } else { // there is a tree
    return root->value + sumNode( root->left ) + sumNode( root->right ) ;
  }
}

ध्यान दें कि बच्चों को यह देखने के लिए स्पष्ट रूप से परीक्षण करने के बजाय कि क्या वे शून्य या नोड्स हैं, हम केवल शून्य नोड के लिए पुनरावर्ती फ़ंक्शन को शून्य बनाते हैं।

तो कहते हैं कि हमारे पास एक पेड़ है जो इस तरह दिखता है (संख्या मान हैं, बच्चों के लिए स्लैश बिंदु और @ का अर्थ है सूचक बिंदु शून्य करने के लिए):

     5
    / \
   4   3
  /\   /\
 2  1 @  @
/\  /\
@@  @@

यदि हम रूट पर समनोड कहते हैं (मान 5 के साथ नोड), हम वापस आ जाएंगे:

return root->value + sumNode( root->left ) + sumNode( root->right ) ;
return 5 + sumNode( node-with-value-4 ) + sumNode( node-with-value-3 ) ;

उस जगह का विस्तार करते हैं। हर जगह हम समनोड देखते हैं, हम इसे रिटर्न स्टेटमेंट के विस्तार के साथ बदल देंगे:

sumNode( node-with-value-5);
return root->value + sumNode( root->left ) + sumNode( root->right ) ;
return 5 + sumNode( node-with-value-4 ) + sumNode( node-with-value-3 ) ;

return 5 + 4 + sumNode( node-with-value-2 ) + sumNode( node-with-value-1 ) 
 + sumNode( node-with-value-3 ) ;  

return 5 + 4 
 + 2 + sumNode(null ) + sumNode( null )
 + sumNode( node-with-value-1 ) 
 + sumNode( node-with-value-3 ) ;  

return 5 + 4 
 + 2 + 0 + 0
 + sumNode( node-with-value-1 ) 
 + sumNode( node-with-value-3 ) ; 

return 5 + 4 
 + 2 + 0 + 0
 + 1 + sumNode(null ) + sumNode( null )
 + sumNode( node-with-value-3 ) ; 

return 5 + 4 
 + 2 + 0 + 0
 + 1 + 0 + 0
 + sumNode( node-with-value-3 ) ; 

return 5 + 4 
 + 2 + 0 + 0
 + 1 + 0 + 0
 + 3 + sumNode(null ) + sumNode( null ) ; 

return 5 + 4 
 + 2 + 0 + 0
 + 1 + 0 + 0
 + 3 + 0 + 0 ;

return 5 + 4 
 + 2 + 0 + 0
 + 1 + 0 + 0
 + 3 ;

return 5 + 4 
 + 2 + 0 + 0
 + 1 
 + 3  ;

return 5 + 4 
 + 2 
 + 1 
 + 3  ;

return 5 + 4 
 + 3
 + 3  ;

return 5 + 7
 + 3  ;

return 5 + 10 ;

return 15 ;

अब देखते हैं कि कैसे हमने एक समग्र टेम्पलेट के दोहराया आवेदन के रूप में विचार करके, मनमानी गहराई और "शाखा" की संरचना पर विजय प्राप्त की? हर बार हमारे समनोडे फ़ंक्शन के माध्यम से, हम केवल एक नोड का उपयोग करते हैं, यदि एक / अगर शाखा का उपयोग करते हैं, और दो साधारण रिटर्न स्टेटमेंट जो लगभग अपने विनिर्देश से सीधे, सीधे लिखे?

How to sum a node:
 If a node is null 
   its sum is zero
 otherwise 
   its sum is its value 
   plus the sum of its left child node
   plus the sum of its right child node

यही पुनरावृत्ति की शक्ति है।


ऊपर का फूलदान उदाहरण पूंछ पुनरावृत्ति का एक उदाहरण है । वह सब पूंछ पुनरावृत्ति का अर्थ है कि पुनरावर्ती कार्य में, यदि हम पुनरावर्ती होते हैं (अर्थात, यदि हम कार्य को फिर से कहते हैं), तो अंतिम कार्य हमने किया था।

पेड़ का उदाहरण पूंछ पुनरावर्ती नहीं था, क्योंकि भले ही हमने जो आखिरी काम किया था वह सही बच्चे की पुनरावृत्ति करना था, इससे पहले कि हमने किया कि हम बाएं बच्चे की पुनरावृत्ति करें।

वास्तव में, जिस क्रम में हम बच्चों को बुलाते हैं, और वर्तमान नोड के मूल्य को जोड़ते हैं वह बिल्कुल भी मायने नहीं रखता है, क्योंकि इसके अलावा सराहनीय है।

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

हमारे पेड़ के पास एक विशेष गुण होगा, कि किसी भी नोड के लिए, उसका चरित्र वर्णमाला के क्रम के बाद ( उसके वर्णानुसार) बच्चे और उसके पहले या उससे पहले का चरित्र होता है। (वर्णमाला क्रम में) उसके दाहिने बच्चे द्वारा रखा गया चरित्र।

हम जो करना चाहते हैं, वह पेड़ को वर्णमाला के क्रम में प्रिंट करना है। यह करना आसान है, पेड़ को विशेष संपत्ति दी जाती है। हम सिर्फ बाएं बच्चे को प्रिंट करते हैं, फिर नोड के चरित्र को, फिर दाएं बच्चे को।

हम सिर्फ विली-निली प्रिंट नहीं करना चाहते हैं, इसलिए हम अपने फ़ंक्शन को प्रिंट करने के लिए पास करेंगे। यह एक प्रिंट (चार) फ़ंक्शन के साथ एक वस्तु होगी; हमें इस बारे में चिंता करने की ज़रूरत नहीं है कि यह कैसे काम करता है, बस जब प्रिंट को कॉल किया जाता है, तो यह कुछ प्रिंट करेगा, कहीं।

आइए देखते हैं कि कोड में:

struct node {
  node* left;
  node* right;
  char value;
} ;

// don't worry about this code
class Printer {
  private ostream& out;
  Printer( ostream& o ) :out(o) {}
  void print( char c ) { out << c; }
}

// worry about this code
int printNode( node* root, Printer& printer ) {
  // if there is no tree, do nothing
  if( root == null ) {
    return ;

  } else { // there is a tree
    printNode( root->left, printer );
    printer.print( value );
    printNode( root->right, printer );
}

Printer printer( std::cout ) ;
node* root = makeTree() ; // this function returns a tree, somehow
printNode( root, printer );

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

अब अगर हमारा पेड़ ऐसा दिखता है:

         k
        / \
       h   n
      /\   /\
     a  j @  @
    /\ /\
    @@ i@
       /\
       @@

हम क्या छापेंगे?

From k, we go left to
  h, where we go left to
    a, where we go left to 
      null, where we do nothing and so
    we return to a, where we print 'a' and then go right to
      null, where we do nothing and so
    we return to a and are done, so
  we return to h, where we print 'h' and then go right to
    j, where we go left to
      i, where we go left to 
        null, where we do nothing and so
      we return to i, where we print 'i' and then go right to
        null, where we do nothing and so
      we return to i and are done, so
    we return to j, where we print 'j' and then go right to
      null, where we do nothing and so
    we return to j and are done, so
  we return to h and are done, so
we return to k, where we print 'k' and then go right to
  n where we go left to 
    null, where we do nothing and so
  we return to n, where we print 'n' and then go right to
    null, where we do nothing and so
  we return to n and are done, so 
we return to k and are done, so we return to the caller

इसलिए यदि हम सिर्फ उन रेखाओं को देखें जिन्हें हमने मुद्रित किया था:

    we return to a, where we print 'a' and then go right to
  we return to h, where we print 'h' and then go right to
      we return to i, where we print 'i' and then go right to
    we return to j, where we print 'j' and then go right to
we return to k, where we print 'k' and then go right to
  we return to n, where we print 'n' and then go right to

हम देखते हैं कि हम "अहीजन" मुद्रित करते हैं, जो वास्तव में वर्णमाला के क्रम में है।

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

और वह पुनरावृत्ति की शक्ति है: पूरी चीजों को करने में सक्षम केवल यह जानने के लिए कि पूरे का एक हिस्सा कैसे करना है (और जानने के लिए कि कब रोकना है)।

अधिकांश भाषाओं में, ऑपरेटर को याद करते हुए || ("या") शॉर्ट-सर्किट जब इसका पहला ऑपरेंड सच होता है, तो सामान्य पुनरावर्ती कार्य होता है:

void recurse() { doWeStop() || recurse(); } 

ल्यूक एम टिप्पणी:

एसओ को इस तरह के जवाब के लिए बिल्ला बनाना चाहिए। बधाई हो!

धन्यवाद, ल्यूक! लेकिन, वास्तव में, क्योंकि मैंने इस उत्तर को चार से अधिक बार संपादित किया (अंतिम उदाहरण को जोड़ने के लिए, लेकिन ज्यादातर टाइपो को सही करने और इसे पॉलिश करने के लिए - एक छोटे नेटबुक कीबोर्ड पर टाइप करना कठिन है), मुझे इसके लिए और अधिक अंक नहीं मिल सकते हैं । जो कुछ हद तक मुझे भविष्य के उत्तरों में उतने ही प्रयास से हतोत्साहित करता है।

मेरी टिप्पणी यहाँ उस पर देखें: /programming/128434/what-are-community-wiki-posts-in-stackoverflow/718699#718699


35

आपका मस्तिष्क उड़ गया क्योंकि यह एक अनंत पुनरावृत्ति में मिल गया। यह एक सामान्य शुरुआत की गलती है।

मानो या न मानो, आप पहले से ही पुनरावृत्ति को समझते हैं, आपको बस एक आम द्वारा घसीटा जा रहा है, लेकिन एक फ़ंक्शन के लिए दोषपूर्ण रूपक: सामान के साथ एक छोटा सा बॉक्स जो अंदर और बाहर आता है।

एक कार्य या प्रक्रिया के बजाय सोचें, जैसे "नेट पर पुनरावृत्ति के बारे में अधिक जानकारी प्राप्त करें"। यह पुनरावर्ती है और आपको इससे कोई समस्या नहीं है। इस कार्य को पूरा करने के लिए:

क) "पुनरावृत्ति" के लिए Google का परिणाम पृष्ठ पढ़ें
बी) एक बार जब आप इसे पढ़ लेते हैं, तो इस पर पहले लिंक का पालन करें और ...
a.1) उस नए पेज को रिकर्सन के बारे में पढ़ें 
b.1) एक बार जब आप इसे पढ़ लेते हैं, तो इस पर पहले लिंक का अनुसरण करें और ...
a.2) रिकर्सन के बारे में वह नया पेज पढ़ें 
b.2) एक बार जब आप इसे पढ़ लेते हैं, तो इस पर पहले लिंक का पालन करें और ...

जैसा कि आप देख सकते हैं, आप लंबे समय से बिना किसी समस्या के पुनरावर्ती सामान कर रहे हैं।

आप उस कार्य को कब तक करते रहेंगे? हमेशा के लिए जब तक आपका दिमाग न उड़ जाए? निश्चित रूप से, आप किसी दिए गए बिंदु पर नहीं रुकेंगे, जब भी आप मानते हैं कि आपने कार्य पूरा कर लिया है।

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

कंप्यूटर जैक नहीं कर सकता है, इसलिए आपको एक स्पष्ट अंत शामिल करना होगा: "नेट पर पुनरावृत्ति के बारे में अधिक जानकारी प्राप्त करें, UNTIL आपको यह समझ में आता है या आपने अधिकतम 10 पृष्ठ पढ़े हैं "।

आपने यह भी अनुमान लगाया है कि आपको "पुनरावृत्ति" के लिए Google के परिणाम पृष्ठ पर शुरू करना चाहिए, और फिर से ऐसा कुछ करना चाहिए जो कंप्यूटर नहीं कर सकता। हमारे पुनरावर्ती कार्य के पूर्ण विवरण में एक स्पष्ट प्रारंभिक बिंदु भी शामिल होना चाहिए:

"नेट पर पुनरावृत्ति के बारे में और अधिक जानकारी प्राप्त करें, UNTIL आप इसे समझें या आपने अधिकतम 10 पृष्ठ पढ़े हैं और www.google.com/search?q=recursion पर शुरू कर रहे हैं "

पूरी बात को टटोलने के लिए, मेरा सुझाव है कि आप इनमें से किसी भी पुस्तक को आजमाएँ:

  • कॉमन लिस्प: ए जेंटल इंट्रोडक्शन टू सिम्बोलिक कंपीटिशन। यह पुनरावृत्ति की सबसे प्यारी गैर-गणितीय व्याख्या है।
  • छोटे से स्कैमर।

6
"फ़ंक्शन = I / O" के छोटे बॉक्स का रूपक तब तक पुनरावृत्ति के साथ काम करता है जब तक आप यह भी कल्पना करते हैं कि वहाँ एक कारखाना है जो अनंत क्लोन बना रहा है और आपका छोटा बॉक्स अन्य छोटे बक्से को निगल सकता है।
ईपीमिएंट

2
दिलचस्प है। तो, भविष्य में रोबोट कुछ गूगल करेंगे और पहले 10 लिंक का उपयोग करके स्वयं सीखेंगे। :) :)
कुमार

2
@कुमार गूगल नहीं कर रहा है जो पहले से ही इंटरनेट के साथ है ..?
TJ

1
महान पुस्तकें, सिफारिश के लिए धन्यवाद
मैक्स कोरसेटस्की

+1 के लिए "आपका मस्तिष्क उड़ गया क्योंकि यह एक अनंत पुनरावृत्ति में मिला। यह एक सामान्य शुरुआत की गलती है।"
स्टैक अंडरफ्लो

26

पुनरावृत्ति को समझने के लिए, आपको बस अपनी शैम्पू की बोतल के लेबल पर देखना होगा:

function repeat()
{
   rinse();
   lather();
   repeat();
}

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


6
धन्यवाद dar7yl - कि हमेशा मुझे शैम्पू की बोतलों पर गुस्सा आता है। (मुझे लगता है कि मैं हमेशा प्रोग्रामिंग के लिए किस्मत में था)। हालाँकि मैंने उस आदमी को
धोखा

5
मुझे आशा है कि आप के rinse()बादlather()
CoderDennis

@JakeWilson अगर टेल-कॉल ऑप्टिमाइज़ेशन का उपयोग किया जाता है - निश्चित। हालांकि यह वर्तमान में खड़ा है, हालांकि - यह पूरी तरह से वैध पुनरावृत्ति है।

1
@ dar7yl इसीलिए मेरी शैम्पू की बोतल हमेशा खाली रहती है ...
Brandon Ling

11

यदि आप एक पुस्तक चाहते हैं जो सरल शब्दों में पुनरावृत्ति की व्याख्या करने का एक अच्छा काम करता है, तो Gödel, Escher, Bach पर एक नज़र डालें : डगलस हॉफ़स्टैटर द्वारा एक अनन्त गोल्डन ब्रैड , विशेष रूप से अध्याय 5. पुनरावृत्ति के अलावा यह समझाने का एक अच्छा काम करता है कंप्यूटर विज्ञान और गणित में कई जटिल अवधारणाओं को एक समझ में आता है, एक स्पष्टीकरण निर्माण के साथ दूसरे पर। यदि आपके पास इन प्रकार की अवधारणाओं से पहले बहुत अधिक जोखिम नहीं था, तो यह एक बहुत अच्छी पुस्तक हो सकती है।


और फिर हॉफस्टैटर की बाकी किताबों के माध्यम से घूमते हैं। इस समय मेरा पसंदीदा कविता के अनुवाद पर एक है: ले टन ब्यू डो मरोट । सीएस विषय ठीक नहीं है, लेकिन यह दिलचस्प मुद्दों को उठाता है कि अनुवाद वास्तव में क्या है और इसका क्या मतलब है।
RBerteig

9

यह एक प्रश्न से अधिक शिकायत है। क्या आपके पास पुनरावर्तन पर अधिक विशिष्ट प्रश्न है? गुणा की तरह, यह एक ऐसी चीज नहीं है जिसके बारे में लोग बहुत कुछ लिखते हैं।

गुणन की बात, इस पर विचार करें।

सवाल:

क्या एक * बी है?

उत्तर:

यदि b 1 है, तो यह एक है। अन्यथा, यह a + a (b-1) है।

* (बी -1) क्या है? इसे काम करने के तरीके के लिए उपरोक्त प्रश्न देखें।


@Andrew ग्रिम: अच्छा सवाल। यह परिभाषा प्राकृतिक संख्याओं के लिए है, पूर्णांक नहीं।
S.Lott

9

मुझे लगता है कि यह बहुत सरल विधि आपको पुनरावृत्ति को समझने में मदद करनी चाहिए। यह विधि तब तक खुद को बुलाएगी जब तक कि एक निश्चित स्थिति सही न हो और फिर वापस लौटें:

function writeNumbers( aNumber ){
 write(aNumber);
 if( aNumber > 0 ){
  writeNumbers( aNumber - 1 );
 }
 else{
  return;
 }
}

यह फ़ंक्शन आपको पहले नंबर से सभी नंबर प्रिंट कर देगा जिसे आप इसे 0. तक फ़ीड करेंगे।

writeNumbers( 10 );
//This wil write: 10 9 8 7 6 5 4 3 2 1 0
//and then stop because aNumber is no longer larger then 0

बासिकली क्या होता है कि राइटअनुसर्स (10) 10 लिखेगा और फिर राइटअनुल्स (9) कहेगा जो 9 लिखेगा और फिर राइटनंबर (8) आदि कॉल करेगा। बट राइट्स नहीं लिखेंगे (-1);

यह कोड अनिवार्य रूप से समान है:

for(i=10; i>0; i--){
 write(i);
}

फिर आप जो पुनरावृत्ति पूछ सकते हैं उसका उपयोग क्यों करें, यदि एक फॉर-लूप अनिवार्य रूप से समान है। जब आप छोरों के लिए घोंसला बनाना चाहते हैं तो आप ज्यादातर पुनरावृत्ति का उपयोग करते हैं, लेकिन यह नहीं जान पाएंगे कि वे कितने गहरे घोंसले हैं। उदाहरण के लिए, नेस्टेड सरणियों से आइटम प्रिंट करते समय:

var nestedArray = Array('Im a string', 
                        Array('Im a string nested in an array', 'me too!'),
                        'Im a string again',
                        Array('More nesting!',
                              Array('nested even more!')
                              ),
                        'Im the last string');
function printArrayItems( stringOrArray ){
 if(typeof stringOrArray === 'Array'){
   for(i=0; i<stringOrArray.length; i++){ 
     printArrayItems( stringOrArray[i] );
   }
 }
 else{
   write( stringOrArray );
 }
}

printArrayItems( stringOrArray );
//this will write:
//'Im a string' 'Im a string nested in an array' 'me too' 'Im a string again'
//'More nesting' 'Nested even more' 'Im the last string'

यह फ़ंक्शन एक ऐसा सरणी ले सकता है, जिसे 100 स्तरों में नेस्ट किया जा सकता है, जबकि आप एक लूप के लिए लिखते हैं तब आपको 100% घोंसला बनाने की आवश्यकता होगी:

for(i=0; i<nestedArray.length; i++){
 if(typeof nestedArray[i] == 'Array'){
  for(a=0; i<nestedArray[i].length; a++){
   if(typeof nestedArray[i][a] == 'Array'){
    for(b=0; b<nestedArray[i][a].length; b++){
     //This would be enough for the nestedAaray we have now, but you would have
     //to nest the for loops even more if you would nest the array another level
     write( nestedArray[i][a][b] );
    }//end for b
   }//endif typeod nestedArray[i][a] == 'Array'
   else{ write( nestedArray[i][a] ); }
  }//end for a
 }//endif typeod nestedArray[i] == 'Array'
 else{ write( nestedArray[i] ); }
}//end for i

जैसा कि आप देख सकते हैं कि पुनरावर्ती विधि बहुत बेहतर है।


1
LOL - मुझे एक दूसरा एहसास हुआ कि आप जावास्क्रिप्ट का उपयोग कर रहे हैं! मैंने "फ़ंक्शन" देखा और सोचा कि PHP तब एहसास होगा कि चर $ के साथ शुरू नहीं हुए थे। तब मैंने सोचा कि शब्द के उपयोग के लिए C # - लेकिन विधियों को फ़ंक्शन नहीं कहा जाता है!
ozzy432836

8

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


1
मैं इस जवाब से सहमत हूं। आधार (सरलतम) मामले को पहचानने और हल करने की चाल है। और फिर उस सरलतम मामले के संदर्भ में समस्या को व्यक्त करें (जो आपने पहले ही हल कर लिया है)।
सर्जियो अकोस्टा

6

मैं इसे एक उदाहरण से समझाने की कोशिश करूँगा।

तुम्हें पता है क्या n! माध्यम? यदि नहीं: http://en.wikipedia.org/wiki/Factorial

3! = 1 * 2 * 3 = 6

यहाँ कुछ स्यूडोकोड जाता है

function factorial(n) {
  if (n==0) return 1
  else return (n * factorial(n-1))
}

तो चलिए इसे आजमाते हैं:

factorial(3)

n 0 है?

नहीं!

इसलिए हम अपनी पुनरावृत्ति के साथ गहरी खुदाई करते हैं:

3 * factorial(3-1)

3-1 = 2

2 == 0 है?

नहीं!

इसलिए हम गहराई तक जाते हैं! 3 * 2 * भाज्य (2-1) 2-1 = 1

1 == 0 है?

नहीं!

इसलिए हम गहराई तक जाते हैं! 3 * 2 * 1 * भाज्य (1-1) 1-1 = 0

0 == 0 है?

हाँ!

हमारे पास एक तुच्छ मामला है

इसलिए हमारे पास 3 * 2 * 1 * 1 = 6 है

मुझे आशा है कि आपकी मदद की जाएगी


यह पुनरावृत्ति के बारे में सोचने का एक उपयोगी तरीका नहीं है। एक सामान्य गलती शुरुआती लोग यह कल्पना करने की कोशिश करते हैं कि पुनर्विचार कॉल के अंदर क्या होता है , केवल विश्वास करने / साबित करने के बजाय कि यह सही उत्तर लौटाएगा - और यह उत्तर प्रोत्साहित करता है।
श्रीवत्सआर

पुनरावर्तन को समझने का इससे बेहतर तरीका क्या होगा? मैं नहीं कहता कि आपको हर पुनरावर्ती कार्य को इस तरह देखना होगा। लेकिन इससे मुझे यह समझने में मदद मिली कि यह कैसे काम करता है।
ज़ोरान ज़रिक

1
[मैंने वोट नहीं दिया -1, BTW।] आप ऐसा सोच सकते हैं: उस फैक्टरियल (n-1) पर भरोसा करके सही तरीके से (n-1) देता है! = (N-1) * ... * 2 * 1, फिर n factorial (n-1) n * (n-1) देता है ... * 2 * 1, जो n है! जो कुछ भी। [यदि आप सीखने की कोशिश कर रहे हैं कि कैसे खुद को पुनरावर्ती कार्यों को लिखने के लिए, न कि देखें कि क्या कुछ कार्य करता है।]
श्रीवत्सआर

मैंने पुनरावृत्ति की व्याख्या करते समय factorials का उपयोग किया है, और मुझे लगता है कि सामान्य कारणों में से एक यह एक उदाहरण के रूप में विफल रहता है क्योंकि विस्फोट गणित को नापसंद करता है, और उस में पकड़ा जाता है। (कोई है कि नापसंद गणित होना चाहिए कोडिंग किया जाना चाहिए एक और सवाल है)। उस कारण से, मैं आमतौर पर गैर-गणितीय उदाहरण का उपयोग करने की कोशिश करता हूं जहां संभव हो।
टोनी मेयर

5

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

विधि ए, कॉल विधि ए कॉल विधि ए। आखिरकार इनमें से एक विधि ए कॉल और निकास नहीं होगी, लेकिन यह पुनरावृत्ति है क्योंकि कुछ स्वयं कॉल करता है।

पुनरावर्तन का उदाहरण जहां मैं हार्ड ड्राइव पर प्रत्येक फ़ोल्डर का नाम प्रिंट करना चाहता हूं: (सी # में)

public void PrintFolderNames(DirectoryInfo directory)
{
    Console.WriteLine(directory.Name);

    DirectoryInfo[] children = directory.GetDirectories();

    foreach(var child in children)
    {
        PrintFolderNames(child); // See we call ourself here...
    }
}

इस उदाहरण में आधार मामला कहां है?
कुणाल मुखर्जी

4

आप कौन सी पुस्तक का उपयोग कर रहे हैं?

एल्गोरिदम पर मानक पाठ्यपुस्तक जो वास्तव में अच्छी है, कॉर्मेन एंड रिवेस्ट है। मेरा अनुभव यह है कि यह काफी अच्छी तरह से पुनरावृत्ति सिखाता है।

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

साथ ही, सामान्य रूप से 30 पृष्ठ बहुत हैं, एक प्रोग्रामिंग भाषा में 30 पृष्ठ भ्रमित करने वाले हैं। सामान्य पुस्तक से सामान्य रूप से पुनरावृत्ति को समझने से पहले, सी या जावा में पुनरावृत्ति सीखने की कोशिश न करें।


4

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


4

http://javabat.com पुनरावृत्ति का अभ्यास करने के लिए एक मजेदार और रोमांचक जगह है। उनके उदाहरण काफी हल्के लगते हैं और व्यापक रूप से काम करते हैं (यदि आप इसे दूर तक ले जाना चाहते हैं)। नोट: उनका दृष्टिकोण अभ्यास करके सीखा जाता है। यहाँ एक पुनरावर्ती कार्य है जिसे मैंने केवल लूप के लिए बदलने के लिए लिखा था।

लूप के लिए:

public printBar(length)
{
  String holder = "";
  for (int index = 0; i < length; i++)
  {
    holder += "*"
  }
  return holder;
}

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

public String printBar(int Length) // Method, to call the recursive function
{
  printBar(length, 0);
}

public String printBar(int length, int index) //Overloaded recursive method
{
  // To get a better idea of how this works without a for loop
  // you can also replace this if/else with the for loop and
  // operationally, it should do the same thing.
  if (index >= length)
    return "";
  else
    return "*" + printBar(length, index + 1); // Make recursive call
}

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


javabat.com एक अत्यंत सहायक वेबसाइट है जो किसी को पुनरावर्ती सोचने में मदद करेगी। मैं अत्यधिक सुझाव देता हूं कि वहां जाकर और अपने दम पर पुनरावर्ती समस्याओं को हल करने का प्रयास किया जाए।
पाराडियस

3

एक पुनरावर्ती कार्य के निर्माण के लिए वास्तव में गणितीय तरीका निम्नानुसार होगा:

1: कल्पना कीजिए कि आपके पास एक फ़ंक्शन है जो f (n-1) के लिए सही है, f का निर्माण ऐसे करें कि f (n) सही हो। 2: बिल्ड f, जैसे कि f (1) सही है।

यह आप कैसे साबित कर सकते हैं कि फ़ंक्शन सही है, गणितीय रूप से है, और इसे इंडक्शन कहा जाता है । यह विभिन्न आधार मामलों, या कई चर पर अधिक जटिल कार्यों के बराबर है)। यह कल्पना करना भी बराबर है कि f (x) सभी x के लिए सही है

अब एक "सरल" उदाहरण के लिए। एक फ़ंक्शन बनाएं जो यह निर्धारित कर सकता है कि क्या एक्स सेंट बनाने के लिए 5 सेंट और 7 सेंट का एक सिक्का संयोजन करना संभव है। उदाहरण के लिए, 2x5 + 1x7 तक 17 सेंट होना संभव है, लेकिन 16 सेंट होना असंभव है।

अब कल्पना करें कि आपके पास एक फ़ंक्शन है जो आपको बताता है कि क्या x सेंट बनाना संभव है, जब तक x <n। इस फ़ंक्शन को can_create_coins_small पर कॉल करें। यह कल्पना करना काफी सरल होना चाहिए कि एन के लिए फ़ंक्शन कैसे बनाया जाए। अब अपने फ़ंक्शन का निर्माण करें:

bool can_create_coins(int n)
{
    if (n >= 7 && can_create_coins_small(n-7))
        return true;
    else if (n >= 5 && can_create_coins_small(n-5))
        return true;
    else
        return false;
}

यहाँ ट्रिक यह महसूस करने के लिए है कि यह तथ्य कि can_create_coins n के लिए काम करता है, का अर्थ है कि आप can_create_coins को can_create_coins_small, के लिए स्थानापन्न कर सकते हैं:

bool can_create_coins(int n)
{
    if (n >= 7 && can_create_coins(n-7))
        return true;
    else if (n >= 5 && can_create_coins(n-5))
        return true;
    else
        return false;
}

एक अंतिम बात अनंत पुनरावृत्ति को रोकने के लिए आधार मामला होना है। ध्यान दें कि यदि आप 0 सेंट बनाने की कोशिश कर रहे हैं, तो यह संभव है कि सिक्के न हों। इस शर्त को जोड़ने से यह मिलता है:

bool can_create_coins(int n)
{
    if (n == 0)
        return true;
    else if (n >= 7 && can_create_coins(n-7))
        return true;
    else if (n >= 5 && can_create_coins(n-5))
        return true;
    else
        return false;
}

यह सिद्ध किया जा सकता है कि अनंत वंश नामक एक विधि का उपयोग करके, यह फ़ंक्शन हमेशा वापस आ जाएगा , लेकिन यह आवश्यक नहीं है। आप कल्पना कर सकते हैं कि f (n) केवल n के कम मूल्यों को बुलाता है, और हमेशा अंततः 0 तक पहुंच जाएगा।

हनोई समस्या के अपने टॉवर को हल करने के लिए इस जानकारी का उपयोग करने के लिए, मुझे लगता है कि चाल यह मानने के लिए है कि आपके पास n-1 टैबलेट्स को बी से बी (किसी भी / बी के लिए) स्थानांतरित करने के लिए एक फ़ंक्शन है, एन टेबल को बी से स्थानांतरित करने की कोशिश कर रहा है ।


3

आम लिस्प में सरल पुनरावर्ती उदाहरण :

MYMAP सूची में प्रत्येक तत्व के लिए एक फ़ंक्शन लागू करता है।

1) एक खाली सूची में कोई तत्व नहीं है, इसलिए हम खाली सूची लौटाते हैं - () और NIL दोनों खाली सूची हैं।

2) फ़ंक्शन को पहली सूची पर लागू करें, बाकी सूची (पुनरावर्ती कॉल) के लिए MYMAP को कॉल करें और दोनों परिणामों को एक नई सूची में संयोजित करें।

(DEFUN MYMAP (FUNCTION LIST)
  (IF (NULL LIST)
      ()
      (CONS (FUNCALL FUNCTION (FIRST LIST))
            (MYMAP FUNCTION (REST LIST)))))

आइए देखते हैं निशान को अंजाम। किसी फ़ंक्शन को दर्ज करने पर, तर्क मुद्रित होते हैं। किसी फ़ंक्शन को निष्पादित करने पर, परिणाम मुद्रित होता है। प्रत्येक पुनरावर्ती कॉल के लिए, आउटपुट स्तर पर इंडेंट किया जाएगा।

यह उदाहरण प्रत्येक नंबर पर एक सूची (1 2 3 4) में SIN फ़ंक्शन को कॉल करता है।

Command: (mymap 'sin '(1 2 3 4))

1 Enter MYMAP SIN (1 2 3 4)
| 2 Enter MYMAP SIN (2 3 4)
|   3 Enter MYMAP SIN (3 4)
|   | 4 Enter MYMAP SIN (4)
|   |   5 Enter MYMAP SIN NIL
|   |   5 Exit MYMAP NIL
|   | 4 Exit MYMAP (-0.75680256)
|   3 Exit MYMAP (0.14112002 -0.75680256)
| 2 Exit MYMAP (0.9092975 0.14112002 -0.75680256)
1 Exit MYMAP (0.841471 0.9092975 0.14112002 -0.75680256)

यह हमारा परिणाम है :

(0.841471 0.9092975 0.14112002 -0.75680256)

सभी टोपी के साथ क्या? गंभीरता से, हालांकि, वे कुछ 20 साल पहले LISP में शैली से बाहर हो गए थे।
सेबेस्टियन क्रोग

खैर, मैंने लिखा है कि एक लिस्प मशीन मॉडल पर, जो अब 17 साल का है। वास्तव में मैंने श्रोता में प्रारूपण के बिना फ़ंक्शन लिखा, कुछ संपादन किया, और फिर इसे प्रारूपित करने के लिए PPRINT का उपयोग किया। इसने कोड को CAPS में बदल दिया।
रेनर जोसविग

3

छह साल की उम्र में पुनरावृत्ति को समझाने के लिए, पहले इसे पांच साल के बच्चे को समझाएं, और फिर एक साल तक प्रतीक्षा करें।

वास्तव में, यह एक उपयोगी काउंटर-उदाहरण है, क्योंकि आपके पुनरावर्ती कॉल को सरल होना चाहिए, कठिन नहीं। पांच-वर्षीय को पुनरावृत्ति की व्याख्या करना और भी कठिन होगा, और यद्यपि आप 0 पर पुनरावृत्ति को रोक सकते हैं, फिर भी आपके पास शून्य-वर्षीय व्यक्ति को पुनरावर्तन की व्याख्या करने के लिए कोई सरल उपाय नहीं है।

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

वास्तव में, यह एक पुनरावर्ती परिभाषा थी कि पुनरावृत्ति के साथ किसी समस्या को कैसे हल किया जाए।


3

उदाहरण के लिए, बच्चे पुनरावृत्ति का उपयोग करते हैं:

डिज्नी वर्ल्ड की सड़क यात्रा

क्या हम अभी तक वहाँ हैं? (नहीं)

क्या हम अभी तक वहाँ हैं? (जल्द ही)

क्या हम अभी तक वहाँ हैं? (लगभग ...)

क्या हम अभी तक वहाँ हैं (SHHHH)

क्या हम अभी तक वहां पर है?(!!!!!)

किस बिंदु पर बच्चा सो जाता है ...

यह उलटी गिनती समारोह एक सरल उदाहरण है:

function countdown()
      {
      return (arguments[0] > 0 ?
        (
        console.log(arguments[0]),countdown(arguments[0] - 1)) : 
        "done"
        );
      }
countdown(10);

सॉफ्टवेयर परियोजनाओं के लिए लागू हॉफ़स्टैटर लॉ भी प्रासंगिक है।

मानव भाषा का सार, चॉम्स्की के अनुसार, परिमित दिमाग का उत्पादन करने की क्षमता है जिसे वह असीम स्तोत्र मानता है। इसके द्वारा उनका अर्थ है कि न केवल हम जो कह सकते हैं, उस पर कोई ऊपरी सीमा नहीं है, बल्कि यह कि हमारी भाषा के वाक्यों की संख्या पर कोई ऊपरी सीमा नहीं है, किसी विशेष वाक्य के आकार की कोई ऊपरी सीमा नहीं है। चॉम्स्की ने दावा किया है कि मानव भाषा की इस रचनात्मकता के सभी मूल सिद्धांतों को समझने वाला मूलभूत उपकरण पुनरावर्तन है: एक वाक्यांश के लिए एक ही प्रकार के दूसरे वाक्यांश के अंदर पुन: व्यवस्थित करने की क्षमता। यदि मैं कहता हूं "जॉन के भाई का घर", मेरे पास एक संज्ञा है, "घर", जो एक संज्ञा वाक्यांश में होता है, "भाई का घर", और वह संज्ञा वाक्यांश दूसरे संज्ञा वाक्यांश में होता है, "जॉन के भाई का घर"। यह बहुत मायने रखता है, और यह '

संदर्भ


2

पुनरावर्ती समाधानों के साथ काम करते समय, मैं हमेशा कोशिश करता हूं:

  • तथ्यात्मक समाधान में, आधार मामले को पहले यानी जब n = 1 स्थापित करें
  • हर दूसरे मामले के लिए एक सामान्य नियम के साथ आने की कोशिश करें

इसके अलावा विभिन्न प्रकार के पुनरावर्ती समाधान हैं, विभाजन और विजय दृष्टिकोण है जो भग्न और कई अन्य लोगों के लिए उपयोगी है।

यह भी मदद करेगा यदि आप पहले सरल समस्याओं पर काम कर सकते हैं तो बस इसे लटकाओ। कुछ उदाहरण तथ्य के लिए हल कर रहे हैं और nth रिट्रेसमेंट नंबर जेनरेट कर रहे हैं।

संदर्भ के लिए, मैं रॉबर्ट सिडगविक द्वारा एल्गोरिदम की अत्यधिक अनुशंसा करता हूं।

उम्मीद है की वो मदद करदे। सौभाग्य।


मुझे आश्चर्य है कि अगर पहले एक सामान्य नियम के साथ आना बेहतर नहीं है, तो पुनरावर्ती कॉल, जो "सरल" है, जो कि इसके साथ शुरू हुआ है। फिर आधार मामला स्पष्ट हो जाना चाहिए जो सबसे सरल मामला है। यही कारण है कि मैं एक समस्या को पुनरावर्ती रूप से हल करने के बारे में सोचने के लिए हूं।
dlaliberte

2

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


1

एक पुनरावर्ती कार्य एक वसंत की तरह है जिसे आप प्रत्येक कॉल पर थोड़ा संकुचित करते हैं। प्रत्येक चरण पर, आप एक ढेर पर थोड़ी जानकारी (वर्तमान संदर्भ) डालते हैं। जब अंतिम चरण पर पहुंच जाता है, तो एक बार में सभी मूल्यों (संदर्भों) को इकट्ठा करते हुए, वसंत जारी किया जाता है!

यकीन नहीं होता कि यह रूपक प्रभावी है ... :-)

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

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

यह निश्चित नहीं है कि मैं बहुत स्पष्ट हूं, लेकिन मैं शिक्षण सामग्री का वास्तविक विश्व उपयोग करना पसंद करता हूं, क्योंकि यह कुछ ऐसा था जिसे मैं अतीत में ठोकर खा रहा था।


1

एक कार्यकर्ता मधुमक्खी सोचो। यह शहद बनाने की कोशिश करता है। यह अपना काम करता है और अन्य श्रमिकों मधुमक्खियों से शहद बनाने की उम्मीद करता है। और जब मधुकोश भर जाता है, तो वह रुक जाता है।

इसे जादू समझो। आपके पास एक फ़ंक्शन है जिसका नाम उसी के साथ है जिसे आप कार्यान्वित करने का प्रयास कर रहे हैं और जब आप इसे सबप्रॉब्लम देते हैं, तो यह आपके लिए हल करता है और केवल एक चीज जो आपको करने की आवश्यकता है वह है समाधान के साथ अपने हिस्से के समाधान को एकीकृत करना आपको दिया।

उदाहरण के लिए, हम किसी सूची की लंबाई की गणना करना चाहते हैं। हमारे फ़ंक्शन को जादुई_लिफ्ट और हमारे जादुई सहायक को जादुई_लिफ्ट के साथ बताता है। हम जानते हैं कि यदि हम सबलिस्ट देते हैं, जिसमें पहला तत्व नहीं है, तो यह हमें जादू द्वारा सबलिस्ट की लंबाई देगा। फिर केवल एक चीज हमें सोचने की ज़रूरत है कि इस जानकारी को अपनी नौकरी के साथ कैसे एकीकृत किया जाए। पहले तत्व की लंबाई 1 है और मैजिक_काउंटर हमें सब-लिस्ट n-1 की लंबाई देता है, इसलिए कुल लंबाई (n-1) + 1 -> n है

int magical_length( list )
  sublist = rest_of_the_list( list )
  sublist_length = magical_length( sublist ) // you can think this function as magical and given to you
  return 1 + sublist_length

हालाँकि यह जवाब अधूरा है क्योंकि हमने विचार नहीं किया कि क्या होता है अगर हम एक खाली सूची देते हैं। हमने सोचा था कि हमारे पास मौजूद सूची में हमेशा कम से कम एक तत्व होता है। इसलिए हमें यह सोचने की आवश्यकता है कि यदि हमें एक खाली सूची दी जाए तो उत्तर क्या होना चाहिए और इसका उत्तर स्पष्ट रूप से है। इसलिए इस जानकारी को अपने कार्य में जोड़ें और इसे आधार / एज कंडीशन कहा जाता है।

int magical_length( list )
  if ( list is empty) then
    return 0
  else
    sublist_length = magical_length( sublist ) // you can think this function as magical and given to you
    return 1 + sublist_length
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.