पुनरावृत्ति क्या है और मुझे इसका उपयोग कब करना चाहिए?


121

मेलिंग सूचियों और ऑनलाइन चर्चाओं पर नियमित रूप से आने वाले विषयों में से एक कंप्यूटर साइंस डिग्री करने का गुण (या इसके अभाव) है। नकारात्मक पक्ष के लिए बार-बार आने वाला एक तर्क यह है कि वे कुछ वर्षों से कोडिंग कर रहे हैं और उन्होंने कभी भी पुनरावृत्ति का उपयोग नहीं किया है।

तो सवाल यह है:

  1. पुनरावृत्ति क्या है?
  2. मैं पुनरावर्तन का उपयोग कब करूंगा?
  3. लोग पुनरावृत्ति का उपयोग क्यों नहीं करते हैं?

9
और शायद यह मदद करता है: stackoverflow.com/questions/126756/…
kennytm

3
यह अवधारणा को समझने में मदद कर सकता है: इस पृष्ठ पर प्रश्न की दूसरी टिप्पणी पर दिए गए लिंक पर नेविगेट करें और टिप्पणी क्या करने के लिए कहते हैं: stackoverflow.com/questions/3021/…
dtmland

जवाबों:


86

का अच्छा स्पष्टीकरण की एक संख्या हैं प्रत्यावर्तन इस सूत्र में, इस सवाल का जवाब (तुम क्यों यह सबसे अधिक भाषाओं में उपयोग नहीं करना चाहिए के बारे में है। * प्रमुख अनिवार्य भाषा कार्यान्वयन के बहुमत में यानी सी, सी ++, बेसिक, अजगर के हर प्रमुख कार्यान्वयन , रूबी, जावा, और C #) पुनरावृत्ति के लिए पुनरावृत्ति काफी हद तक बेहतर है।

यह देखने के लिए कि, उपरोक्त फ़ंक्शन उन फ़ंक्शन के माध्यम से चलते हैं जो एक फ़ंक्शन को कॉल करने के लिए उपयोग करते हैं:

  1. समारोह के तर्कों और स्थानीय चरों के लिए स्टैक पर जगह खुदी हुई है
  2. फ़ंक्शन के तर्कों को इस नए स्थान में कॉपी किया जाता है
  3. नियंत्रण समारोह में कूदता है
  4. फ़ंक्शन का कोड चलता है
  5. फ़ंक्शन के परिणाम को एक रिटर्न मान में कॉपी किया जाता है
  6. स्टैक अपने पिछले स्थान पर फिर से दिख रहा है
  7. नियंत्रण कूदता है जहां फ़ंक्शन को बुलाया गया था

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

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

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

* मुझे प्यार है। मेरी पसंदीदा स्थिर भाषा में छोरों का उपयोग नहीं किया गया है, पुनरावृत्ति बार-बार कुछ करने का एकमात्र तरीका है। मुझे नहीं लगता कि पुनरावृत्ति आम तौर पर उन भाषाओं में एक अच्छा विचार है जो इसके लिए तैयार नहीं हैं।

** वैसे मारियो, आपके अरेंजस्ट्रीमिंग फंक्शन का विशिष्ट नाम "जॉइन" है, और मुझे आश्चर्य होगा अगर आपकी पसंद की भाषा पहले से ही इसे लागू नहीं करती है।


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

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

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

63

पुनरावृत्ति का सरल अंग्रेजी उदाहरण।

A child couldn't sleep, so her mother told her a story about a little frog,
    who couldn't sleep, so the frog's mother told her a story about a little bear,
         who couldn't sleep, so the bear's mother told her a story about a little weasel... 
            who fell asleep.
         ...and the little bear fell asleep;
    ...and the little frog fell asleep;
...and the child fell asleep.

1
ऊपर + दिल को छूने के लिए :)
सुहैल मुमताज़ अवन

कुछ ऐसी ही कहानी है छोटे बच्चों के लिए जो चीनी लोक कथाओं में सोए हुए नहीं होंगे, मुझे बस यही याद था, और यह याद दिलाता है कि असली दुनिया कैसे काम करती है।
हार्वे लिन

49

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

struct Node {
    Node* next;
};

और आप यह पता लगाना चाहते हैं कि आप कितनी लंबी सूची से जुड़े हैं, आप इसे पुनरावृत्ति के साथ कर सकते हैं:

int length(const Node* list) {
    if (!list->next) {
        return 1;
    } else {
        return 1 + length(list->next);
    }
}

(यह बेशक लूप के साथ किया जा सकता है, लेकिन अवधारणा के दृष्टांत के रूप में उपयोगी है)


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

2
क्या आपको वास्तव में यहाँ एक और कथन की आवश्यकता है?
एड्रिएन बी

1
नहीं, यह केवल स्पष्टता के लिए है।
एंड्रियास ब्रिंक

@SteveWortham: यह पूंछ-जैसा लिखा नहीं गया है; length(list->next)अभी भी लौटने की जरूरत है length(list)ताकि उत्तरार्द्ध परिणाम में 1 जोड़ सके। क्या यह लंबाई-दूर तक साथ-साथ गुजरने के लिए लिखा गया था, तभी हम कॉल करने वाले को भूल सकते थे। की तरह int length(const Node* list, int count=0) { return (!list) ? count : length(list->next, count + 1); }
cHao

