2013-06-03 7 views
5

मैं प्रोजेक्ट यूलर नंबर 5 पर काम कर रहा हूं। मैंने गुगल नहीं किया है, क्योंकि इससे आमतौर पर उत्तर के साथ SO हो जाएगा। तो, यह मुझे मिला है:इस लूप को कैसे तोड़ें

private int Euler5(int dividend, int divisor) 
    { 
     if (divisor < 21) 
     { 
      // if it equals zero, move to the next divisor 
      if (dividend % divisor == 0) 
      { 
       divisor++; 
       return Euler5(dividend, divisor); 
      } 
      else 
      { 
       dividend++; 
       return Euler5(dividend, 1); // move to the dividend 
      } 
     } 
     // oh hey, the divisor is above 20, so what's the dividend 
     return dividend; 
    } 

मेरे दिमाग में, यह समझ में आता है। फिर भी वीएस2012 मुझे एक स्टैक ओवर फ्लोएक्सप्शन बता रहा है कि मैं यह सुनिश्चित करता हूं कि मैं अनंत लूप में नहीं हूं या रिकर्सन का उपयोग कर रहा हूं। मेरा सवाल है, यह एक अनंत लूप क्यों है? मुझे एहसास है कि मैं पूरी तरह मूर्खतापूर्ण कुछ खो रहा हूँ।

संपादित

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

+3

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

+0

@ सर्वी: लगता है कि मेरे पास ढेर के बारे में जानने के लिए और यह कैसे काम करता है। धन्यवाद। – MyCodeSucks

+0

यह अभी भी स्टैक ओवरफ़्लो का कारण बनता है, लेकिन जब आप पुनरारंभ करते हैं, तो आपको 1 के विभाजक को जांचने की आवश्यकता नहीं होती है, सभी पूर्णांक 1 से पहले विभाजित होते हैं। आप अपने लाभांश को 2 (या यहां तक ​​कि 10) तक बढ़ा सकते हैं। जब आप एक लूप – Cemafor

उत्तर

10

बेशक इस प्रकार का तर्क ढेर को उड़ाने जा रहा है। इस बारे में सोचो, अगर आप सबसे छोटी संख्या 1--10 द्वारा समान रूप से विभाज्य पाने की समस्या को हल करने के लिए इस तर्क लागू करने के लिए कॉल, आप कम से कम 2520 होगी ढेर में गहरी, problem statement प्रति थे:

2520 सबसे छोटी संख्या है जिसे प्रत्येक संख्या द्वारा 1 से 10 तक किसी भी शेष के बिना विभाजित किया जा सकता है।

1--20 के लिए, उत्तर स्पष्ट रूप से बहुत बड़ा है और यह आश्चर्य की बात नहीं है कि आप ढेर उड़ रहे हैं। आपको एक गैर-पुनरावर्ती समाधान मिलना चाहिए।

मेरा सवाल यह है कि यह एक अनंत लूप क्यों है?

यह नहीं है। ढेर आकार में सीमित है। आप बहुत अधिक रिकर्सिव कॉल कर रहे हैं और अंत में अधिकतम स्टैक आकार का उल्लंघन कर रहे हैं।

मुझे एहसास है कि मुझे कुछ पूरी तरह से मूर्खतापूर्ण याद आ रही है।

आप right place पर आए थे।

+0

आह में बदलते हैं तो बस कुछ युक्तियाँ, ठीक है, वह है। मुझे पता नहीं था कि ढेर पर बहुत सी कॉल होने से मुद्दों का कारण बन सकता है। मैंने कभी भी इसके करीब कुछ भी नहीं किया होगा। लेकिन अब यह थोड़ा सा समझ में आता है। – MyCodeSucks

+0

@ CL4PTR4P: Yup। यह मूल रूप से एक ढेर अतिप्रवाह है। ढेर सीमित आकार है। बहुत सारे फ़ंक्शन स्टैक को कॉल करते हैं और आपके पास एक हलचल उल्लंघन होगा। – jason

1

जेसन के उत्तर के लिए +1, जो स्पष्ट रूप से समस्या को समझाता है।

अब कुछ समाधान के लिए! मुझे एल्गोरिदम से रिकर्सन को हटाने के कम से कम तीन तरीकों से पता है:

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

एक एल्गोरिद्म जिसका मतलब है कि वे पिछले लौटने से पहले किया बात कर रहे हैं पूंछ पुनरावर्ती है, अगर अपने सभी पुनरावर्ती कॉल पूंछ कॉल हैं। यदि यह आपके लिए अस्पष्ट है, तो 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; 
} 

अच्छा!

+0

मैं समस्या का समाधान नहीं मांग रहा था। – MyCodeSucks

+0

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

+0

लेकिन फिर भी रिकर्सिविटी को हटाने का वह नहीं है जिसे मैं ढूंढ रहा था। – MyCodeSucks

संबंधित मुद्दे