रिकर्सन (कंप्यूटर विज्ञान)



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

"The power of recursion evidently lies in the possibility of defining an infinite set of objects by a finite statement. In the same manner, an infinite number of computations can be described by a finite recursive program, even if this program contains no explicit repetitions."

- Niklaus Wirth

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

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

पुनरावर्ती कार्य और एल्गोरिदम
एक सामान्य एल्गोरिथम#डिजाइन रणनीति समस्या को उसी प्रकार की उप-समस्याओं में विभाजित करना है, जो मूल के समान हैं, उन उप-समस्याओं को हल करें, और परिणामों को संयोजित करें। इसे अक्सर फूट डालो और जीतो विधि के रूप में जाना जाता है; जब एक लुकअप तालिका के साथ जोड़ा जाता है जो पहले हल की गई उप-समस्याओं के परिणामों को संग्रहीत करता है (उन्हें बार-बार हल करने और अतिरिक्त गणना समय खर्च करने से बचने के लिए), इसे गतिशील प्रोग्रामिंग या memoization के रूप में संदर्भित किया जा सकता है [sic].

बेस केस
एक पुनरावर्ती फ़ंक्शन परिभाषा में एक या अधिक आधार मामले होते हैं, जिसका अर्थ है इनपुट जिसके लिए फ़ंक्शन एक परिणाम पैदा करता है तुच्छ (गणित) ly (बिना आवर्ती), और एक या अधिक पुनरावर्ती मामले, जिसका अर्थ है इनपुट जिसके लिए प्रोग्राम की पुनरावृत्ति होती है (स्वयं कॉल करता है)। उदाहरण के लिए, कारख़ाने का फ़ंक्शन को समीकरणों द्वारा पुनरावर्ती रूप से परिभाषित किया जा सकता है $0! = 1$ और, सभी के लिए $n > 0$, $n! = n(n − 1)!$. कोई भी समीकरण अपने आप में पूर्ण परिभाषा नहीं बनाता है; पहला बेस केस है, और दूसरा रिकर्सिव केस है। क्योंकि बेस केस रिकर्सन की श्रृंखला को तोड़ता है, इसे कभी-कभी टर्मिनेटिंग केस भी कहा जाता है।

पुनरावर्ती मामलों की नौकरी को जटिल इनपुट को सरल में विभाजित करने के रूप में देखा जा सकता है। ठीक से डिज़ाइन किए गए पुनरावर्ती फ़ंक्शन में, प्रत्येक पुनरावर्ती कॉल के साथ, इनपुट समस्या को इस तरह से सरल किया जाना चाहिए कि अंततः बेस केस तक पहुंचना चाहिए। (ऐसे कार्य जो सामान्य परिस्थितियों में समाप्त करने के लिए अभिप्रेत नहीं हैं—उदाहरण के लिए, कुछ डेमॉन (कंप्यूटर सॉफ़्टवेयर)—इसका अपवाद हैं।) बेस केस लिखने की उपेक्षा करना, या इसके लिए गलत तरीके से परीक्षण करना, अनंत लूप का कारण बन सकता है।

कुछ कार्यों के लिए (जैसे कि वह जो श्रृंखला (गणित) की गणना करता है $e = 1/0! + 1/1! + 1/2! + 1/3! + ...$) इनपुट डेटा द्वारा निहित कोई स्पष्ट आधार मामला नहीं है; इनके लिए कोई एक पैरामीटर जोड़ सकता है (जैसे कि हमारे श्रृंखला उदाहरण में जोड़े जाने वाले शब्दों की संख्या) एक 'स्टॉपिंग मानदंड' प्रदान करने के लिए जो आधार मामला स्थापित करता है। इस तरह के एक उदाहरण को अधिक स्वाभाविक रूप से corecursion द्वारा माना जाता है, जहां आउटपुट में उत्तरोत्तर पद आंशिक योग हैं; इसे nth पद (nth आंशिक योग) की गणना करने के लिए इंडेक्सिंग पैरामीटर का उपयोग करके एक पुनरावर्तन में परिवर्तित किया जा सकता है।