46

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

सबसे सरल उदाहरण पूंछ पुनरावृत्ति है जहां फ़ंक्शन की बहुत अंतिम पंक्ति अपने आप में एक कॉल है:

int FloorByTen(int num)
{
    if (num % 10 == 0)
        return num;
    else
        return FloorByTen(num-1);
}

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

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

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

आप पुनरावृत्ति के साथ उन लोगों में से एक को आकर्षित कर सकते हैं, जहां 3 दिशाओं में कॉल स्टैक शाखाएं हैं:

private void BuildVertices(double x, double y, double len)
{
    if (len > 0.002)
    {
        mesh.Positions.Add(new Point3D(x, y + len, -len));
        mesh.Positions.Add(new Point3D(x - len, y - len, -len));
        mesh.Positions.Add(new Point3D(x + len, y - len, -len));
        len *= 0.5;
        BuildVertices(x, y + len, len);
        BuildVertices(x - len, y - len, len);
        BuildVertices(x + len, y - len, len);
    }
}

यदि आप इसे पुनरावृत्ति के साथ करने का प्रयास करते हैं तो मुझे लगता है कि आप पाएंगे कि इसे पूरा करने के लिए बहुत अधिक कोड लगता है।

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

निष्कर्ष

व्यावहारिक रूप से, पुनरावृत्ति सबसे अधिक समझ में आता है जब भी आपको पुनरावृत्ति शाखा की आवश्यकता होती है।


27

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

विहित उदाहरण एन के फैक्टरियल उत्पन्न करने के लिए एक दिनचर्या है। N की फैक्टर मेमोरी की गणना 1 और n के बीच की सभी संख्याओं को गुणा करके की जाती है। C # में एक पुनरावृत्ति समाधान इस तरह दिखता है:

public int Fact(int n)
{
  int fact = 1;

  for( int i = 2; i <= n; i++)
  {
    fact = fact * i;
  }

  return fact;
}

पुनरावृत्ति समाधान के बारे में कुछ भी आश्चर्यजनक नहीं है और इसे C # से परिचित किसी भी व्यक्ति को समझाना चाहिए।

पुनरावर्ती समाधान यह पहचान कर पाया जाता है कि nth Factorial n * Fact (n-1) है। या इसे दूसरे तरीके से रखने के लिए, यदि आप जानते हैं कि एक विशेष तथ्य संख्या क्या है तो आप अगले की गणना कर सकते हैं। यहाँ C # में पुनरावर्ती समाधान है:

public int FactRec(int n)
{
  if( n < 2 )
  {
    return 1;
  }

  return n * FactRec( n - 1 );
}

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

जब पहली बार सामना किया गया तो यह भ्रामक हो सकता है इसलिए यह जांचने के लिए शिक्षाप्रद है कि जब यह चलता है तो यह कैसे काम करता है। कल्पना कीजिए कि हम FactRec (5) कहते हैं। हम दिनचर्या में प्रवेश करते हैं, बेस केस द्वारा नहीं उठाए जाते हैं और इसलिए हम इस तरह से समाप्त होते हैं:

// In FactRec(5)
return 5 * FactRec( 5 - 1 );

// which is
return 5 * FactRec(4);

यदि हम पैरामीटर 4 के साथ विधि को फिर से दर्ज करते हैं तो हम फिर से गार्ड क्लॉज द्वारा बंद नहीं किए जाते हैं और इसलिए हम यहां समाप्त होते हैं:

// In FactRec(4)
return 4 * FactRec(3);

यदि हम इस रिटर्न वैल्यू को बदले में रिटर्न वैल्यू में बदल देते हैं

// In FactRec(5)
return 5 * (4 * FactRec(3));

यह आपको एक सुराग देना चाहिए कि अंतिम समाधान कैसे आता है इसलिए हम तेजी से ट्रैक करेंगे और प्रत्येक कदम को नीचे दिखाएंगे:

return 5 * (4 * FactRec(3));
return 5 * (4 * (3 * FactRec(2)));
return 5 * (4 * (3 * (2 * FactRec(1))));
return 5 * (4 * (3 * (2 * (1))));

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

यह ध्यान रखें कि विधि में प्रत्येक कॉल या तो आधार मामले को ट्रिगर करता है या उसी विधि को कॉल करता है जहां पैरामीटर आधार मामले के करीब हैं (अक्सर पुनरावर्ती कॉल कहा जाता है)। यदि ऐसा नहीं होता है, तो विधि हमेशा के लिए चलेगी।


2
अच्छी व्याख्या, लेकिन मुझे लगता है कि यह ध्यान रखना महत्वपूर्ण है कि यह केवल पूंछ पुनरावृत्ति है और पुनरावृत्ति समाधान पर कोई लाभ नहीं देता है। यह कोड की लगभग समान मात्रा है, और फ़ंक्शन कॉल ओवरहेड के कारण धीमी गति से चलेगी।
स्टीव वॉर्थम

1
@SteveWortham: यह पूंछ पुनरावृत्ति नहीं है। पुनरावर्ती चरण में, लौटने FactRec()से nपहले परिणाम को गुणा करना पड़ता है ।
रवि जांग

12

