"C ++ कंटेनर पसंद" नामक एक अच्छी तरह से ज्ञात छवि (चीट शीट) है। यह वांछित उपयोग के लिए सबसे अच्छा कंटेनर चुनने के लिए एक फ्लो चार्ट है।
किसी को पता है कि अगर वहाँ पहले से ही एक सी + + 11 संस्करण है?
यह पिछले एक है:
"C ++ कंटेनर पसंद" नामक एक अच्छी तरह से ज्ञात छवि (चीट शीट) है। यह वांछित उपयोग के लिए सबसे अच्छा कंटेनर चुनने के लिए एक फ्लो चार्ट है।
किसी को पता है कि अगर वहाँ पहले से ही एक सी + + 11 संस्करण है?
यह पिछले एक है:
जवाबों:
ऐसा नहीं है कि मुझे पता है, हालांकि यह मेरे अनुमान से किया जा सकता है। इसके अलावा, चार्ट थोड़ा बंद है, क्योंकि list
सामान्य रूप से इतना अच्छा कंटेनर नहीं है, और न ही है forward_list
। दोनों सूची आला अनुप्रयोगों के लिए बहुत विशिष्ट कंटेनर हैं।
ऐसा चार्ट बनाने के लिए, आपको बस दो सरल दिशानिर्देशों की आवश्यकता है:
प्रदर्शन के बारे में चिंता करना आमतौर पर पहली बार में बेकार है। जब आप कुछ हज़ारों (या अधिक) आइटम को हैंडल करना शुरू करते हैं, तो बड़े ओ विचार केवल वास्तव में किक करते हैं।
कंटेनरों की दो बड़ी श्रेणियां हैं:
find
ऑपरेशन हैऔर फिर आप उनमें से शीर्ष पर कई एडेप्टर का निर्माण कर सकते हैं: stack
, queue
, priority_queue
। मैं यहां से एडाप्टरों को छोड़ दूंगा, वे पहचानने योग्य होने के लिए पर्याप्त रूप से विशिष्ट हैं।
प्रश्न 1: साहचर्य ?
प्रश्न 1.1: आदेश दिया गया ?
unordered_
कंटेनर का उपयोग करें, अन्यथा उसके पारंपरिक आदेश वाले समकक्ष का उपयोग करें।प्रश्न 1.2: अलग कुंजी ?
map
, अन्यथा a का उपयोग करेंset
प्रश्न १.३: नकल ?
multi
, अन्यथा नहीं।उदाहरण:
मान लीजिए कि मेरे पास कई लोग हैं, जिनके साथ एक विशिष्ट आईडी जुड़ी हुई है, और मैं अपनी आईडी से एक व्यक्ति के डेटा को यथाशीघ्र पुनः प्राप्त करना चाहूंगा।
मैं एक find
फ़ंक्शन चाहता हूं , इस प्रकार एक सहयोगी कंटेनर
1.1। मैं आदेश के बारे में कम परवाह नहीं कर सकता, इस प्रकार एक unordered_
कंटेनर
1.2। मेरी कुंजी (आईडी) उस मूल्य से अलग है जो इसके साथ जुड़ा हुआ है, इस प्रकार एmap
1.3। आईडी अद्वितीय है, इस प्रकार किसी डुप्लिकेट को रेंगना नहीं चाहिए।
अंतिम जवाब है: std::unordered_map<ID, PersonData>
।
प्रश्न 2: मेमोरी स्थिर ?
list
प्रश्न २.१: कौन सा ?
list
; ए forward_list
केवल कम स्मृति पदचिह्न के लिए उपयोगी है।प्रश्न 3: डायनामिक रूप से आकार ?
{ ... }
सिंटैक्स का उपयोग करके ) प्रदान कर सकते हैं , तो एक का उपयोग करें array
। यह पारंपरिक सी-सरणी की जगह लेता है, लेकिन सुविधाजनक कार्यों के साथ।प्रश्न 4: डबल-एंडेड ?
deque
, अन्यथा ए का उपयोग करें vector
।आप ध्यान दें कि, जब तक आपको एक सहयोगी कंटेनर की आवश्यकता नहीं होगी, तब तक आपकी पसंद ए होगी vector
। यह पता चला है कि यह सटर और स्ट्रॉस्ट्रुप की सिफारिश भी है ।
array
एक डिफ़ॉल्ट रचनात्मक प्रकार की आवश्यकता नहीं है; 2) उठा multi
रों इतना डुप्लिकेट के बारे में नहीं है किया जा रहा अनुमति लेकिन है कि क्या के बारे में अधिक रखने के लिए उन्हें मायने रखती है (आप गैर में डुप्लिकेट डाल सकते हैं multi
कंटेनरों, यह सिर्फ होता है कि केवल एक ही रखा जाता है)।
map.find(key)
तुलना में बहुत अधिक स्वादिष्ट है std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
, इसलिए यह महत्वपूर्ण है, शब्दार्थ से, यह find
एक से एक के बजाय एक सदस्य समारोह है <algorithm>
। ओ (1) बनाम ओ (लॉग एन) के लिए, यह शब्दार्थ को प्रभावित नहीं करता है; मैं उदाहरण से "कुशलतापूर्वक" निकालूंगा और इसे "आसानी से" से बदल दूंगा।
deque
कि यह संपत्ति भी थी?
deque
तत्वों स्थिर रहे हैं केवल यदि आप धक्का दोनों छोर पर / पॉप; यदि आप बीच में सम्मिलित करना / मिटाना शुरू करते हैं तो बनाए गए अंतर को भरने के लिए N / 2 तत्वों तक को बदल दिया जाता है।
मुझे मैथ्यू का जवाब पसंद है, लेकिन मैं फ्लोचार्ट को इस तरह से संशोधित करने जा रहा हूं:
डिफ़ॉल्ट रूप से, यदि आपको किसी सामान की आवश्यकता है, तो उपयोग करें std::vector
। इस प्रकार, हर दूसरे कंटेनर को केवल कुछ कार्यक्षमता विकल्प प्रदान करके उचित ठहराया जाता है std::vector
।
std::vector
इसके लिए आवश्यक है कि इसकी सामग्रियां मूव-कंस्ट्रक्टिव हों, क्योंकि इसके लिए आसपास की वस्तुओं को फेरबदल करने की आवश्यकता होती है। यह सामग्री पर जगह करने के लिए एक भयानक बोझ नहीं है (ध्यान दें कि डिफ़ॉल्ट बिल्डरों की आवश्यकता नहीं है , इसके लिए धन्यवाद emplace
और इसके बाद)। हालांकि, अधिकांश अन्य कंटेनरों को किसी विशेष निर्माता (फिर से, धन्यवाद emplace
) की आवश्यकता नहीं है । इसलिए यदि आपके पास एक ऐसी वस्तु है जहाँ आप बिल्कुल भी एक कदम निर्माता को लागू नहीं कर सकते हैं , तो आपको कुछ और चुनना होगा।
A std::deque
सामान्य प्रतिस्थापन होगा, जिसके कई गुण होंगे std::vector
, लेकिन आप केवल छल के दोनों सिरों पर सम्मिलित कर सकते हैं। बीच में आवेषण को हिलाने की आवश्यकता होती है। एक std::list
उसकी सामग्री पर कोई आवश्यकता देता है।
std::vector<bool>
नहीं है। खैर, यह मानक है। लेकिन यह vector
सामान्य अर्थों में नहीं है, क्योंकि std::vector
आम तौर पर अनुमति देने वाले संचालन निषिद्ध हैं। और यह सबसे निश्चित रूप से शामिल नहीं है bool
रों ।
इसलिए, यदि आपको एस के vector
कंटेनर से वास्तविक व्यवहार की आवश्यकता है, तो आप bool
इसे प्राप्त नहीं करेंगे std::vector<bool>
। तो आप एक के साथ बनाने के लिए होगा std::deque<bool>
।
यदि आपको एक कंटेनर में तत्वों को खोजने की आवश्यकता है, और खोज टैग केवल एक सूचकांक नहीं हो सकता है, तो आपको और के std::vector
पक्ष में त्यागने की आवश्यकता हो सकती है । कुंजी शब्द " हो सकता है " पर ध्यान दें ; एक क्रमबद्ध कभी-कभी एक उचित विकल्प होता है। या Boost.Container , जो एक छँटाई को लागू करता है ।set
map
std::vector
flat_set/map
std::vector
अब इनमें से चार विविधताएं हैं, जिनमें से प्रत्येक की अपनी आवश्यकताएं हैं।
map
जब खोज टैग का उपयोग उसी चीज़ के रूप में न हो, जिस आइटम को आप स्वयं ढूंढ रहे हैं। अन्यथा एक का उपयोग करें set
।unordered
जब आपके पास कंटेनर में बहुत सी वस्तुएं हैं और खोज प्रदर्शन बिल्कुल आवश्यक है O(1)
, बजाय O(logn)
।multi
यदि आपको एक ही खोज टैग के लिए कई वस्तुओं की आवश्यकता हो तो उपयोग करें ।यदि आपको किसी विशेष तुलना ऑपरेशन के आधार पर हमेशा वस्तुओं के एक कंटेनर की आवश्यकता होती है, तो आप एक का उपयोग कर सकते हैं set
। या multi_set
यदि आपको एक ही मूल्य के लिए कई वस्तुओं की आवश्यकता है।
या आप किसी सॉर्ट का उपयोग कर सकते हैं std::vector
, लेकिन आपको इसे क्रमबद्ध रखना होगा।
जब पुनरावृत्तियों और संदर्भों को अमान्य कर दिया जाता है तो कभी-कभी चिंता होती है। यदि आपको वस्तुओं की एक सूची की आवश्यकता है, जैसे कि आपके पास विभिन्न मदों में उन वस्तुओं के लिए पुनरावृत्तियाँ / संकेत हैं, तो std::vector
अमान्य होने का दृष्टिकोण उचित नहीं हो सकता है। कोई भी प्रविष्टि ऑपरेशन वर्तमान आकार और क्षमता के आधार पर अमान्य हो सकता है।
std::list
एक फर्म गारंटी प्रदान करता है: एक इट्रेटर और उसके संबंधित संदर्भ / पॉइंटर्स केवल तभी अमान्य होते हैं जब आइटम को कंटेनर से निकाल दिया जाता है। std::forward_list
वहाँ है अगर स्मृति एक गंभीर चिंता का विषय है।
यदि यह बहुत मजबूत है, तो std::deque
एक कमजोर लेकिन उपयोगी गारंटी प्रदान करता है। बीच में सम्मिलन से अमान्य परिणाम प्राप्त होते हैं, लेकिन सिर या पूंछ पर सम्मिलन केवल पुनरावृत्तियों के अमान्यकरण का कारण बनता है , न कि कंटेनर में आइटम के संकेत / संदर्भ।
std::vector
केवल अंत में सस्ते प्रविष्टि प्रदान करता है (और फिर भी, यह महंगा हो जाता है यदि आप क्षमता उड़ाते हैं)।
std::list
प्रदर्शन के मामले में महंगा है (प्रत्येक नए सम्मिलित आइटम में एक मेमोरी आवंटन लागत है), लेकिन यह सुसंगत है । यह वस्तुतः बिना किसी प्रदर्शन लागत के साथ-साथ वस्तुओं के फेरबदल की अपरिहार्य क्षमता भी प्रदान करता है, साथ ही साथ std::list
प्रदर्शन के किसी भी नुकसान में उसी प्रकार के अन्य कंटेनरों के साथ वस्तुओं का व्यापार करता है। अगर आपको बहुत सी चीजों को इधर-उधर करने की जरूरत है , तो उपयोग करें std::list
।
std::deque
सिर और पूंछ पर निरंतर-समय सम्मिलन / निष्कासन प्रदान करता है, लेकिन बीच में सम्मिलन काफी महंगा हो सकता है। इसलिए यदि आपको सामने से और पीछे से चीजों को जोड़ने / हटाने की जरूरत है, तो std::deque
हो सकता है कि आपको क्या चाहिए।
यह ध्यान दिया जाना चाहिए कि, शब्दार्थ को स्थानांतरित करने के लिए धन्यवाद, std::vector
सम्मिलन का प्रदर्शन उतना बुरा नहीं हो सकता है जितना पहले हुआ करता था। कुछ कार्यान्वयनों ने मूवमेंट-आधारित आइटम कॉपी (तथाकथित "स्वैप्टिमाइज़ेशन") के एक रूप को लागू किया, लेकिन अब यह चलती भाषा का हिस्सा है, यह मानक द्वारा अनिवार्य है।
std::array
यदि आप सबसे कम संभव गतिशील आवंटन चाहते हैं तो एक अच्छा कंटेनर है। यह सी-एरे के चारों ओर केवल एक आवरण है; इसका अर्थ है कि इसका आकार संकलन-समय पर ज्ञात होना चाहिए । यदि आप उस के साथ रह सकते हैं, तो उपयोग करें std::array
।
कहा जा रहा है, एक आकार का उपयोग std::vector
और reserve
आईएनजी बस के रूप में अच्छी तरह से एक बंधे के लिए काम करेगा std::vector
। इस तरह, वास्तविक आकार अलग-अलग हो सकता है, और आपको केवल एक मेमोरी आवंटन मिलता है (जब तक कि आप क्षमता को नहीं उड़ाते)।
std::sort
, वहाँ भी है std::inplace_merge
जो आसानी से नए तत्व (बजाय एक से जगह दिलचस्प है std::lower_bound
+ std::vector::insert
कॉल)। flat_set
और के बारे में जानकर अच्छा लगा flat_map
!
vector<bool>
है vector<char>
।
std::allocator<T>
वह संरेखण का समर्थन नहीं करता है (और मुझे नहीं पता कि यह क्यों नहीं होगा), तो आप हमेशा अपने स्वयं के कस्टम आवंटनकर्ता का उपयोग कर सकते हैं।
std::vector::resize
एक अधिभार है जो एक मान नहीं लेता है (यह सिर्फ नए आकार लेता है; कोई भी नए तत्व डिफ़ॉल्ट रूप से इन-प्लेस होंगे)। इसके अलावा, कंपाइलर वैल्यू पैरामीटर को ठीक से अलाइन करने में असमर्थ क्यों होते हैं, तब भी जब वे उस एलाइनमेंट के लिए घोषित किए जाते हैं।
bitset
बूल के लिए यदि आप अग्रिम में आकार जानते हैं। en.cppreference.com/w/cpp/utility/bitset
यहाँ उपरोक्त फ्लोचार्ट का C ++ 11 संस्करण है। [मूल लेखक के बिना मूल रूप से पोस्ट किए गए, मिकेल पर्ससन ]
यहां एक त्वरित स्पिन है, हालांकि इसे शायद काम की जरूरत है
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
आप देख सकते हैं कि यह C ++ 03 संस्करण से बेतहाशा भिन्न है , मुख्य रूप से इस तथ्य के कारण कि मुझे वास्तव में लिंक किए गए नोड्स पसंद नहीं हैं। लिंक किए गए नोड कंटेनर आमतौर पर गैर-लिंक किए गए कंटेनर द्वारा प्रदर्शन में हराया जा सकता है, कुछ दुर्लभ स्थितियों को छोड़कर। यदि आपको नहीं पता कि वे परिस्थितियां क्या हैं, और बढ़ावा देने के लिए उपयोग किया है, तो लिंक किए गए नोड कंटेनरों का उपयोग न करें। (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset)। यह सूची ज्यादातर छोटे और मध्यम पक्षीय कंटेनरों पर केंद्रित है, क्योंकि (ए) यह 99.99% है जो हम कोड में व्यवहार करते हैं, और (बी) बड़ी संख्या में तत्वों को अलग-अलग कंटेनरों की नहीं बल्कि कस्टम एल्गोरिदम की आवश्यकता होती है।