8

मैंने उच्च और निम्न खोज की है और रन-टाइम जटिलताओं, रिकर्सन और जावा से संबंधित बहुत सारी सामग्री नहीं मिल रही है।रिकर्सिव एल्गोरिदम के लिए रन-टाइम जटिलताओं

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

private String toStringRec(DNode d) 
{ 
    if (d == trailer) 
     return ""; 
    else 
     return d.getElement() + toStringRec(d.getNext()); 
} 

यह एक पुनरावर्ती विधि कि बस हालांकि एक दोगुना से जुड़े सूची पुनरावृति और तत्वों का प्रिंट आउट जाएगा।

एकमात्र चीज जिसके साथ मैं आ सकता हूं यह है कि इसमें ओ (एन) की रन-टाइम जटिलता है, क्योंकि रिकर्सिव विधि कॉल की संख्या डीएलआईस्ट में नोड्स की संख्या पर निर्भर करेगी, लेकिन मैं अभी भी ' इस जवाब के साथ सहज महसूस नहीं करते हैं।

मुझे यकीन नहीं है कि मुझे d और d.getNext() के अतिरिक्त के लिए लेखांकन होना चाहिए या नहीं।

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

+0

देखें: http://stackoverflow.com/questions/1126388/slow-string-concatenation-over-large-input – dyoo

उत्तर

0

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

रिकर्सिव विधियों (ज्यादातर मामलों में) के बारे में दिलचस्प बात यह है कि वे भी अंतरिक्ष जटिलता में ओ (एन) हैं। एक नई स्टैक प्रविष्टि (विधि में पारित पैरामीटर को स्टोर करने के लिए) प्रत्येक कॉल के लिए toStringRec को बनाया जाता है, जिसे n बार कहा जाता है।

+1

दुर्भाग्य से यह स्पष्टीकरण गलत निष्कर्ष प्रदान करता है। यह स्ट्रिंग कॉन्सटेनेशन की लागत को ध्यान में रखता नहीं है। यही है, प्रत्येक आइटम पर लागत ** स्थिर नहीं है **। यह इस समस्या का एक प्रमुख बिंदु है। कृपया इसे सही करें। – dyoo

+0

मैं मानता हूं कि प्रत्येक आइटम की लागत स्थिर नहीं है, लेकिन मैं सहमत नहीं हूं कि यह ओ (एन) है। 'स्ट्रिंग 1 + स्ट्रिंग 2' की लागत ओ (एम) है, जहां एम परिणामी स्ट्रिंग की लंबाई है। विशेष रूप से, दो स्ट्रिंग्स को संयोजित करना एक नए चार [] लंबाई एम के निर्माण और मूल स्ट्रिंग्स से प्रत्येक चरित्र की एक-एक-एक समय की प्रतिलिपि बनाना सबसे खराब है। जब दिए गए कोड के पुनरावृत्ति पर, ToStringRec एक बहुत लंबे स्ट्रिंग को वापस कर सकता है, लेकिन concatenation की लागत अभी भी ओ (एम) है। एम इस उदाहरण में सीधे एन से बंधे नहीं है, क्योंकि 'getElement' खाली या बहुत लंबा तार वापस कर सकता है। – sgmorrison

+0

मान लें कि कुछ लंबाई 'm' है जो कि किसी विशेष d.getElement() के आकार पर ऊपरी सीमा है। फिर लौटे स्ट्रिंग का आकार हम 'toStringRec (नोड)' से वापस प्राप्त करते हैं, 'नोड' से शुरू होने वाली श्रृंखला की लंबाई से बंधे होते हैं। चलो टी (एन) 'गणना की लागत हो। फिर: 'टी (एन) <सी 1 + सी 2 * एम * (एन -1) + सी 3 * टी (एन -1) ', कुछ स्थिरांक' सी 1', 'सी 2',' सी 3' के लिए। मध्य अवधि स्ट्रिंग concatenation का प्रतिनिधित्व करता है। 'सी 4' को 'सी 1' से लगातार बड़ा होना चाहिए जो 'एम * सी 2' का एक बहुतायत भी है। – dyoo

3

पहली नज़र में, यह पूंछ कॉल का एक सामान्यीकरण tail recursion modulo cons का क्लासिक केस जैसा दिखता है। यह पुनरावृत्तियों की संख्या के साथ एक लूप के बराबर है।

हालांकि, यह इतना आसान नहीं है: यहां मुश्किल बात एक बढ़ती स्ट्रिंग के लिए d.getElement() के अलावा है: यह अपने आप में एक रैखिक आपरेशन है, और यह N बार दोहराया जाता है। इसलिए आपके फ़ंक्शन की जटिलता O(N^2) है।