रिकर्सन एक फ़ंक्शन को हल करने वाली समस्या को हल कर रहा है। इसका एक अच्छा उदाहरण एक तथ्यात्मक कार्य है। Factorial एक गणित की समस्या है जहाँ 5 का भाज्य उदाहरण के लिए, 5 * 4 * 3 * 2 * 1. है। यह फ़ंक्शन C # में सकारात्मक पूर्णांक के लिए हल करता है (परीक्षण नहीं किया गया - कोई बग हो सकता है)।

public int Factorial(int n)
{
    if (n <= 1)
        return 1;

    return n * Factorial(n - 1);
}

9

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

उदाहरण के लिए, संख्या के लिए एक भाज्य की गणना करने के लिए X, कोई भी इसका प्रतिनिधित्व कर सकता है X times the factorial of X-1। इस प्रकार, विधि "फैक्टर्स" को ढूंढती है X-1, और फिर इसे Xअंतिम उत्तर देने के लिए जो भी मिला उसे गुणा करती है । बेशक, के factorial को खोजने के लिए X-1, यह पहले के factorial की गणना करेंगे X-2, और इसी तरह। आधार मामला होगा जब X0 या 1 है, ऐसी स्थिति में इसे वापस करने के लिए जानता है 1के बाद से 0! = 1! = 1


1
मुझे लगता है कि तुम क्या करने के लिए कर रहे हैं refereing प्रत्यावर्तन लेकिन <a href=" en.wikipedia.org/wiki/... और Conquer</a> नहीं है एल्गोरिथ्म डिजाइन सिद्धांत। <A href = "में उदाहरण के लिए देखो en.wikipedia। org / wiki / Ackermann_function "> एकरमैन फंक्शन </a>।
गैब्रियल erčerbák

2
नहीं, मैं डी एंड सी का जिक्र नहीं कर रहा हूं। D & C का तात्पर्य है कि 2 या अधिक उप-प्रजातियां मौजूद हैं, स्वयं द्वारा पुनरावृत्ति नहीं होती है (उदाहरण के लिए, यहाँ दिया गया तथ्यात्मक उदाहरण D & C नहीं है - यह पूरी तरह से रैखिक है)। डी एंड सी अनिवार्य रूप से पुनरावृत्ति का सबसेट है।
अंबर

3
सटीक लेख से उद्धृत आप लिंक किए गए: "एक फूट डालो और जीत एल्गोरिथ्म काम करता है द्वारा रिकर्सिवली में एक समस्या टूट दो या अधिक उप-समस्याओं को एक ही (या संबंधित) प्रकार की,"
एम्बर

मुझे नहीं लगता कि यह एक महान विवरण है, क्योंकि पुनरावृत्ति सख्ती से बोलने से समस्या को हल करने की आवश्यकता नहीं है। आप बस खुद को बुला सकते हैं (और अतिप्रवाह)।
यूके-एएल

मैं एक लेख में आपके स्पष्टीकरण का उपयोग कर रहा हूं जो मैं PHP मास्टर के लिए लिख रहा हूं, हालांकि मैं इसे आपके लिए विशेषता नहीं बना सकता। आशा है कि आप बुरा नहीं मानेंगे
13:30

9

एक पुरानी, ​​अच्छी तरह से ज्ञात समस्या पर विचार करें :

गणित में, दो या अधिक गैर-शून्य पूर्णांक का सबसे बड़ा सामान्य भाजक (gcd) ... सबसे बड़ा धनात्मक पूर्णांक है जो शेष संख्या के बिना संख्याओं को विभाजित करता है।

Gcd की परिभाषा आश्चर्यजनक रूप से सरल है:

gcd परिभाषा

जहां mod modoo ऑपरेटर है (जो पूर्णांक विभाजन के बाद शेष है)।

अंग्रेजी में, इस परिभाषा किसी भी संख्या का सबसे बड़ा आम भाजक कहते हैं और शून्य कि संख्या, और दो संख्याओं का सबसे बड़ा आम भाजक है हूँ और एन की सबसे बड़ा आम भाजक है n और विभाजित करने के बाद शेष मीटर से n

यदि आप जानना चाहते हैं कि यह क्यों काम करता है, तो यूक्लिडियन एल्गोरिथ्म पर विकिपीडिया लेख देखें ।

उदाहरण के तौर पर gcd (10, 8) की गणना करते हैं। प्रत्येक चरण इसके ठीक पहले वाले के बराबर है:

  1. gcd (10, 8)
  2. gcd (10, 10 mod 8)
  3. gcd (8, 2)
  4. gcd (8, 8 मॉड 2)
  5. gcd (2, 0)
  6. 2

पहले चरण में, 8 शून्य के बराबर नहीं है, इसलिए परिभाषा का दूसरा भाग लागू होता है। 10 मॉड 8 = 2 क्योंकि 8 2 के शेष के साथ एक बार 10 में चला जाता है। चरण 3 में, दूसरा भाग फिर से लागू होता है, लेकिन इस बार 8 मॉड 2 = 0 क्योंकि 2 8 शेष के साथ विभाजित करता है। चरण 5 पर, दूसरा तर्क 0 है, इसलिए उत्तर 2 है।

