जेसन के उत्तर के लिए +1, जो स्पष्ट रूप से समस्या को समझाता है।
अब कुछ समाधान के लिए! मुझे एल्गोरिदम से रिकर्सन को हटाने के कम से कम तीन तरीकों से पता है:
- इसके बजाय पूरी तरह से पुनरावृत्त एल्गोरिदम खोजें (जो कुछ समस्याओं के लिए मुश्किल हो सकता है);
- लूप के साथ एक समान में रिकर्सिव एल्गोरिदम को ट्रांसफॉर्म करें और कॉल स्टैक के बराबर स्टोर करने के लिए स्टैक < टी> (या किसी प्रकार की सूची) का उपयोग करें। इसकी मूल आवश्यकता के समान अंतरिक्ष आवश्यकता है, लेकिन ढेर ढेर से कहीं अधिक बड़ा हो सकता है!
- रिकर्सिव एल्गोरिदम का एक विशेष परिवार पूंछ-रिकर्सिव है। जो आसानी से यांत्रिक रूप से ढेर को कभी भी बहने के लिए परिवर्तित नहीं कर सकते हैं। तुम भाग्यशाली हो, यह तुम्हारा मामला है!
एक एल्गोरिद्म जिसका मतलब है कि वे पिछले लौटने से पहले किया बात कर रहे हैं पूंछ पुनरावर्ती है, अगर अपने सभी पुनरावर्ती कॉल पूंछ कॉल हैं। यदि यह आपके लिए अस्पष्ट है, तो Google के साथ बेहतर उदाहरण देखें।
ऐसे एल्गोरिदम आसानी से पैरामीटर को समायोजित करके और वास्तविक कॉल के बजाय गोटो का उपयोग करके परिवर्तित किया जा सकता है। अपना उदाहरण दोबारा देखें:
private int Euler5(int dividend, int divisor)
{
tail_call:
if (divisor < 21)
{
// if it equals zero, move to the next divisor
if (dividend % divisor == 0)
{
divisor++;
goto tail_call; // return Eular5(dividend, divisor);
}
else
{
dividend++;
// return Eular5(dividend, 1); // move to the dividend
divisor = 1;
goto tail_call;
}
}
// oh hey, the divisor is above 20, so what's the dividend
return dividend;
}
ओह हे! यह बिल्कुल वही कार्य है, लेकिन एक निश्चित स्टैक आकार के साथ (कोई कॉल नहीं है, केवल कूदता है)। अब कुछ कहेंगे: "उह ... गेटोस! वे बुरे हैं! मर जाओ, मर जाओ!"। मैं कहूंगा कि यह कुछ वैध उपयोगों में से एक है। आखिरकार यदि आपका कंपाइलर काफी स्मार्ट था, तो यह पूंछ-कॉल अनुकूलन स्वयं करेगा (एफ # वास्तव में करता है, सी # नहीं करता है, जेआईटी x64 पर ऐसा कर सकता है, x86 पर नहीं)।
लेकिन उन लोगों के लिए मैं कहूंगा: थोड़ा बेहतर देखो। क्योंकि प्रत्येक/यदि शाखा के अंत में एक गोटो है, तो मैं इसे "अगर" पूरी तरह से बाहर ले जा सकता हूं। अब मेरे पास कुछ है "प्रारंभ: अगर (एक्स) {वाई(); गोटो शुरू;}" इसके बारे में सोचें, यह सिर्फ एक है "जबकि (एक्स) वाई()" लूप। तो आपको बस अपने फ़ंक्शन का पुनरावृत्ति संस्करण मिला:
private int Euler5(int dividend, int divisor)
{
while (divisor < 21)
{
// if it equals zero, move to the next divisor
if (dividend % divisor == 0)
{
divisor++;
}
else
{
dividend++;
divisor = 1;
}
}
// oh hey, the divisor is above 20, so what's the dividend
return dividend;
}
अच्छा!
यह संभव है कि आप अनंत रिकर्सन के बिना भी स्टैक उड़ रहे हों। उनमें से बहुत सी समस्याएं विशेष रूप से इतनी बड़ी होने के लिए डिज़ाइन की गई हैं कि आपके कोड को उचित रूप से अच्छी तरह से स्केल करने की आवश्यकता है। आप शायद यहां एक गैर-पुनरावर्ती दृष्टिकोण का उपयोग करना चाहते हैं और इसे लूप में दोबारा दोहराएं। – Servy
@ सर्वी: लगता है कि मेरे पास ढेर के बारे में जानने के लिए और यह कैसे काम करता है। धन्यवाद। – MyCodeSucks
यह अभी भी स्टैक ओवरफ़्लो का कारण बनता है, लेकिन जब आप पुनरारंभ करते हैं, तो आपको 1 के विभाजक को जांचने की आवश्यकता नहीं होती है, सभी पूर्णांक 1 से पहले विभाजित होते हैं। आप अपने लाभांश को 2 (या यहां तक कि 10) तक बढ़ा सकते हैं। जब आप एक लूप – Cemafor