क्या पुनरावृत्ति अपने आप में एक विशेषता है?


116

... या यह सिर्फ एक अभ्यास है?

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

मैं यहाँ पूछ रहा हूँ क्योंकि मुझे संदेह है कि किसी के पास एक निश्चित उत्तर है।

उदाहरण के लिए, निम्नलिखित दो विधियों में क्या अंतर है:

public static void a() {
    return a();
    }

public static void b() {
    return a();
    }

अन्य के अलावा " aहमेशा के लिए जारी रहता है" (वास्तविक प्रोग्राम में इसका उपयोग उपयोगकर्ता को फिर से अमान्य इनपुट के साथ प्रदान करने के लिए सही ढंग से करने के लिए किया जाता है), क्या इसके aऔर के बीच कोई मूलभूत अंतर है b? संयुक्त राष्ट्र-अनुकूलित संकलक के लिए, उन्हें अलग तरीके से कैसे नियंत्रित किया जाता है?

अंत में इसे करने के लिए सीखने के द्वारा कि क्या करने के लिए नीचे आता है return a()से bहै कि हम भी सीख लिया वजह return a()से a। क्या हमने?


24
बहुत बढ़िया बहस। मुझे आश्चर्य है कि अगर आपने इसे अपने प्रोफेसर को इस तरह समझाया। यदि आपने किया, तो मुझे लगता है कि उसे आपको अपना खोया हुआ क्रेडिट देना चाहिए।
माइकल यावोरस्की

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

34
एक समस्या को हल करने के लिए सुरुचिपूर्ण तरीके से आने के लिए, या बॉक्स की सोच से बाहर आने के लिए, प्रोफेसर को इसके बजाय अतिरिक्त क्रेडिट देना चाहिए।

11
असाइनमेंट क्या था? यह एक समस्या है जिसके बारे में मैंने अक्सर सोचा है, जब आप एक प्रोग्रामिंग असाइनमेंट सबमिट करते हैं, तो क्या चिह्नित किया जा रहा है, किसी समस्या को हल करने की क्षमता या आपके द्वारा सीखी गई चीजों का उपयोग करने की आपकी क्षमता। ये दोनों जरूरी समान नहीं हैं।
लियोन

35
FWIW, इनपुट के लिए संकेत देना जब तक कि यह सही नहीं है पुनरावृत्ति का उपयोग करने के लिए एक अच्छी जगह नहीं है, स्टैक को ओवरफ्लो करना बहुत आसान है। इस विशेष उदाहरण के लिए, कुछ का उपयोग करना बेहतर होगा a() { do { good = prompt(); } while (!good); }
केविन

जवाबों:


113

अपने विशिष्ट प्रश्न का उत्तर देने के लिए: नहीं, भाषा सीखने के दृष्टिकोण से, पुनरावृत्ति एक विशेषता नहीं है। यदि आपके प्रोफेसर ने वास्तव में आपको "सुविधा" का उपयोग करने के लिए चिह्नित किया है, तो वह अभी तक पढ़ाया नहीं गया था, यह गलत था।

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

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

ढेर ओवरफ्लो

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

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

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

पठनीयता

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

private int getInput() {
    int input;
    do {
        input = promptForInput();
    } while (!inputIsValid(input))
    return input;
}

बनाम

private int getInput() {
    int input = promptForInput();
    if(inputIsValid(input)) {
        return input;
    }
    return getInput();
}

हाँ, ये दोनों काम करते हैं, और हाँ वे दोनों समझने में बहुत आसान हैं। लेकिन अंग्रेजी में दो दृष्टिकोणों का वर्णन कैसे किया जा सकता है? मुझे लगता है कि यह कुछ इस तरह होगा:

जब तक इनपुट मान्य नहीं होगा, तब तक मैं इनपुट के लिए संकेत दूंगा और फिर इसे वापस कर दूंगा

बनाम

मैं इनपुट के लिए संकेत दूंगा, फिर यदि इनपुट मान्य है तो मैं उसे वापस कर दूंगा, अन्यथा मुझे इनपुट मिलता है और उसके बदले परिणाम वापस मिलता है

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

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