क्या आपने देखा कि समान चिह्न के बाएँ और दाएँ दोनों तरफ gcd दिखाई देता है? एक गणितज्ञ यह कहेगा कि यह परिभाषा पुनरावर्ती है क्योंकि आप अपनी परिभाषा के अंदर पुनरावृत्ति को परिभाषित कर रहे हैं ।

पुनरावर्ती परिभाषाएँ सुरुचिपूर्ण होती हैं। उदाहरण के लिए, किसी सूची के योग के लिए एक पुनरावर्ती परिभाषा है

sum l =
    if empty(l)
        return 0
    else
        return head(l) + sum(tail(l))

जहां headएक सूची में पहला तत्व tailहै और बाकी सूची में है। ध्यान दें कि sumअंत में इसकी परिभाषा के अंदर पुनरावृत्ति होती है।

शायद आप इसके बजाय किसी सूची में अधिकतम मूल्य पसंद करेंगे:

max l =
    if empty(l)
        error
    elsif length(l) = 1
        return head(l)
    else
        tailmax = max(tail(l))
        if head(l) > tailmax
            return head(l)
        else
            return tailmax

आप गैर-ऋणात्मक पूर्णांकों के गुणन को पुनरावर्ती रूप से परिवर्धन की श्रृंखला में बदलने के लिए परिभाषित कर सकते हैं:

a * b =
    if b = 0
        return 0
    else
        return a + (a * (b - 1))

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

मर्ज सॉर्ट की एक सुंदर पुनरावर्ती परिभाषा है:

sort(l) =
    if empty(l) or length(l) = 1
        return l
    else
        (left,right) = split l
        return merge(sort(left), sort(right))

पुनरावर्ती परिभाषाएँ चारों ओर हैं यदि आप जानते हैं कि क्या देखना है। ध्यान दें कि इन सभी परिभाषाओं में बहुत सरल आधार मामले हैं, उदाहरण के लिए , जीडीसी (एम, 0) = एम। पुनरावर्ती मामले आसान जवाब के लिए नीचे उतरने के लिए समस्या को दूर कर देते हैं।

इस समझ के साथ, आप अब पुनरावर्तन पर विकिपीडिया के लेख में अन्य एल्गोरिदम की सराहना कर सकते हैं !


8
  1. एक फ़ंक्शन जो स्वयं को कॉल करता है
  2. जब कोई फ़ंक्शन (आसानी से) एक साधारण ऑपरेशन में विघटित हो सकता है और समस्या के कुछ छोटे हिस्से पर समान कार्य कर सकता है। मुझे कहना चाहिए, बल्कि, कि यह इसे पुनरावृत्ति के लिए एक अच्छा उम्मीदवार बनाता है।
  3. वे करते हैं!

विहित उदाहरण गुट है जो दिखता है:

int fact(int a) 
{
  if(a==1)
    return 1;

  return a*fact(a-1);
}

सामान्य तौर पर, पुनरावृत्ति आवश्यक रूप से तेज़ नहीं होती है (फ़ंक्शन कॉल ओवरहेड उच्च हो जाता है क्योंकि पुनरावर्ती कार्य छोटे होते हैं, ऊपर देखें) और कुछ समस्याओं (किसी को भी ढेर कर सकते हैं?) से पीड़ित हो सकते हैं। कुछ लोग कहते हैं कि वे गैर-तुच्छ मामलों में 'सही' होने के लिए कठिन होते हैं, लेकिन मैं वास्तव में नहीं खरीदता। कुछ स्थितियों में, पुनरावृत्ति सबसे अधिक समझ में आता है और किसी विशेष कार्य को लिखने का सबसे सुंदर और स्पष्ट तरीका है। यह ध्यान दिया जाना चाहिए कि कुछ भाषाएं पुनरावर्ती समाधानों का पक्ष लेती हैं और उन्हें बहुत अधिक अनुकूलित करती हैं (LISP दिमाग में आता है)।


6

एक पुनरावर्ती फ़ंक्शन वह है जो स्वयं कॉल करता है। इसका उपयोग करने के लिए मैंने जो सबसे आम कारण पाया है, वह है पेड़ की संरचना का पता लगाना। उदाहरण के लिए, यदि मेरे पास चेकबॉक्स के साथ एक ट्री व्यू है (एक नए प्रोग्राम की स्थापना के बारे में सोचें, "पृष्ठ स्थापित करने के लिए सुविधाओं का चयन करें), तो मैं" चेक ऑल "बटन चाहता हूं, जो कुछ इस तरह होगा (छद्मकोश):

function cmdCheckAllClick {
    checkRecursively(TreeView1.RootNode);
}

function checkRecursively(Node n) {
    n.Checked = True;
    foreach ( n.Children as child ) {
        checkRecursively(child);
    }
}

तो आप देख सकते हैं कि checkRecursively पहले नोड को चेक करता है जो इसे पारित किया जाता है, फिर उस नोड के प्रत्येक बच्चे के लिए खुद को कॉल करता है।

आपको पुनरावृत्ति के साथ थोड़ा सावधान रहने की आवश्यकता है। यदि आप एक अनंत पुनरावर्ती लूप में आते हैं, तो आपको एक स्टैक ओवरफ्लो अपवाद मिलेगा :)