+0

हम्म, मैंने सोचा था कि d.getElement() को नोड डी में संग्रहीत डेटा प्राप्त करना था। मुझे लगता है कि इस पर मेरा प्रश्न थोड़ा स्पष्ट है ... –

+2

@XiaoChuanYu नहीं, 'd.getElement()' 'O (1)' है। यह स्ट्रिंग कॉन्सटेनेशन है जो कि रैखिक है। – dasblinkenlight

+0

हां, स्ट्रिंग कॉन्सटेनेशन की लागत को अनदेखा न करने के लिए धन्यवाद। यह बिल्कुल सही है। गॉस राशि '1 + 2 + ... + एन' खेल में आता है, और वह जगह है जहां से वर्गिक आता है। – dyoo

2

यदि टी (एन) प्राथमिक संचालन की संख्या है (इस मामले में - जब हम फ़ंक्शन के बॉडी में प्रवेश करते हैं, तो अंदर की किसी भी पंक्ति को सबसे अधिक बार निष्पादित किया जाता है लेकिन दूसरा रिटर्न ओ (1) नहीं होता है)) n तत्वों की एक सूची पर toStringRec बुला, तो

T(0) = 1 - as the only things that happen is the branch instruction and a 
       return 
    T(n) = n + T(n-1) for n > 0 - as the stuff which is being done in the 
       function besides calling toStringRec is some constant time stuff and 
       concatenating strings that takes O(n) time; and we also run 
       toStringRec(d.getNet()) which takes T(n-1) time 

इस बिंदु हम एल्गोरिथ्म की जटिलता का वर्णन किया है पर द्वारा निष्पादित। अब हम टी, टी (एन) = ओ (एन ** 2) के लिए बंद फॉर्म की गणना कर सकते हैं।

+0

नहीं: "फ़ंक्शन में किए गए सामान" ओ (1) नहीं है।यह वह काम है जो 'n' के लिए आनुपातिक समय लेता है, मानते हैं कि प्रत्येक तत्व पर स्ट्रिंग का आकार खाली नहीं है। इसलिए, 'टी (एन) 'के लिए बंद फॉर्म' स्थिरांक सी के लिए 'टी (एन) = 1 सी + 2 सी + 3 सी + ... + एनसी' जैसा दिखता है। यह गॉस राशि है। 'टी (एन)' वर्गवार नहीं है, रैखिक नहीं है। – dyoo

+0

अच्छा पकड़, धन्यवाद! –

2

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

T(0) = 0 
T(n) = C + T(n-1) 

फिर आप प्रतिस्थापन का उपयोग कर एक श्रृंखला को खोजने के लिए समय को चलाने के लिए हल कर सकते हैं :

T(n) = C + T(n-1) = 2C + T(n-2) = 3C + T(n-3) = ... = nC + T(n-n) = nC + 0 = nC 

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

+0

बेशक इस उदाहरण में आप इसे सामान्य समझ सकते हैं: आप प्रत्येक नोड को एक लिंक्ड सूची में प्रिंट कर रहे हैं, इसलिए आपके द्वारा किए जाने वाले प्रिंटों की संख्या सूची के आकार के समान ही दर पर बढ़ती है। तो यह रैखिक समय है। – cjm

+1

इस विशेष उदाहरण में, हम यह नहीं मान सकते कि प्रत्येक चरण में किए गए काम को निरंतर समय दिया जाता है, यह देखते हुए कि जावा में स्ट्रिंग कॉन्सटेनेशन कैसे काम करता है। – dyoo

+0

मुझे लगता है कि यह धारणा बनाने के लिए ठीक है क्योंकि इस समस्या का बिंदु जावा लाइब्रेरी फ़ंक्शंस की जटिलता को नहीं देखना है, लेकिन यह समझने के लिए कि इस प्रकार के रिकर्सिव एल्गोरिदम का सामान्य रूप से विश्लेषण कैसे किया जा सकता है। – cjm

0

ऐसे रिकर्सिव एल्गोरिदम के लिए, ऑर्डर की गणना करने के लिए आमतौर पर रिकर्सिव समीकरण लिखना संभव है। टी (एन) के साथ निष्पादित निर्देशों की संख्या दिखाने के लिए यह परंपरागत है। इस उदाहरण में, हमने:

टी (एन) = टी (n - 1) + O (1)

(मान लें कि समारोह निरंतर समय में getElement रन है।) इस समीकरण के समाधान तुच्छता से टी है (एन) = ओ (एन)।

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

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