8
क्या आप अपने दावे पर विस्तार कर सकते हैं कि पुनरावृत्ति एक विशेषता नहीं है? मैंने अपने उत्तर में तर्क दिया है कि यह है, क्योंकि सभी संकलक आवश्यक रूप से इसका समर्थन नहीं करते हैं।
हैरी जॉनसन

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

2
ध्यान दें कि 'पठनीयता' समस्या वाक्य रचना के साथ एक समस्या है। आवर्ती के बारे में स्वाभाविक रूप से "अपठनीय" कुछ भी नहीं है। वास्तव में, आगमनात्मक डेटा संरचनाओं को व्यक्त करने का सबसे आसान तरीका है, जैसे लूप और सूची और क्रम और इतने पर। और अधिकांश डेटा संरचनाएं आगमनात्मक हैं।
nomen

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

2
@HarryJohnston को पुनरावृत्ति के लिए समर्थन का समर्थन एक नई सुविधा की कमी के बजाय मौजूदा सुविधाओं के लिए एक अपवाद होगा । विशेष रूप से, इस प्रश्न के संदर्भ में, एक "नई सुविधा" का अर्थ है "उपयोगी व्यवहार जिसे हमने अभी तक सिखाया नहीं है", जो कि पुनरावृत्ति के लिए सही नहीं है क्योंकि यह उन सुविधाओं का एक तार्किक विस्तार है जिन्हें सिखाया गया था (अर्थात्, प्रक्रियाएं शामिल हैं निर्देश, निर्देश और प्रक्रिया कॉल निर्देश हैं)। यह ऐसा है जैसे कि प्रोफेसर ने एक छात्र को पढ़ाया, और फिर उसे एक से अधिक बार एक ही मूल्य जोड़ने के लिए डांटा क्योंकि "हमने कई गुना अधिक कवर नहीं किया है"।
nmclean

48

बल्कि मेटा सवाल से शाब्दिक सवाल का जवाब करने के लिए,: प्रत्यावर्तन है भावना है कि नहीं सभी compilers और / या भाषाओं जरूरी अनुमति में, एक सुविधा। व्यवहार में, यह सभी (सामान्य) आधुनिक संकलकों से अपेक्षित है - और निश्चित रूप से सभी जावा संकलक! - लेकिन यह सार्वभौमिक रूप से सच नहीं है।

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

ऐसे कंपाइलर के लिए, जब आप किसी फंक्शन को इस तरह कहते हैं

a();

इसे लागू किया जाता है

move the address of label 1 to variable return_from_a
jump to label function_a
label 1

और () की परिभाषा,

function a()
{
   var1 = 5;
   return;
}

के रूप में कार्यान्वित किया जाता है

label function_a
move 5 to variable var1
jump to the address stored in variable return_from_a

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

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

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


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

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

5
Shader भाषाएँ या GPGPU भाषाएँ (कहते हैं, GLSL, Cg, OpenCL C) एक उदाहरण के रूप में पुनरावृत्ति का समर्थन नहीं करती हैं। Insofar, "सभी भाषाएं इसका समर्थन नहीं करती हैं" तर्क निश्चित रूप से मान्य है। रिकर्सियन एक स्टैक के बराबर होता है (यह जरूरी नहीं कि स्टैक हो , लेकिन रिटर्न एड्रेस और फंक्शन फ्रेम को किसी तरह स्टोर करने के लिए एक साधन होना चाहिए )।
डेमन

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

2
यहां तक ​​कि टर्बो पास्कल के कुछ संस्करण डिफ़ॉल्ट रूप से अक्षम हो गए, और आपको इसे सक्षम करने के लिए एक कंपाइलर निर्देश सेट करना पड़ा।
dan04

17

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


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

3
"मैं चाहता हूं कि कौन सी व्यक्तिगत प्राथमिकता तक पढ़ना आसान है"। माना। रिकर्सियन एक जावा सुविधा नहीं है। ये हैं
माइक