मैं एक कारण नहीं सोच सकता कि लोग इसका उपयोग क्यों न करें, जब उचित हो। यह कुछ परिस्थितियों में उपयोगी है, और दूसरों में नहीं।

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


5

पुनरावृत्ति प्रत्यक्ष या परोक्ष रूप से स्वयं को संदर्भित करने वाली एक अभिव्यक्ति है।

एक सरल उदाहरण के रूप में पुनरावर्ती कथनों पर विचार करें:

  • GNU का अर्थ है GNU का नॉट यूनिक्स
  • PHP का अर्थ है PHP: Hypertext Preprocessor
  • YAML का मतलब है YAML Ain't Markup Language
  • वाइन का मतलब वाइन एम्यूलेटर नहीं है
  • VISA का अर्थ है वीज़ा इंटरनेशनल सर्विस एसोसिएशन

विकिपीडिया पर अधिक उदाहरण


4

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

लोग कई कारणों से पुनरावृत्ति से बचते हैं:

  1. अधिकांश लोग (स्वयं शामिल) कार्यात्मक प्रोग्रामिंग के विपरीत प्रक्रियात्मक या वस्तु-उन्मुख प्रोग्रामिंग पर अपने प्रोग्रामिंग दांत काटते हैं। ऐसे लोगों के लिए, पुनरावृत्त दृष्टिकोण (आमतौर पर लूप का उपयोग करना) अधिक प्राकृतिक लगता है।

  2. हममें से जो हमारे प्रोग्रामिंग दांतों को प्रक्रियात्मक या ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग पर काटते हैं, उन्हें अक्सर पुनरावृत्ति से बचने के लिए कहा जाता है क्योंकि यह त्रुटि प्रवण है।

  3. हमें अक्सर बताया जाता है कि पुनरावृत्ति धीमा है। एक रूटीन से बार-बार कॉल करने और लौटने पर ढेर सारा स्टैकिंग और पॉपिंग होता है, जो लूपिंग की तुलना में धीमा होता है। मुझे लगता है कि कुछ भाषाएं दूसरों की तुलना में इसे बेहतर तरीके से संभालती हैं, और उन भाषाओं को सबसे अधिक संभावना नहीं है जहां प्रमुख प्रतिमान प्रक्रियात्मक या वस्तु-उन्मुख है।

  4. कम से कम प्रोग्रामिंग भाषाओं के एक जोड़े के लिए, मैंने इस्तेमाल किया है, मुझे याद है कि अगर यह एक निश्चित गहराई से परे नहीं है तो रिकर्सन का उपयोग करने की सिफारिशें सुननी पड़ती हैं।


4

एक पुनरावर्ती कथन वह है जिसमें आप इनपुट के संयोजन के रूप में आगे की प्रक्रिया को परिभाषित करते हैं और आपने पहले से ही क्या किया है।

उदाहरण के लिए, तथ्यात्मक को लें:

factorial(6) = 6*5*4*3*2*1

लेकिन यह वास्तव में देखने के लिए आसान है (6) भी है:

6 * factorial(5) = 6*(5*4*3*2*1).

तो आम तौर पर:

factorial(n) = n*factorial(n-1)

बेशक, पुनरावृत्ति के बारे में मुश्किल बात यह है कि यदि आप चीजों को परिभाषित करना चाहते हैं कि आपने पहले से क्या किया है, तो शुरू करने के लिए कुछ जगह होनी चाहिए।

इस उदाहरण में, हम सिर्फ फैक्टरियल (1) = 1 को परिभाषित करके एक विशेष केस बनाते हैं।

अब हम इसे नीचे से ऊपर की ओर देखते हैं:

factorial(6) = 6*factorial(5)
                   = 6*5*factorial(4)
                   = 6*5*4*factorial(3) = 6*5*4*3*factorial(2) = 6*5*4*3*2*factorial(1) = 6*5*4*3*2*1

चूंकि हमने फैक्टरियल (1) = 1 को परिभाषित किया है, हम "नीचे" तक पहुंचते हैं।

सामान्यतया, पुनरावर्ती प्रक्रियाओं के दो भाग होते हैं:

1) पुनरावर्ती भाग, जो नई प्रक्रियाओं के संदर्भ में कुछ प्रक्रिया को परिभाषित करता है जो एक ही प्रक्रिया के माध्यम से आपने "पहले से ही" किया है। (यानी factorial(n) = n*factorial(n-1))

2) एक आधार भाग, जो यह सुनिश्चित करता है कि प्रक्रिया हमेशा के लिए इसे शुरू करने के लिए कुछ स्थान न दे (यानी factorial(1) = 1)

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

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


4

मुझे यह परिभाषा पसंद है:
पुनरावृत्ति में, एक रूटीन समस्या के एक छोटे हिस्से को हल करता है, समस्या को छोटे टुकड़ों में विभाजित करता है, और फिर प्रत्येक छोटे टुकड़ों को हल करने के लिए खुद को कॉल करता है।

मुझे स्टीव मैककोन्सेल्स को कोड कम्प्लीट में रिकर्सन की चर्चा भी पसंद है जहाँ वह कंप्यूटर साइंस की किताबों में रिकर्शन पर इस्तेमाल किए गए उदाहरणों की आलोचना करता है।

भाज्य या फाइबोनैचि संख्या के लिए पुनरावृत्ति का उपयोग न करें

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