पुनरावर्ती डेटा प्रकार
कई कंप्यूटर प्रोग्रामों को मनमाने ढंग से बड़ी मात्रा में डेटा को संसाधित या उत्पन्न करना चाहिए। पुनरावर्तन डेटा का प्रतिनिधित्व करने के लिए एक तकनीक है जिसका सटीक आकार प्रोग्रामर के लिए अज्ञात है: प्रोग्रामर इस डेटा को एक स्व-संदर्भ | स्व-संदर्भ परिभाषा के साथ निर्दिष्ट कर सकता है। स्व-संदर्भित परिभाषाएँ दो प्रकार की होती हैं: आगमनात्मक और सह-संदर्भ परिभाषाएँ।

आगमनात्मक रूप से परिभाषित डेटा
आगमनात्मक रूप से परिभाषित पुनरावर्ती डेटा परिभाषा वह है जो निर्दिष्ट करती है कि डेटा के उदाहरणों का निर्माण कैसे किया जाए। उदाहरण के लिए, लिंक की गई सूचियों को आगमनात्मक रूप से परिभाषित किया जा सकता है (यहां, हास्केल (प्रोग्रामिंग भाषा) सिंटैक्स का उपयोग करके):

, एक अभिव्यक्ति में एक से अधिक उत्पाद या योग संचालन के साथ।

संयोग से परिभाषित डेटा और कोरकर्शन
एक सहगामी डेटा परिभाषा वह है जो उन परिचालनों को निर्दिष्ट करती है जो डेटा के एक टुकड़े पर किए जा सकते हैं; विशिष्ट रूप से, स्व-संदर्भित सह-प्रवाहकीय परिभाषाओं का उपयोग अनंत आकार की डेटा संरचनाओं के लिए किया जाता है।

अनौपचारिक रूप से दिए गए तारों की अनंत धारा (कंप्यूटर विज्ञान) की एक अनुकूल परिभाषा इस तरह दिख सकती है:

स्ट्रिंग्स की एक धारा एक ऐसी वस्तु है जो: सिर एक स्ट्रिंग है, और पूंछ (ओं) तार की एक धारा है।

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