2
@Vality: टेल कॉल एलिमिनेशन? कुछ JVM यह कर सकते हैं, लेकिन ध्यान रखें कि अपवादों के लिए स्टैक ट्रेस बनाए रखने की भी आवश्यकता है। यदि यह पूंछ कॉल उन्मूलन की अनुमति देता है, तो स्टैक ट्रेस, भोलेपन से उत्पन्न, अमान्य हो सकता है, इसलिए कुछ JVM उस कारण से TCE नहीं करते हैं।
icktoofay

5
किसी भी तरह, अपने टूटे हुए कोड को कम टूटने के लिए अनुकूलन पर निर्भर करना, बहुत बुरा रूप है।
cHao

7
+1, देखें कि हाल ही में उबंटू में लॉगिन स्क्रीन तब टूटी थी जब उपयोगकर्ता लगातार एंटर बटन दबाता था, उसी एक्सबॉक्स को खुशी होती है
सेबस्टियन

13

अंक घटाने क्योंकि "हम कक्षा में पुनरावृत्ति को कवर नहीं किया" भयानक है। यदि आपने फ़ंक्शन A को कॉल करने का तरीका सीखा है, जो फ़ंक्शन B को कॉल करता है, जो फ़ंक्शन C को कॉल करता है, जो B पर वापस लौटता है, जो A पर वापस लौटता है, जो कॉल करने वाले पर वापस लौटता है, और शिक्षक ने आपको स्पष्ट रूप से नहीं बताया कि ये अलग-अलग फ़ंक्शन होने चाहिए (जो पुराने FORTRAN संस्करणों में उदाहरण के लिए मामला होगा), ऐसा कोई कारण नहीं है कि A, B और C सभी समान कार्य नहीं कर सकते।

दूसरी ओर, हमें यह तय करने के लिए वास्तविक कोड देखना होगा कि क्या आपके विशेष मामले में पुनरावृत्ति का उपयोग करना वास्तव में सही काम है। कई विवरण नहीं हैं, लेकिन यह गलत लगता है।


10

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

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

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

मेरा मानना ​​है कि पुनरावर्तन के बाद से ही प्रोफेसर ने अंक काट लिए हैं और इसकी संभावना नहीं है कि बिना प्रोग्रामिंग अनुभव वाले किसी व्यक्ति को पुनरावृत्ति के बारे में सोचना होगा। (बेशक इसका मतलब यह नहीं है कि वे नहीं करेंगे, लेकिन यह संभावना नहीं है)।

IMHO, मुझे लगता है कि प्रोफेसर आपको अंक घटाकर सही है। आप आसानी से सत्यापन भाग को एक अलग विधि में ले जा सकते हैं और इसे इस तरह उपयोग कर सकते हैं:

public bool foo() 
{
  validInput = GetInput();
  while(!validInput)
  {
    MessageBox.Show("Wrong Input, please try again!");
    validInput = GetInput();
  }
  return hasWon(x, y, piece);
}

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


विधि का उद्देश्य स्वयं इनपुट को मान्य करना है, फिर किसी अन्य विधि के परिणाम को कॉल करें और वापस लौटाएं (यही कारण है कि यह स्वयं लौटता है)। विशिष्ट होने के लिए, यह जांचता है कि टिक-टैक-टो खेल में चाल वैध है, तो रिटर्न hasWon(x, y, piece)(केवल प्रभावित पंक्ति और स्तंभ की जांच करने के लिए)।

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

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

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

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

6

हो सकता है कि आपके प्रोफेसर ने इसे अभी तक पढ़ाया न हो, लेकिन लगता है कि आप पुनरावृत्ति के फायदे और नुकसान जानने के लिए तैयार हैं।

पुनरावर्तन का मुख्य लाभ यह है कि पुनरावर्ती एल्गोरिदम अक्सर लिखने में बहुत आसान और तेज होते हैं।

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

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


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