मैंने सोचा था कि यह एक बहुत ही दिलचस्प बिंदु था और यह एक कारण हो सकता है कि पुनरावृत्ति को अक्सर गलत समझा जाता है।

EDIT: यह डेव के जवाब पर एक खुदाई नहीं थी - जब मैंने यह पोस्ट किया तो मैंने वह जवाब नहीं देखा था


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

मैं सहमत हूं - मुझे बस तब मिली जब मैं किताब पढ़ रहा था कि यह एक दिलचस्प बिंदु था पुनरावृत्ति पर एक खंड के बीच में उठाना
Robben_Ford_Fan_boy

4

1.) एक विधि पुनरावर्ती है अगर वह खुद को कॉल कर सकती है; या तो सीधे:

void f() {
   ... f() ... 
}

या अप्रत्यक्ष रूप से:

void f() {
    ... g() ...
}

void g() {
   ... f() ...
}

2.) पुनरावृत्ति का उपयोग कब करें

Q: Does using recursion usually make your code faster? 
A: No.
Q: Does using recursion usually use less memory? 
A: No.
Q: Then why use recursion? 
A: It sometimes makes your code much simpler!

3.) लोग पुनरावृत्ति का उपयोग केवल तब करते हैं जब पुनरावृत्त कोड लिखना बहुत जटिल होता है। उदाहरण के लिए, प्रीऑर्डर, पोस्टऑर्डर जैसे ट्री ट्रैवर्सल तकनीकों को पुनरावृत्त और पुनरावर्ती दोनों बनाया जा सकता है। लेकिन आमतौर पर हम इसकी सरलता के कारण पुनरावर्ती का उपयोग करते हैं।


विभाजन के बारे में विभाजन और जीत के दौरान जटिलता को कम करने के बारे में क्या?
mfrachet 19

4

यहाँ एक सरल उदाहरण है: एक सेट में कितने तत्व। (चीजों को गिनने के बेहतर तरीके हैं, लेकिन यह एक अच्छा सरल पुनरावर्ती उदाहरण है।)

सबसे पहले, हमें दो नियम चाहिए:

  1. यदि सेट खाली है, तो सेट में आइटमों की गिनती शून्य (duh!) है।
  2. यदि सेट खाली नहीं है, तो गिनती एक है और एक आइटम को हटाने के बाद सेट में आइटम की संख्या है।

मान लीजिए कि आपके पास इस तरह का एक सेट है: [xxx]। चलिए गिनते हैं कि कितने आइटम हैं।

  1. सेट [xxx] है जो खाली नहीं है, इसलिए हम नियम लागू करते हैं। वस्तुओं की संख्या एक से अधिक है [xx] में आइटमों की संख्या (यानी हमने एक आइटम हटा दिया है)।
  2. सेट [xx] है, इसलिए हम नियम 2 को फिर से लागू करते हैं: [+] में आइटम का एक + नंबर।
  3. सेट [x] है, जो अभी भी नियम 2 से मेल खाता है: [+] में मदों की एक + संख्या।
  4. अब सेट [] है, जो नियम 1 से मेल खाता है: गिनती शून्य है!
  5. अब जब हम चरण 4 (0) में उत्तर जानते हैं, तो हम चरण 3 (1 + 0) को हल कर सकते हैं।
  6. इसी तरह, अब हम चरण 3 (1) में उत्तर जानते हैं, हम चरण 2 (1 + 1) को हल कर सकते हैं
  7. और अब अंत में जब हम चरण 2 (2) में उत्तर जानते हैं, तो हम चरण 1 (1 + 2) को हल कर सकते हैं और वस्तुओं की गिनती [xxx] में प्राप्त कर सकते हैं, जो कि 3. हुर्रे!

हम इसका प्रतिनिधित्व कर सकते हैं:

count of [x x x] = 1 + count of [x x]
                 = 1 + (1 + count of [x])
                 = 1 + (1 + (1 + count of []))
                 = 1 + (1 + (1 + 0)))
                 = 1 + (1 + (1))
                 = 1 + (2)
                 = 3

पुनरावर्ती समाधान लागू करते समय, आपके पास आमतौर पर कम से कम 2 नियम होते हैं:

  • आधार, साधारण मामला जो बताता है कि क्या होता है जब आपने अपने सभी डेटा का "उपयोग" किया है। यह आमतौर पर "यदि आप डेटा को संसाधित करने से बाहर हैं, तो आपका उत्तर X है"
  • पुनरावर्ती नियम, जो बताता है कि यदि आपके पास अभी भी डेटा है तो क्या होगा। यह आमतौर पर किसी प्रकार का नियम है जो कहता है कि "अपने डेटा को छोटा करने के लिए कुछ करें, और अपने नियमों को छोटे डेटा सेट पर पुन: लागू करें।"

अगर हम ऊपर से छद्मकोड में अनुवाद करते हैं, तो हमें मिलता है:

numberOfItems(set)
    if set is empty
        return 0
    else
        remove 1 item from set
        return 1 + numberOfItems(set)

बहुत अधिक उपयोगी उदाहरण हैं (उदाहरण के लिए एक पेड़ को पीछे छोड़ते हुए), जो मुझे यकीन है कि अन्य लोग कवर करेंगे।


