2016-08-27 4 views
6

सी ++ मानक std::partitionForwardIterator और BidirectionalIterator के बीच अनुमानित अनुप्रयोगों की विभिन्न संख्याओं के लिए आवश्यक है। ForwardIterator संस्करण के लिए, विधेय आवेदनों की संख्या < = एन, जहां एन = std::distance(first, last), लेकिन BidirectionalIterator संस्करण के लिए, विधेय आवेदनों की संख्या < = एन/2 होगा किया जाएगा। जाहिर है, दोनों संस्करणों में समय जटिलता (एन) है।सी ++ मानक को विभिन्न प्रकार के इटरेटर के लिए विभिन्न जटिलताओं को पूरा करने के लिए std :: विभाजन की आवश्यकता क्यों है?

मेरा सवाल है, यह विभिन्न प्रकार के इटरेटर के लिए अलग-अलग आवश्यकताओं को प्रदान करने के लिए परेशान क्यों है? इस तरह की आवश्यकता बहुत सारे कंपाइलर्स को मजबूर करती है?

उदाहरण: एमएसवीसी, इस तरह की आवश्यकता को पूरा करने के दो तरीकों से std::partition फ़ंक्शन को कार्यान्वित करें, जो बहुत ही सुरुचिपूर्ण प्रतीत नहीं होता है।

एक और सवाल: क्या कोई एल्गोरिथ्म है कि इस गुणांक पर निर्भर करता है कर रहे हैं, जैसे कि जब एन/2 हो जाता है एन, asymptotic जटिलता अलग होगा कि? मेरी समझ के लिए, यदि हम Master's Theorem पर T(n) = aT(n/b) + f(n) के रूप में मानते हैं, तो f(n) में गुणांक इससे कोई फर्क नहीं पड़ता।

सीएफ। MSVC के विभाजन के एक बराबर कार्यान्वयन:

template<class BidirIt, class UnaryPred> 
BidirIt partition(BidirIt first, BidirIt last, UnaryPred pred, std::bidirectional_iterator_tag) 
{ 
    while (true) 
    { 
     while ((first != last) && pred(*first)) 
     { 
      ++first; 
     } 
     if (first == last) 
     { 
      break; 
     } 
     --last; 
     while ((first != last) && !pred(*last)) 
     { 
      --last; 
     } 
     if (first == last) 
     { 
      break; 
     } 
     std::iter_swap(first, last); 
     ++first; 
    } 
    return first; 
} 
template<class ForwardIt, class UnaryPred> 
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred pred, std::forward_iterator_tag) 
{ 
    first = std::find_if_not(first, last, pred); 
    if (first == last) 
    { 
     return first; 
    } 

    for (ForwardIt src = std::next(first); src != last; ++src) 
    { 
     if (pred(*src)) 
     { 
      std::iter_swap(first, src); 
      ++src; 
     } 
    } 
    return first; 
} 
template<class ForwardIt, class UnaryPred> 
ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred pred) 
{ 
    return partition(first, last, pred, typename std::iterator_traits<ForwardIt>::iterator_category()); 
} 

उत्तर

4

भविष्यवाणी pred दोनों मामलों में एन बार निष्पादित किया गया है - प्रत्येक तत्व को एक बार परीक्षण किया जाना चाहिए। ForwardIterator और BidirectionalIterator के बीच का अंतर स्वैप की मात्रा में है। क्योंकि यह एक ही बार में सामने से और पीछे से रेंज को स्कैन करता है, एक बार यह बाईं कि सही है कि करता है से विधेय और मूल्य को पूरा नहीं करता से मूल्य तक पहुँच जाता है

BidirectionalIterator, ज्यादा से ज्यादा एन/2 स्वैप करता है इसे पूरा करो, यह उन्हें स्वैप करता है। तो सबसे बुरी स्थिति में यह एन/2 स्वैप में यह काम कर सकता है।

ForwardIterator में यह लाभ नहीं है और सबसे खराब स्थिति में प्रत्येक तत्व के लिए स्वैप कर सकता है।

मानक को उन दो अलग-अलग सीमाओं की आवश्यकता होती है, क्योंकि वे दोनों सबसे अच्छे हैं। तो प्रोग्रामर भरोसा कर सकते हैं कि हर मानक पुस्तकालय कार्यान्वयन इस तरह से व्यवहार करेगा।

+0

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

+0

आपका स्वागत है। यदि उत्तर आपके प्रश्न का उत्तर देता है तो कृपया उत्तर को स्वीकार के रूप में चिह्नित करें। – michalsrb

3

यही सच है, समय जटिलता अभी भी एक ही है।

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

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

+0

मेरे प्रश्न का उत्तर देने के लिए धन्यवाद। अब मैं समझ सकता हूं कि स्वैप ऑपरेशन महंगा होने के बाद मानक स्वैप की संख्या को अनुकूलित करने की उम्मीद है। आपके तरह के उत्तरों के लिए फिर से धन्यवाद। :) –

+0

"विशेष रूप से बड़ी वस्तुओं के लिए। अधिकांश समय में वे तीन प्रति संचालन शामिल करते हैं।" ... मुझे उम्मीद नहीं है! एक सही ढंग से लागू डेटा संरचना के लिए इसमें तीन चाल संचालन या पीआईएमपीएल सूचक स्वैप शामिल होंगे। सही ढंग से लागू होने पर, स्वैपिंग महंगा नहीं है। जाहिर है कि आधा सस्ता संचालन करने के लिए अभी भी बेहतर है। –

+0

@ निकोलस होल्थॉस हाँ, मेरा मतलब था पाठ्यक्रम के संचालन। मेरी गलती को सुधारना धन्यवाद। – greenshade

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

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