1
यदि स्टैक ओवरफ्लो एक समस्या है, तो आपको एक भाषा / रनटाइम का उपयोग करना चाहिए जो टेल कॉल ऑप्टिमाइज़ेशन का समर्थन करता है, जैसे .NET 4.0 या कोई कार्यात्मक प्रोग्रामिंग भाषा
सेबस्टियन

सभी पुनरावर्ती पूंछ कॉल नहीं हैं।
वारेन ड्यू

6

विशिष्ट प्रश्न के बारे में, एक पुनरावृत्ति एक विशेषता है, मैं हाँ कहने के लिए इच्छुक हूं, लेकिन प्रश्न की पुनः व्याख्या करने के बाद। भाषा और संकलन के सामान्य डिज़ाइन विकल्प हैं जो पुनरावृत्ति को संभव बनाते हैं, और ट्यूरिंग-पूर्ण भाषाएँ मौजूद हैं जो पुनरावृत्ति की अनुमति नहीं देती हैं । दूसरे शब्दों में, पुनरावृत्ति एक ऐसी क्षमता है जो भाषा / संकलक डिजाइन में कुछ विकल्पों द्वारा सक्षम होती है।


1
इससे मेरा सिर फट गया, विशेषकर अनलैम्बडा +1
जॉन पॉवेल ने

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

5

इनपुट विफलता के मामले में इनपुट के लिए एक पुनरावर्ती फ़ंक्शन का उपयोग करके मैं आपके प्रश्न से क्या घटा सकता हूं, यह एक अच्छा अभ्यास नहीं है। क्यों?

क्योंकि प्रत्येक पुनरावर्ती कार्य कॉल स्टैक पर धकेल दिया जाता है। चूंकि यह पुनरावृत्ति उपयोगकर्ता इनपुट द्वारा संचालित होती है, इसलिए एक अनंत पुनरावर्ती कार्य होना संभव है और इस प्रकार इसका परिणाम StackOverflow :-p

ऐसा करने के लिए एक गैर पुनरावर्ती लूप होने से जाने का रास्ता है।


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

4
@fay लेकिन यदि इनपुट कई बार अमान्य है, तो आपको एक StackOverflowError मिलेगी। पुनरावृत्ति अधिक सुरुचिपूर्ण है, लेकिन मेरी आँखों में, आमतौर पर एक नियमित लूप (स्टैक के कारण) की तुलना में अधिक समस्या है।
माइकल यावोरस्की

1
यह एक दिलचस्प और अच्छी बात है। मैंने उस त्रुटि पर विचार नहीं किया था। हालांकि, क्या while(true)समान विधि को कॉल करने के माध्यम से समान प्रभाव प्राप्त किया जा सकता है ? यदि हां, तो मैं यह नहीं कहूंगा कि यह पुनरावृत्ति के बीच किसी भी अंतर का समर्थन करता है, यह जानने के लिए अच्छा है।

1
@fay while(true)एक अनंत लूप है। जब तक आपके पास एक breakबयान नहीं होता है, मुझे इसमें बिंदु दिखाई नहीं देता है, जब तक कि आप अपने प्रोग्राम को क्रैश करने की कोशिश नहीं कर रहे हैं। मेरी बात है, यदि आप एक ही विधि कॉल (उस के प्रत्यावर्तन), यह कभी कभी आप एक दे देंगे StackOverflowError , लेकिन अगर आप एक का उपयोग whileया forपाश, ऐसा नहीं होगा। समस्या केवल एक नियमित लूप के साथ मौजूद नहीं है। हो सकता है कि मैंने आपको गलत समझा हो, लेकिन मेरा जवाब आपके लिए नहीं है।
माइकल यवोरस्की

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

3

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

एक सुविधा के रूप में पुनरावृत्ति

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

कोई पुनरावृत्ति नहीं?

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

एक अभ्यास के रूप में पुनरावृत्ति

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

  • वाक्य-विन्यास अभी भी बहुत अनुकूल नहीं है
  • संकलक उस अभ्यास का पता लगाने और उसे अनुकूलित करने में सक्षम नहीं हो सकते हैं

तल - रेखा

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

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