3

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

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


3

एक उदाहरण: एक सीढ़ी की पुनरावर्ती परिभाषा है: एक सीढ़ी में निम्न शामिल हैं: - एक एकल चरण और एक सीढ़ी (पुनरावर्तन) - या केवल एक कदम (समाप्ति)


2

हल की गई समस्या पर पुनरावृत्ति करने के लिए: कुछ भी न करें, आप कर रहे हैं।
एक खुली समस्या पर पुनरावृत्ति करने के लिए: अगला चरण करें, फिर बाकी पर पुनरावृत्ति करें।


2

सादे अंग्रेजी में: मान लें कि आप 3 काम कर सकते हैं:

  1. एक सेब लें
  2. टैली मार्क्स लिखिए
  3. टैली मार्क्स गिनें

आपके सामने एक टेबल पर बहुत सारे सेब हैं और आप जानना चाहते हैं कि कितने सेब हैं।

start
  Is the table empty?
  yes: Count the tally marks and cheer like it's your birthday!
  no:  Take 1 apple and put it aside
       Write down a tally mark
       goto start

आपके द्वारा किए जाने तक उसी चीज़ को दोहराने की प्रक्रिया को पुनरावृत्ति कहा जाता है।

मुझे आशा है कि यह "सादा अंग्रेजी" उत्तर है जिसे आप ढूंढ रहे हैं!


1
रुको, मेरे सामने एक टेबल पर बहुत सारे टैली मार्क्स हैं, और अब मैं जानना चाहता हूं कि कितने टैली मार्क्स हैं। क्या मैं किसी तरह इसके लिए सेब का उपयोग कर सकता हूं?
क्रिस्टोफर हैमरस्ट्रॉम

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

2

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

एक दूसरे का सामना करने वाले दो दर्पणों पर विचार करें। हमने साफ-सुथरा अनंत प्रभाव देखा है। प्रत्येक प्रतिबिंब दर्पण का एक उदाहरण है, जो दर्पण के किसी अन्य उदाहरण के भीतर निहित होता है, आदि दर्पण स्वयं का प्रतिबिंब होता है।

एक द्विआधारी खोज पेड़ पुनरावृत्ति का एक अच्छा प्रोग्रामिंग उदाहरण है। संरचना प्रत्येक नोड के साथ पुनरावर्ती है जिसमें एक नोड के 2 उदाहरण हैं। एक द्विआधारी खोज पेड़ पर काम करने के कार्य भी पुनरावर्ती हैं।


2

यह एक पुराना प्रश्न है, लेकिन मैं लॉजिस्टिक दृष्टिकोण से एक उत्तर जोड़ना चाहता हूं (अर्थात एल्गोरिथ्म शुद्धता के दृष्टिकोण से या प्रदर्शन के दृष्टिकोण से नहीं)।

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

इस प्रकार, मैं अक्सर पुनरावृत्ति से बचता हूं, और इसके बजाय स्टैक ऑपरेशन का उपयोग करता हूं, क्योंकि रिकर्सन स्वयं अनिवार्य रूप से स्टैक ऑपरेशन है।


1

आप इसे किसी भी समय उपयोग करना चाहते हैं आपके पास एक पेड़ की संरचना है। यह XML को पढ़ने में बहुत उपयोगी है।


1

प्रोग्रामिंग पर लागू होने वाली पुनरावृत्ति मूल रूप से अपनी परिभाषा के अंदर से एक फ़ंक्शन को बुला रही है (खुद के अंदर), विभिन्न मापदंडों के साथ ताकि किसी कार्य को पूरा करने के लिए।


1

"अगर मेरे पास एक हथौड़ा है, तो सब कुछ एक नाखून की तरह देखो।"

रिकर्सियन बड़ी समस्याओं के लिए एक समस्या को सुलझाने की रणनीति है, जहां हर कदम पर, "2 छोटी चीजों को एक बड़ी चीज में बदल दें," हर बार एक ही हथौड़ा के साथ।

उदाहरण

मान लीजिए कि आपकी डेस्क 1024 कागजों की अव्यवस्थित गंदगी से ढकी है। पुनरावृत्ति का उपयोग करते हुए, आप गड़बड़ी से कागज के एक साफ, स्वच्छ ढेर कैसे बनाते हैं?

  1. विभाजित करें: सभी शीटों को बाहर फैलाएं, ताकि आपके पास प्रत्येक "स्टैक" में सिर्फ एक शीट हो।
  2. जीत:
    1. एक शीट को एक दूसरे के ऊपर रखकर चारों ओर घूमें। अब आपके पास 2 के ढेर हैं।
    2. चारों ओर जाएं, प्रत्येक 2-स्टैक को एक और 2-स्टैक के शीर्ष पर रखें। अब आपके पास 4 के ढेर हैं।
    3. चारों ओर, प्रत्येक 4-स्टैक को एक और 4-स्टैक के ऊपर रखें। अब आपके पास 8 के ढेर हैं।
    4. ... इत्यादि ...
    5. अब आपके पास 1024 चादरों का एक बड़ा ढेर है!

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


6
आप फूट डालो और जीतो का वर्णन कर रहे हैं। हालांकि यह पुनरावृत्ति का एक उदाहरण है, यह केवल किसी भी तरह से नहीं है।
कोनराड रुडोल्फ