Corecursion संयोग से संबंधित है, और इसका उपयोग (संभवतः) अनंत वस्तुओं के विशेष उदाहरणों की गणना करने के लिए किया जा सकता है। एक प्रोग्रामिंग तकनीक के रूप में, यह अक्सर आलसी मूल्यांकन प्रोग्रामिंग भाषाओं के संदर्भ में प्रयोग किया जाता है, और वांछित आकार या प्रोग्राम के आउटपुट की सटीकता अज्ञात होने पर रिकर्सन के लिए बेहतर हो सकता है। ऐसे मामलों में कार्यक्रम को असीम रूप से बड़े (या असीम रूप से सटीक) परिणाम के लिए एक परिभाषा और उस परिणाम का एक सीमित भाग लेने के लिए एक तंत्र दोनों की आवश्यकता होती है। पहली n अभाज्य संख्याओं की गणना करने की समस्या वह है जिसे एक कोरकर्सिव प्रोग्राम (जैसे फोल्ड (उच्च-क्रम फ़ंक्शन)#उदाहरण) के साथ हल किया जा सकता है।

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

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

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

अप्रत्यक्ष पुनरावर्तन
पुनरावर्तन के सबसे बुनियादी उदाहरण, और यहाँ प्रस्तुत अधिकांश उदाहरण प्रदर्शित करते हैं डायरेक्ट रिकर्सन, जिसमें एक फंक्शन खुद को कॉल करता है।  अप्रत्यक्ष  पुनरावर्तन तब होता है जब एक फ़ंक्शन को स्वयं नहीं बल्कि किसी अन्य फ़ंक्शन द्वारा कहा जाता है जिसे वह (या तो प्रत्यक्ष या अप्रत्यक्ष रूप से) कहता है। उदाहरण के लिए, यदि f f को कॉल करता है, जो कि प्रत्यक्ष रिकर्सन है, लेकिन यदि f g को कॉल करता है, जो f, को कॉल करता है, तो वह  का अप्रत्यक्ष रिकर्सन है च।  तीन या अधिक कार्यों की श्रृंखला संभव है; उदाहरण के लिए, फ़ंक्शन 1 फ़ंक्शन 2 को कॉल करता है, फ़ंक्शन 2 फ़ंक्शन 3 को कॉल करता है, और फ़ंक्शन 3 फ़ंक्शन 1 को फिर से कॉल करता है।

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

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

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

"[Functions that consume structured data] typically decompose their arguments into their immediate structural components and then process those components. If one of the immediate components belongs to the same class of data as the input, the function is recursive. For that reason, we refer to these functions as (STRUCTURALLY) RECURSIVE FUNCTIONS."

- Felleisen, Findler, Flatt, and Krishnaurthi

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

"Many well-known recursive algorithms generate an entirely new piece of data from the given data and recur on it. HtDP (How to Design Programs) refers to this kind as generative recursion. Examples of generative recursion include: gcd, quicksort, binary search, mergesort, Newton's method, fractals, and adaptive integration."

- Matthias Felleisen

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

कार्यान्वयन के मुद्दे
वास्तविक कार्यान्वयन में, एक शुद्ध पुनरावर्ती कार्य (बेस केस के लिए एकल जांच, अन्यथा पुनरावर्ती चरण) के बजाय, स्पष्टता या दक्षता के प्रयोजनों के लिए कई संशोधन किए जा सकते हैं। इसमे शामिल है:


 * आवरण समारोह (शीर्ष पर)
 * बेस केस को शॉर्ट-सर्किट करना, उर्फ ​​आर्म-लेंथ रिकर्सन (नीचे)
 * हाइब्रिड एल्गोरिथम (सबसे नीचे) - डेटा के काफी छोटे होने पर एक अलग एल्गोरिथम पर स्विच करना

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

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

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

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

शॉर्ट-सर्किटिंग मुख्य रूप से एक चिंता का विषय है जब कई आधार मामले सामने आते हैं, जैसे कि एक पेड़ में नल पॉइंटर्स, जो फ़ंक्शन कॉल की संख्या में रैखिक हो सकते हैं, इसलिए महत्वपूर्ण बचत $O(n)$ एल्गोरिदम; इसे गहराई से पहली खोज के लिए नीचे चित्रित किया गया है। एक पेड़ पर शॉर्ट सर्किट आधार मामले के रूप में एक खाली नोड पर विचार करने के बजाय आधार मामले के रूप में एक पत्ते (कोई बच्चों के साथ गैर-खाली नोड) पर विचार करने से मेल खाता है। यदि केवल एक आधार मामला है, जैसे कि फैक्टोरियल की गणना में, शॉर्ट सर्किटिंग केवल प्रदान करता है $O(1)$ बचत।

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

गहराई-पहली खोज
बाइनरी ट्री की डेप्थ-फर्स्ट सर्च (DFS) में शॉर्ट-सर्किटिंग का एक बुनियादी उदाहरण दिया गया है; मानक पुनरावर्ती चर्चा के लिए #बाइनरी ट्री अनुभाग देखें।

डीएफएस के लिए मानक पुनरावर्ती एल्गोरिथ्म है:

शॉर्ट सर्किटिंग में, इसके बजाय यह है:
 * बेस केस: यदि वर्तमान नोड शून्य है, तो झूठी वापसी करें
 * पुनरावर्ती कदम: अन्यथा, वर्तमान नोड के मूल्य की जांच करें, यदि मेल खाता है तो सही लौटें, अन्यथा बच्चों पर पुनरावर्तन करें
 * वर्तमान नोड का मूल्य जांचें, अगर मेल खाता है तो सही लौटें,
 * अन्यथा, बच्चों पर, यदि शून्य नहीं है, तो पुनरावर्ती करें।

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

ऊँचाई h के एक बिल्कुल सही बाइनरी ट्री के मामले में, 2 हैंh+1−1 नोड और 2h+1 बच्चों के रूप में अशक्त संकेत (2 में से प्रत्येक के लिए 2h छोड़ देता है), इसलिए शॉर्ट-सर्किटिंग सबसे खराब स्थिति में फ़ंक्शन कॉल की संख्या को आधा कर देता है।

सी में, मानक पुनरावर्ती एल्गोरिथ्म को इस प्रकार लागू किया जा सकता है: <वाक्यविन्यास लैंग = सी> बूल ट्री_कंटेन्स (स्ट्रक्चर नोड * ट्री_नोड, इंट आई) { अगर (tree_node == न्यूल) विवरण झूठा है; // मुख्य मामला और अगर (tree_node-> डेटा == i)       वापसी सच; वरना रिटर्न ट्री_कंटेन्स (ट्री_नोड-> लेफ्ट, आई) || tree_contains(tree_node->right, i); } 

शॉर्ट-सर्किट एल्गोरिथ्म को इस प्रकार लागू किया जा सकता है:

<वाक्यविन्यास लैंग = सी> // खाली पेड़ को संभालने के लिए रैपर फ़ंक्शन बूल ट्री_कंटेन्स (स्ट्रक्चर नोड * ट्री_नोड, इंट आई) { अगर (tree_node == न्यूल) विवरण झूठा है; // खाली पेड़ वरना वापसी tree_contains_do (tree_node, i); // सहायक फ़ंक्शन को कॉल करें }

// मानता है tree_node != NULL बूल ट्री_कंटेन्स_डो (स्ट्रक्चर नोड * ट्री_नोड, इंट आई) { अगर (tree_node-> डेटा == i)       वापसी सच; // मिल गया और // रिकर्स रिटर्न (ट्री_नोड-> लेफ्ट एंड& ट्री_कंटेन्स_डो (ट्री_नोड-> लेफ्ट, आई)) || (ट्री_नोड-> राइट एंड& ट्री_कंटेन्स_डो (ट्री_नोड-> राइट, आई)); } 

बूलियन && (AND) ऑपरेटरों के शॉर्ट सर्किट मूल्यांकन के उपयोग पर ध्यान दें, ताकि पुनरावर्ती कॉल केवल तभी किया जा सके जब नोड वैध (गैर-शून्य) हो। ध्यान दें कि जबकि AND में पहला शब्द एक नोड के लिए सूचक है, दूसरा शब्द एक बूलियन है, इसलिए समग्र अभिव्यक्ति एक बूलियन का मूल्यांकन करती है। रिकर्सिव शॉर्ट सर्किटिंग में यह एक आम मुहावरा है। यह बूलियन || के शॉर्ट-सर्किट मूल्यांकन के अतिरिक्त है (या) ऑपरेटर, बाएं बच्चे के विफल होने पर केवल सही बच्चे की जांच करने के लिए। वास्तव में, इन कार्यों के संपूर्ण नियंत्रण प्रवाह को रिटर्न स्टेटमेंट में एकल बूलियन अभिव्यक्ति के साथ बदला जा सकता है, लेकिन सुगमता दक्षता के लिए कोई लाभ नहीं उठाती है।

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

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

एक्स की गणना करने के लिए टेम्पलेट्स की तुलना करेंn एक्स द्वारा परिभाषितn = एफ (एन, एक्सn-1) एक्स सेbase: एक अनिवार्य भाषा के लिए ओवरहेड फ़ंक्शन को परिभाषित करना है, और एक कार्यात्मक भाषा के लिए ओवरहेड संचायक चर x को परिभाषित करना है।

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

<वाक्यविन्यास लैंग = सी> अहस्ताक्षरित इंट फैक्टोरियल (अहस्ताक्षरित इंट एन) { अहस्ताक्षरित इंट उत्पाद = 1; // खाली उत्पाद 1 है जबकि (एन) { उत्पाद * = एन; --एन; } वापसी उत्पाद; } 

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

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

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

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

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

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

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

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

टेल रिकर्सन का महत्व यह है कि टेल-रिकर्सिव कॉल (या कोई टेल कॉल) करते समय, कॉलर की वापसी स्थिति को कॉल स्टैक पर सेव करने की आवश्यकता नहीं होती है; जब पुनरावर्ती कॉल वापस आती है, तो यह पहले से सहेजी गई वापसी स्थिति पर सीधे शाखा करेगी। इसलिए, उन भाषाओं में जो टेल कॉल्स के इस गुण को पहचानती हैं, टेल रिकर्सन स्पेस और टाइम दोनों को बचाता है।

निष्पादन का क्रम
इन दो कार्यों पर विचार करें:

फंक्शन 1
<वाक्यविन्यास प्रकाश लैंग = सी> शून्य पुनरावर्ती समारोह (पूर्णांक संख्या) { प्रिंटफ (% डी \ n, संख्या); अगर (संख्या <4) रिकर्सिवफंक्शन (संख्या + 1); } 



समारोह 2
<वाक्यविन्यास प्रकाश लैंग = सी> शून्य पुनरावर्ती समारोह (पूर्णांक संख्या) { अगर (संख्या <4) रिकर्सिवफंक्शन (संख्या + 1); प्रिंटफ (% डी \ n, संख्या); } 

फंक्शन 2 फंक्शन 1 है जिसमें लाइनों की अदला-बदली की जाती है।

किसी फ़ंक्शन के केवल एक बार कॉल करने के मामले में, रिकर्सिव कॉल से पहले रखे गए निर्देशों को रिकर्सिव कॉल के बाद दिए गए किसी भी निर्देश से पहले एक बार रिकर्सन निष्पादित किया जाता है। अधिकतम रिकर्सन तक पहुंचने के बाद बाद वाले को बार-बार निष्पादित किया जाता है।

यह भी ध्यान दें कि प्रिंट स्टेटमेंट का क्रम उल्टा है, जो कि कॉल स्टैक पर फ़ंक्शन और स्टेटमेंट को संग्रहीत करने के तरीके के कारण है।

फैक्टोरियल
एक पुनरावर्ती प्रक्रिया का एक उत्कृष्ट उदाहरण एक प्राकृतिक संख्या के भाज्य की गणना करने के लिए उपयोग किया जाने वाला कार्य है:


 * $$ \operatorname{fact}(n) =

\begin{cases} 1 & \mbox{if } n = 0 \\ n \cdot \operatorname{fact}(n-1) & \mbox{if } n > 0 \\ \end{cases} $$

फ़ंक्शन को पुनरावृत्ति संबंध के रूप में भी लिखा जा सकता है:
 * $$b_n = nb_{n-1}$$
 * $$b_0 = 1$$

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

उपरोक्त अनिवार्य कोड एक संचायक चर का उपयोग करके इस गणितीय परिभाषा के बराबर है $t$:



\begin{align} \operatorname{fact}(n) & = \operatorname{fact_{acc}}(n, 1) \\ \operatorname{fact_{acc}}(n, t) & = \begin{cases} t & \mbox{if } n = 0 \\ \operatorname{fact_{acc}}(n-1, nt) & \mbox{if } n > 0 \\ \end{cases} \end{align} $$ ऊपर दी गई परिभाषा सीधे कार्यात्मक प्रोग्रामिंग भाषाओं जैसे कि योजना (प्रोग्रामिंग भाषा) में अनुवाद करती है; यह पुनरावर्ती रूप से कार्यान्वित पुनरावृत्ति का एक उदाहरण है।

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

कार्य परिभाषा:
 * $$ \gcd(x,y) =

\begin{cases} x & \mbox{if } y = 0 \\ \gcd(y, \operatorname{remainder}(x,y)) & \mbox{if } y > 0 \\ \end{cases} $$

सबसे बड़े सामान्य विभाजक के लिए पुनरावृत्ति संबंध, जहाँ $$x \% y$$ शेष व्यक्त करता है $$x / y$$:


 * $$\gcd(x,y) = \gcd(y, x \% y)$$ यदि $$y \neq 0$$
 * $$\gcd(x,0) = x$$

उपरोक्त पुनरावर्ती कार्यक्रम पूंछ-पुनरावर्ती है; यह पुनरावृत्त एल्गोरिथम के समतुल्य है, और ऊपर दिखाई गई गणना मूल्यांकन के चरणों को दर्शाती है जो एक ऐसी भाषा द्वारा निष्पादित की जाएगी जो टेल कॉल को समाप्त करती है। नीचे उसी एल्गोरिदम का एक संस्करण है जो स्पष्ट पुनरावृत्ति का उपयोग करता है, जो उस भाषा के लिए उपयुक्त है जो पूंछ कॉल को समाप्त नहीं करता है। अपनी स्थिति को पूरी तरह से चर x और y में बनाए रखने और लूपिंग निर्माण का उपयोग करके, कार्यक्रम पुनरावर्ती कॉल करने और कॉल स्टैक को बढ़ाने से बचता है।

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

हनोई की मीनारें


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

कार्य परिभाषा:
 * $$ \operatorname{hanoi}(n) =

\begin{cases} 1 & \mbox{if } n = 1 \\ 2\cdot\operatorname{hanoi}(n-1) + 1 & \mbox{if } n > 1\\ \end{cases} $$ हनोई के लिए पुनरावृत्ति संबंध:
 * $$h_n = 2h_{n-1}+1$$
 * $$h_1 = 1$$

उदाहरण कार्यान्वयन:

हालांकि सभी पुनरावर्ती कार्यों का एक स्पष्ट समाधान नहीं है, हनोई अनुक्रम के टॉवर को एक स्पष्ट सूत्र में घटाया जा सकता है।

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

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

सी में बाइनरी खोज का उदाहरण कार्यान्वयन:

<वाक्यविन्यास लैंग = सी> /* उचित प्रारंभिक स्थितियों के साथ बाइनरी_सर्च को कॉल करें।

इनपुट: डेटा आरोही क्रम में क्रमबद्ध पूर्णांकों की एक सरणी है, toFind खोजने के लिए पूर्णांक है, गिनती सरणी में तत्वों की कुल संख्या है

आउटपुट: बाइनरी_सर्च का परिणाम

*/ int search (int *data, int toFind, int count) {   // प्रारंभ = 0 (प्रारंभिक सूचकांक) // अंत = गिनती - 1 (शीर्ष सूचकांक) बाइनरी_सर्च लौटें (डेटा, टूफाइंड, 0, काउंट -1); }

/*  बाइनरी सर्च एल्गोरिथम।

इनपुट: डेटा आरोही क्रम में क्रमबद्ध पूर्णांकों की एक सरणी है, toFind खोजने के लिए पूर्णांक है, प्रारंभ न्यूनतम सरणी अनुक्रमणिका है, अंत अधिकतम सरणी सूचकांक है आउटपुट: सरणी डेटा के भीतर खोजने के लिए पूर्णांक की स्थिति, -1 अगर नहीं मिला */ इंट बाइनरी_सर्च (इंट * डेटा, इंट टूफाइंड, इंट स्टार्ट, इंट एंड) {   // मध्य बिंदु प्राप्त करें। int मध्य = प्रारंभ + (अंत - प्रारंभ)/2; // पूर्णांक विभाजन

अगर (शुरू> अंत) // स्टॉप कंडीशन (बेस केस) वापसी -1; और अगर (डेटा [मध्य] == toFind) // मिला, वापसी index मध्य वापसी; और अगर (डेटा [मिड]> टूफाइंड) // डेटा टूफाइंड से अधिक है, तो आधा खोजें बाइनरी_सर्च लौटें (डेटा, टूफाइंड, स्टार्ट, मिड -1); और // डेटा खोजने से कम है, ऊपरी आधा खोजें बाइनरी_सर्च लौटें (डेटा, खोजने के लिए, मध्य + 1, अंत); } 

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

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

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

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

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

<वाक्यविन्यास लैंग = सी> संरचना नोड { इंट डेटा; // कुछ पूर्णांक डेटा संरचना नोड * अगला; // पॉइंटर किसी अन्य स्ट्रक्चर नोड के लिए }; 

क्योंकि संरचना नोड डेटा संरचना को पुनरावर्ती रूप से परिभाषित किया गया है, इस पर चलने वाली प्रक्रियाओं को स्वाभाविक रूप से पुनरावर्ती प्रक्रियाओं के रूप में लागू किया जा सकता है। नीचे दी गई list_print प्रक्रिया सूची के खाली होने तक नीचे चलती है (अर्थात, सूची सूचक का मान NULL है)। प्रत्येक नोड के लिए यह डेटा तत्व (एक पूर्णांक) प्रिंट करता है। सी कार्यान्वयन में, सूची सूची_प्रिंट प्रक्रिया द्वारा अपरिवर्तित बनी हुई है।

<वाक्यविन्यास लैंग = सी> शून्य सूची_प्रिंट (संरचना नोड * सूची) {   अगर (सूची! = न्यूल) // बेस केस {      प्रिंटफ (% डी, सूची-> डेटा); // प्रिंट पूर्णांक डेटा एक स्थान के बाद list_print (सूची-> अगला); // अगले नोड पर पुनरावर्ती कॉल } } 

बाइनरी पेड़
नीचे बाइनरी ट्री नोड के लिए एक सरल परिभाषा दी गई है। लिंक की गई सूचियों के लिए नोड की तरह, इसे पुनरावर्ती रूप से स्वयं के संदर्भ में परिभाषित किया गया है। दो स्व-संदर्भित संकेत हैं: बाएँ (बाएँ उप-वृक्ष की ओर इशारा करते हुए) और दाएँ (दाएँ उप-वृक्ष की ओर इशारा करते हुए)। <वाक्यविन्यास लैंग = सी> संरचना नोड { इंट डेटा; // कुछ पूर्णांक डेटा संरचना नोड * बायां; // बाईं सबट्री के लिए सूचक संरचना नोड * सही; // दाएँ सबट्री की ओर इशारा करें }; 

पुनरावर्तन का उपयोग करके पेड़ पर संचालन को लागू किया जा सकता है। ध्यान दें कि क्योंकि दो स्व-संदर्भ सूचक (बाएं और दाएं) हैं, पेड़ के संचालन के लिए दो पुनरावर्ती कॉल की आवश्यकता हो सकती है:

<वाक्यविन्यास लैंग = सी> // परीक्षण करें कि क्या tree_node में i है; यदि हां, तो 1 लौटाएं, यदि नहीं तो 0। int tree_contains (संरचना नोड * tree_node, int i) { अगर (tree_node == न्यूल) वापसी 0; // मुख्य मामला और अगर (tree_node-> डेटा == i)       वापसी 1; वरना रिटर्न ट्री_कंटेन्स (ट्री_नोड-> लेफ्ट, आई) || tree_contains(tree_node->right, i); }  जैसा कि ऊपर परिभाषित किया गया है, tree_contains को किसी भी कॉल के लिए अधिकतम दो पुनरावर्ती कॉल किए जाएंगे।

<वाक्यविन्यास प्रकाश लैंग = सी> // इनऑर्डर ट्रैवर्सल: शून्य ट्री_प्रिंट (संरचना नोड * ट्री_नोड) { अगर (ट्री_नोड! = न्यूल) {// बेस केस ट्री_प्रिंट (ट्री_नोड-> बाएं); // जाना छोड़ दिया प्रिंटफ (% डी, ट्री_नोड-> डेटा); // एक स्थान के बाद पूर्णांक प्रिंट करें ट्री_प्रिंट (ट्री_नोड-> राइट); // दायें जाइये } } 

ऊपर दिया गया उदाहरण ट्री ट्रैवर्सल | बाइनरी ट्री के इन-ऑर्डर ट्रैवर्सल को दिखाता है। बाइनरी सर्च ट्री बाइनरी ट्री का एक विशेष मामला है जहां प्रत्येक नोड के डेटा तत्व क्रम में होते हैं।

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

<वाक्यविन्यास लैंग = जावा लाइन = 1> आयात java.io.फ़ाइल;

पब्लिक क्लास फ़ाइल सिस्टम {

सार्वजनिक स्थैतिक शून्य main (String [] args) { पार ; }

/** निजी स्थिर शून्य ट्रैवर्स { फ़ाइल [] fs = File.listRoots ; for (int i = 0; i <fs.length; i++) { System.out.println(fs[i]); if (fs[i].isDirectory && fs[i].canRead) { आरट्रावर्स (एफएस [i]); } } }
 * फ़ाइल सिस्टम की जड़ें प्राप्त करें
 * पुनरावर्ती फ़ाइल सिस्टम ट्रैवर्सल के साथ आगे बढ़ता है

/** निजी स्थैतिक शून्य आरट्रावर्स (फ़ाइल एफडी) { फ़ाइल [] fss = fd.listFiles ;
 * पुनरावर्ती रूप से किसी दिए गए निर्देशिका को पार करें
 * @पारम एफडी ट्रैवर्सल के शुरुआती बिंदु को इंगित करता है
 * @पारम एफडी ट्रैवर्सल के शुरुआती बिंदु को इंगित करता है

for (int i = 0; i 

यह कोड पुनरावर्तन और पुनरावृत्ति दोनों है - फ़ाइलें और निर्देशिकाएँ पुनरावृत्त होती हैं, और प्रत्येक निर्देशिका पुनरावर्ती रूप से खोली जाती है।

ट्रैवर्स विधि प्रत्यक्ष पुनरावर्तन का एक उदाहरण है, जबकि ट्रैवर्स विधि एक आवरण कार्य है।

बेस केस परिदृश्य यह है कि किसी दिए गए फाइल सिस्टम में हमेशा निश्चित संख्या में फाइलें और/या निर्देशिकाएं होंगी।

पुनरावर्ती एल्गोरिदम की समय-दक्षता
पुनरावर्ती एल्गोरिदम की समय जटिलता को बिग ओ नोटेशन के पुनरावृत्ति संबंध में व्यक्त किया जा सकता है। वे (आमतौर पर) तब एक बिग-ओ टर्म में सरलीकृत हो सकते हैं।

शॉर्टकट नियम (मास्टर प्रमेय)
यदि फ़ंक्शन की समय-जटिलता रूप में है $$T(n) = a \cdot T(n / b) + f(n)$$ फिर समय-जटिलता का बिग ओ इस प्रकार है:


 * यदि $$f(n) = O(n ^ { \log_b a - \varepsilon})$$ कुछ स्थिरांक के लिए $$\varepsilon > 0$$, तब टी (एन) = \थीटा (एन ^ {\log_b ए})
 * यदि $$f(n) = \Theta(n ^ { \log_b a })$$, फिर टी (एन) = \ थीटा (एन ^ { \ log_b ए} \ लॉग एन) 
 * यदि $$f(n) = \Omega(n ^ { \log_b a + \varepsilon})$$ कुछ स्थिरांक के लिए $$\varepsilon > 0$$, और यदि $$ \cdot f(n / b) \leq c \cdot f(n)$$ कुछ स्थिरांक के लिए $c < 1$ और सभी पर्याप्त रूप से बड़े $n$, फिर टी (एन) = \ थीटा (एफ (एन)) </ गणित>

कहाँ पे $a$ रिकर्सन के प्रत्येक स्तर पर रिकर्सिव कॉल की संख्या का प्रतिनिधित्व करता है, $b$ पुनरावर्तन के अगले स्तर के लिए इनपुट किस कारक से छोटा है, इसका प्रतिनिधित्व करता है (यानी आप समस्या को विभाजित करने वाले टुकड़ों की संख्या), और $f(n)$ उस कार्य का प्रतिनिधित्व करता है जो फ़ंक्शन पुनरावृत्ति के प्रत्येक स्तर पर किसी भी पुनरावर्तन (जैसे विभाजन, पुनर्संयोजन) से स्वतंत्र रूप से करता है।

यह भी देखें

 * कार्यात्मक प्रोग्रामिंग
 * कम्प्यूटेशनल समस्या
 * एसक्यूएल में श्रेणीबद्ध और पुनरावर्ती प्रश्न
 * क्लेन-रॉसर विरोधाभास
 * ओपन रिकर्सन
 * रिकर्सन
 * सीरपिन्स्की वक्र
 * मैककार्थी 91 समारोह
 * μ-पुनरावर्ती कार्य
 * आदिम पुनरावर्ती कार्य
 * तक (फ़ंक्शन)

इस पेज में लापता आंतरिक लिंक की सूची

 * समारोह (कंप्यूटर विज्ञान)
 * प्रत्यावर्तन
 * कार्यात्मक प्रोग्रामिंग
 * संगणनीयता सिद्धांत
 * खोज तालिका
 * डेमन (कंप्यूटर सॉफ्टवेयर)
 * संयोग
 * आत्म संदर्भ
 * जानकारी
 * लिंक्ड सूची
 * पूर्णांकों
 * स्ट्रीम (कंप्यूटर साइंस)
 * अभाज्य सँख्या
 * आपसी पुनरावर्तन
 * अनाम पुनरावर्तन
 * अनाम समारोह
 * पास-बाय-संदर्भ
 * बहाव को काबू करें
 * यात्रा
 * ढेर (डेटा संरचना)
 * उदाहरण (कंप्यूटर विज्ञान)
 * क्रम पर्यावरण
 * घुमाव के दौरान
 * पायथन (प्रोग्रामिंग भाषा)
 * परिमाणक्रम
 * कार्यात्मक भाषाएँ
 * एक्सेप्शन हेंडलिंग
 * मिलान वाइल्डकार्ड
 * रूपरेखा (कंप्यूटर प्रोग्रामिंग)
 * सॉफ़्टवेयर परीक्षण
 * महत्तम सामान्य भाजक
 * क्रमबद्ध सरणी
 * SQL में श्रेणीबद्ध और पुनरावर्ती प्रश्न

संदर्भ

 * (viii+64 pages)