कोई बात नहीं। मैं यहाँ एक वाक्य में [पुनरावृत्ति की दुनिया] [1] को पकड़ने की कोशिश नहीं कर रहा हूँ। मैं एक सहज व्याख्या चाहता हूं। [१]: facebook.com/pages/Recursion-Fairy/269711978049
एंड्रेस जान टैक

1

पुनरावृत्ति वह प्रक्रिया है जहां एक विधि कॉल एक निश्चित कार्य करने में सक्षम होने के लिए है। यह कोड की अतिरेक को कम करता है। अधिकांश पुनरावर्ती कार्यों या विधियों में पुनरावर्ती कॉल को तोड़ने के लिए एक संघनक होना चाहिए अर्थात यदि कोई शर्त पूरी होती है तो खुद को कॉल करने से रोकें - यह एक अनंत लूप के निर्माण को रोकता है। सभी कार्य पुनरावर्ती उपयोग किए जाने के लिए अनुकूल नहीं हैं।


1

अगर मेरी राय किसी के साथ सहमत है, क्षमा करें, मैं सिर्फ सादे अंग्रेजी में पुनरावर्तन समझाने की कोशिश कर रहा हूँ।

मान लीजिए कि आपके तीन प्रबंधक हैं- जैक, जॉन और मॉर्गन। जैक 2 प्रोग्रामर, जॉन - 3, और मॉर्गन - 5 का प्रबंधन करता है। आप प्रत्येक प्रबंधक को 300 डॉलर देने जा रहे हैं और जानना चाहते हैं कि इसकी लागत क्या होगी। उत्तर स्पष्ट है - लेकिन क्या होगा अगर मॉर्गन के कर्मचारियों में से 2 भी प्रबंधक हैं?

यहाँ पुनरावृत्ति आता है। आप पदानुक्रम के शीर्ष से शुरू करते हैं। गर्मियों की लागत 0 $ है। आप जैक से शुरू करते हैं, फिर जांचें कि क्या उसके पास कर्मचारी के रूप में कोई प्रबंधक है। यदि आप पाते हैं कि उनमें से कोई भी है, तो जांचें कि क्या उनके पास कोई प्रबंधक है और कर्मचारी हैं। एक प्रबंधक को हर बार गर्मियों की लागत में 300 डॉलर जोड़ें। जब आप जैक के साथ समाप्त हो जाते हैं, तो जॉन, उसके कर्मचारियों और फिर मॉर्गन के पास जाएं।

आपको कभी पता नहीं चलेगा कि आप उत्तर पाने से पहले कितने चक्र में जाएंगे, हालांकि आप जानते हैं कि आपके पास कितने प्रबंधक हैं और आप कितने बजट खर्च कर सकते हैं।

पुनरावृत्ति एक वृक्ष है, जिसकी शाखाएँ और पत्तियाँ क्रमशः माता-पिता और बच्चे कहलाते हैं। जब आप एक पुनरावर्तन एल्गोरिथ्म का उपयोग करते हैं, तो आप कमोबेश होशपूर्वक डेटा से एक पेड़ का निर्माण कर रहे हैं।


1

सादे अंग्रेजी में, पुनरावृत्ति का अर्थ है बार-बार कुछ दोहराना।

प्रोग्रामिंग में एक उदाहरण अपने भीतर फ़ंक्शन को कॉल करने का है।

किसी संख्या के भाज्य की गणना के निम्नलिखित उदाहरण को देखें:

public int fact(int n)
{
    if (n==0) return 1;
    else return n*fact(n-1)
}

1
सादे अंग्रेजी में, बार-बार कुछ दोहराने के लिए पुनरावृत्ति कहा जाता है।
toon81

1

कोई भी एल्गोरिथ्म डेटाटाइप पर संरचनात्मक पुनरावृत्ति प्रदर्शित करता है यदि मूल रूप से डेटाटाइप के प्रत्येक मामले के लिए एक केस के साथ एक स्विच-स्टेटमेंट होता है।

उदाहरण के लिए, जब आप एक प्रकार पर काम कर रहे हों

  tree = null 
       | leaf(value:integer) 
       | node(left: tree, right:tree)

एक संरचनात्मक पुनरावर्ती एल्गोरिदम का रूप होगा

 function computeSomething(x : tree) =
   if x is null: base case
   if x is leaf: do something with x.value
   if x is node: do something with x.left,
                 do something with x.right,
                 combine the results

यह वास्तव में किसी भी एल्गोरिथ्म को लिखने का सबसे स्पष्ट तरीका है जो डेटा संरचना पर काम करता है।

अब, जब आप Peano axioms का उपयोग करके पूर्णांक (अच्छी तरह से, प्राकृतिक संख्या) को देखते हैं

 integer = 0 | succ(integer)

आप देखते हैं कि पूर्णांक पर एक संरचनात्मक पुनरावर्ती एल्गोरिदम इस तरह दिखता है

 function computeSomething(x : integer) =
   if x is 0 : base case
   if x is succ(prev) : do something with prev

बहुत प्रसिद्ध फैक्टरियल फंक्शन इस फॉर्म का सबसे तुच्छ उदाहरण है।


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