किस परिदृश्य में मैं एक विशेष एसटीएल कंटेनर का उपयोग करता हूं?


184

मैं अपनी पुस्तक में C ++ पर STL कंटेनरों पर पढ़ रहा हूं, विशेष रूप से STL और उसके कंटेनरों पर अनुभाग। अब मुझे समझ में आया है कि उनमें से हर एक के अपने विशिष्ट गुण हैं, और मैं उन सभी को याद करने के करीब हूं ... लेकिन जो मैं अभी तक समझ नहीं पाया हूं, उनमें से प्रत्येक का उपयोग किस परिदृश्य में किया जाता है।

स्पष्टीकरण क्या है? उदाहरण कोड ज्यादा पसंद किया जाता है।


क्या आपका मतलब है नक्शा, वेक्टोट, सेट आदि?
थॉमस टेम्पेलमैन

यहां तक कि इस चित्र को देखकर मैं नहीं कह सकता कि सबसे अच्छा मेरी quastion में उपयोग करने के लिए एक हो जाएगा stackoverflow.com/questions/9329011/...
sergiol

2
@sbi: इस से C ++ फ़ेक टैग को हटाकर इसे और हाल ही में और C ++ 11 में शामिल किया जा सकता है मैं C ++ 11 में एक मानक पुस्तकालय कंटेनर का कुशलता से चयन कैसे कर सकता हूं?
आलोक सेव

जवाबों:


336

यह धोखा पत्र विभिन्न कंटेनरों का एक बहुत अच्छा सारांश प्रदान करता है।

विभिन्न उपयोग परिदृश्यों में उपयोग करने के लिए एक गाइड के रूप में तल पर फ्लोचार्ट देखें:

http://linuxsoftware.co.nz/containerchoice.png

डेविड मूर द्वारा बनाया गया और CC BY-SA 3.0 को लाइसेंस दिया गया


14
यह फ्लोचार्ट सुनहरा है, काश मेरे पास कुछ ऐसा होता जैसे कि c #
Bruno


3
प्रारंभिक बिंदु vectorबल्कि खाली होना चाहिए । stackoverflow.com/questions/10699265/…
eonil

5
आपके पास अब unordered_mapऔर unordered_set(और उनके बहु प्रकार) हैं जो प्रवाह चार्ट में नहीं हैं, लेकिन जब आप ऑर्डर के बारे में परवाह नहीं करते हैं, तो अच्छे चयन होते हैं, लेकिन कुंजी द्वारा तत्वों को खोजने की आवश्यकता होती है। उनकी खोज आमतौर पर O (1) के बजाय O (1) है।
ऐड़ीकापी

2
@ शटल87 न केवल उस आकार में कभी भी भिन्न नहीं होगा, बल्कि इससे भी महत्वपूर्ण बात यह है कि आकार संकलन समय पर निर्धारित किया जाता है और कभी भी भिन्न नहीं होगा।
यंगजॉन

188

यहां डेविड मूर के संस्करण (ऊपर देखें) से प्रेरित एक फ्लोचार्ट है जो मैंने बनाया था, जो नए मानक (सी ++ 11) के साथ अप-टू-डेट (ज्यादातर) है। यह केवल मेरा व्यक्तिगत लेना है, यह निर्विवाद नहीं है, लेकिन मुझे लगा कि यह इस चर्चा के लिए मूल्यवान हो सकता है:

यहां छवि विवरण दर्ज करें


4
क्या आप मूल उपलब्ध करा सकते हैं? यह एक उत्कृष्ट चार्ट है। शायद एक ब्लॉग या GitHub पर छड़ी?
केविनरपे

1
यह एक उत्कृष्ट चार्ट है। हालांकि कोई मुझे समझा सकता है कि 'लगातार पदों' से क्या मतलब है?
IDDQD

3
@STAL लगातार स्थिति का अर्थ है कि यदि आपके पास कंटेनर में एक तत्व के लिए एक सूचक या पुनरावृत्ति है, तो वह सूचक या पुनरावृत्ति (या उसी तत्व को इंगित करते हुए) मान्य रहेगा जो आप कंटेनर से जोड़ते या हटाते हैं (जब तक कि वह इसके अनुसार नहीं है) प्रश्न में तत्व नहीं है)।
मिकेल पर्सन

1
यह वास्तव में एक शानदार चार्ट है, हालांकि मुझे लगता vector (sorted)है कि बाकी के साथ थोड़ा असंगत है। यह एक अलग प्रकार का कंटेनर नहीं है, बस एक ही है std::vectorलेकिन इसे क्रमबद्ध किया गया है। इससे भी अधिक महत्वपूर्ण, मैं यह नहीं देखता कि एक std::setआदेशित पुनरावृत्ति के लिए कोई उपयोग क्यों नहीं कर सकता है यदि यह एक सेट गर्त को पुनरावृत्त करने का मानक व्यवहार है। यकीन है, अगर उत्तर कंटेनर कुंड के मूल्यों तक पहुँचने के बारे में बात कर रहा है [], तो ठीक है, आप केवल एक बोए गए के साथ कर सकते हैं std::vector। लेकिन या तो मामले में, निर्णय "आदेश की आवश्यकता है" सवाल के बाद ही किया जाना चाहिए
रास

1
@ user2019840 मैं मानक कंटेनरों के चार्ट को प्रतिबंधित करना चाहता था। "सॉर्ट किए गए वेक्टर" के स्थान पर क्या दिखाई देना चाहिए "फ्लैट_सेट" ( बूस्ट.कॉनटेनर से ), या समतुल्य है (प्रत्येक प्रमुख पुस्तकालय या कोड-बेस में एक फ्लैट_सेट समकक्ष, एएफएआईके है)। लेकिन ये गैर-मानक हैं, और एसटीएल से काफी चमकदार चूक है। और यही कारण है कि आप std :: set या std :: map (कम से कम बार-बार नहीं) के माध्यम से पुनरावृति नहीं करना चाहते हैं, ऐसा करने के लिए यह बहुत अक्षम है
मिकेल पर्सन

42

सरल उत्तर: std::vectorसब कुछ के लिए उपयोग करें जब तक कि आपके पास अन्यथा करने का वास्तविक कारण न हो।

जब आप एक ऐसा मामला पाते हैं जहां आप सोच रहे हैं, "जी, std::vectorएक्स की वजह से यहां अच्छा काम नहीं करता है", एक्स के आधार पर जाएं।


1
हालाँकि .. सावधान रहें कि आइटम्स को डिलीट / इंसर्ट करते समय न डालें ... इससे बचने के लिए जहाँ तक हो सके कॉन्स्टिटर का उपयोग करें ..
vrdhn

11
हम्म ... मुझे लगता है कि लोग वेक्टर का उपयोग कर रहे हैं। कारण यह है, कि "काम नहीं करता है" -केस आसानी से नहीं होगा - इसलिए लोग सबसे अधिक इस्तेमाल किए जाने वाले कंटेनर से चिपके रहते हैं और सूची, कतारों के लिए इसका दुरुपयोग करते हैं, ... मेरे उत्पीड़न में - जो फ्लोचार्ट से मेल खाता है - एक को "सभी को फिट लगता है" लागू करने के बजाय इच्छित उपयोग के आधार पर कंटेनर चुनना चाहिए।
काला

13
@ ब्लेक प्वाइंट है, वेक्टर आमतौर पर ऑपरेशन पर भी तेज होता है जो सिद्धांत में धीमी गति से काम करना चाहिए।
बार्टेक बानाचेविज़

1
@Vardhan std::remove_ifलगभग हमेशा "पुनरावृति के दौरान हटाएं" दृष्टिकोण से बेहतर है।
fredoverflow

1
कुछ बेंचमार्क वास्तव में इस चर्चा को कम व्यक्तिपरक बनाने में मदद करेंगे।
फेलिक्स डी।

11

स्कॉट मेयर्स द्वारा प्रभावी STL को देखें। यह समझाने में अच्छा है कि एसटीएल का उपयोग कैसे किया जाए।

यदि आप वस्तुओं की एक निर्धारित / अनिर्धारित संख्या को संग्रहीत करना चाहते हैं और आप कभी भी किसी को हटाने नहीं जा रहे हैं, तो एक वेक्टर वह है जो आप चाहते हैं। यह सी सरणी के लिए डिफ़ॉल्ट प्रतिस्थापन है, और यह एक की तरह काम करता है, लेकिन अतिप्रवाह नहीं करता है। आप इसका आकार पहले से आरक्षित () के साथ निर्धारित कर सकते हैं।

यदि आप एक अनिर्धारित संख्या की वस्तुओं को संग्रहीत करना चाहते हैं, लेकिन आप उन्हें जोड़ रहे हैं और उन्हें हटा रहे हैं, तो आप शायद एक सूची चाहते हैं ... क्योंकि आप किसी भी निम्नलिखित तत्वों को स्थानांतरित किए बिना एक तत्व को हटा सकते हैं - वेक्टर के विपरीत। यह एक वेक्टर की तुलना में अधिक मेमोरी लेता है, हालांकि, और आप क्रमिक रूप से एक तत्व तक नहीं पहुंच सकते हैं।

यदि आप तत्वों का एक गुच्छा लेना चाहते हैं और उन तत्वों के केवल अद्वितीय मूल्यों को ढूंढना चाहते हैं, तो उन सभी को एक सेट में पढ़ना यह कर देगा, और यह उन्हें आपके लिए भी छाँटेगा।

यदि आपके पास बहुत सारे कुंजी-मूल्य जोड़े हैं, और आप उन्हें कुंजी द्वारा सॉर्ट करना चाहते हैं, तो एक मानचित्र उपयोगी है ... लेकिन यह केवल प्रति कुंजी एक मान रखेगा। यदि आपको प्रति कुंजी एक से अधिक मान की आवश्यकता है, तो आपके पास नक्शे में आपके मूल्य के रूप में एक वेक्टर / सूची हो सकती है, या एक मल्टीमैप का उपयोग कर सकता है।

यह एसटीएल में नहीं है, लेकिन यह एसटीएल के लिए टीआर 1 अपडेट में है: यदि आपके पास बहुत सारे कुंजी-मूल्य जोड़े हैं जो आप कुंजी द्वारा देखने जा रहे हैं, और आप उनके आदेश की परवाह नहीं करते हैं, तो आप हो सकते हैं एक हैश का उपयोग करना चाहते हैं - जो tr1 :: unordered_map है। मैंने इसे विजुअल C ++ 7.1 के साथ उपयोग किया है, जहां इसे stdext :: hash_map कहा गया। इसमें नक्शे के लिए O (log n) के लुक के बजाय O (1) का लुकअप है।


मैंने कुछ उपाख्यानों के बारे में सुना है जो यह बताता है कि Microsoft का hash_mapबहुत अच्छा कार्यान्वयन नहीं है। मुझे उम्मीद है कि उन्होंने बेहतर प्रदर्शन किया unordered_map
मार्क रैनसम

3
सूचियों की - "आप क्रमिक रूप से किसी तत्व तक नहीं पहुँच सकते।" - मुझे लगता है कि आप का मतलब है कि आप किसी तत्व पर रैंडम-एक्सेस या इंडेक्स को सीधे नहीं कर सकते हैं ....
टोनी डेलरॉय

^ हां, क्योंकि अनुक्रमिक पहुंच ठीक है कि क्या listकरता है। बल्कि वहाँ चमक त्रुटि।
अंडरस्कोर_ड

7

मैंने 3 गुण होने के लिए फ़्लोचार्ट को फिर से डिज़ाइन किया:

  1. मुझे लगता है कि एसटीएल कंटेनर 2 मुख्य वर्गों के लिए तैयार हैं। मूल कंटेनर और उन मूल कंटेनरों का लाभ उठाते हैं जो एक नीति को लागू करते हैं।
  2. पहले फ्लोचार्ट को निर्णय प्रक्रिया को उन मुख्य स्थितियों में विभाजित करना चाहिए जिन पर हमें निर्णय लेना चाहिए और फिर प्रत्येक मामले पर विस्तार से बताना चाहिए।
  3. कुछ विस्तारित कंटेनरों में उनके आंतरिक कंटेनर के रूप में विभिन्न बुनियादी कंटेनर चुनने की संभावना है। फ़्लोचार्ट उन स्थितियों पर विचार करना चाहिए जिनमें प्रत्येक मूल कंटेनर का उपयोग किया जा सकता है।

फ़्लोचार्ट: यहां छवि विवरण दर्ज करें

अधिक जानकारी इस लिंक में दी गई है


5

एक महत्वपूर्ण बात केवल कुछ समय अब तक उल्लेख किया है, कि यदि आप सन्निहित स्मृति की आवश्यकता होती है (जैसे एक सी सरणी देता है), तो आप केवल उपयोग कर सकते हैं vector, arrayया string

arrayयदि संकलन समय पर आकार ज्ञात हो तो उपयोग करें ।

उपयोग करें stringयदि आपको केवल चरित्र प्रकारों के साथ काम करने की आवश्यकता है और न केवल एक सामान्य-उद्देश्य वाले कंटेनर की आवश्यकता है।

vectorअन्य सभी मामलों में उपयोग करें ( vectorवैसे भी अधिकांश मामलों में कंटेनर का डिफ़ॉल्ट विकल्प होना चाहिए)।

इन तीनों के साथ आप data()कंटेनर के पहले तत्व को पॉइंटर प्राप्त करने के लिए सदस्य फ़ंक्शन का उपयोग कर सकते हैं ।


3

यह सब इस बात पर निर्भर करता है कि आप क्या स्टोर करना चाहते हैं और कंटेनर के साथ क्या करना चाहते हैं। यहाँ कंटेनर वर्गों के लिए कुछ (बहुत गैर-थकाऊ) उदाहरण दिए गए हैं जिनका मैं सबसे अधिक उपयोग करता हूं:

vector: सम्‍मिलित ऑब्जेक्ट के साथ बहुत कम या कोई मेमोरी ओवरहेड वाला कॉम्पैक्ट लेआउट। इसे खत्म करने के लिए कुशल। विशेष रूप से जटिल वस्तुओं के लिए परिशिष्ट डालना, सम्मिलित करना और मिटाना महंगा हो सकता है। सूचकांक द्वारा निहित वस्तु को खोजने के लिए सस्ता, जैसे myVector [10]। जहाँ आप सी। में एक सरणी का उपयोग किया होगा अच्छा जहाँ आप बहुत सी साधारण वस्तुओं (जैसे int) है। reserve()कंटेनर में बहुत सारी वस्तुओं को जोड़ने से पहले उपयोग करना न भूलें ।

list: छोटी मेमोरी ओवरहेड प्रति निहित वस्तु। इसे खत्म करने के लिए कुशल। परिशिष्ट, सम्मिलित करना और मिटाना सस्ता है। जहाँ आपने C में लिंक्ड लिस्ट का इस्तेमाल किया होगा, वहां इस्तेमाल करें।

set(और multiset): निहित ऑब्जेक्ट के प्रति महत्वपूर्ण स्मृति ओवरहेड। उस कंटेनर का उपयोग करें जहाँ आपको यह पता लगाने की आवश्यकता है कि उस कंटेनर में कोई वस्तु दी गई है, या कंटेनर को कुशलता से मर्ज करें।

map(और multimap): निहित ऑब्जेक्ट के प्रति महत्वपूर्ण स्मृति ओवरहेड। उपयोग करें जहाँ आप कुंजी-मूल्य जोड़े जमा करना चाहते हैं और कुंजी द्वारा मूल्यों को जल्दी से देखना चाहते हैं।

Zdan द्वारा सुझाए गए धोखा पत्र पर प्रवाह चार्ट एक अधिक संपूर्ण गाइड प्रदान करता है।


"स्मॉल मेमोरी ओवरहेड प्रति समाहित ऑब्जेक्ट" सूची के लिए सही नहीं है। std :: सूची को दोगुनी लिंक की गई सूची के रूप में लागू किया जाता है और इसलिए यह प्रति संग्रहीत वस्तु पर 2 सूचक रखता है जो कि उपेक्षा नहीं है।
हन्ना खलील

मैं अभी भी प्रति संग्रहीत ऑब्जेक्ट के दो बिंदुओं को "छोटा" के रूप में गिनूंगा।
बोलियां

की तुलना में क्या? std :: Forward_list एक कंटेनर है जिसे मुख्य रूप से प्रति वस्तु (केवल एक सूचक) में कम मेटा-डेटा संग्रहीत करने का सुझाव दिया गया था। जबकि std :: वेक्टर प्रति वस्तु में 0 मेटा डेटा रखता है। तो 2 पॉइंटर्स अन्य कंटेनरों की तुलना में परक्राम्य नहीं है
हन्ना खलील

यह सब आपकी वस्तुओं के आकार पर निर्भर करता है। मैंने पहले ही कहा है कि वेक्टर में "कम वस्तु के साथ बहुत कम या कोई मेमोरी ओवरहेड के साथ कॉम्पैक्ट लेआउट" है। मैं अभी भी कहूंगा कि सेट और नक्शे की तुलना में सूची में एक छोटी मेमोरी ओवरहेड है और वेक्टर की तुलना में थोड़ी बड़ी मेमोरी है। मुझे यकीन नहीं है कि आप किस बिंदु पर टीबीएच बनाने की कोशिश कर रहे हैं!
बोलियां

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

2

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

class CollectionOfFoo {
    Collection<Foo*> foos;
    .. delegate methods specifically 
}

यह सामने वाले को ज्यादा खर्च नहीं करता है, और जब भी आप किसी को इस संरचना पर एक्स संचालन करना चाहते हैं, तो डिबगिंग में समय बचाता है।

एक नौकरी के लिए सही डेटा संरचना का चयन करने के लिए आ रहा है:

प्रत्येक डेटा संरचना कुछ संचालन प्रदान करती है, जो कि समय जटिलता भिन्न हो सकती है:

O (1), O (lg N), O (N), आदि।

आपको अनिवार्य रूप से एक सर्वश्रेष्ठ अनुमान लेना होगा, जिस पर संचालन सबसे अधिक किया जाएगा, और एक डेटा संरचना का उपयोग करें जिसमें ओ (1) के रूप में वह ऑपरेशन है।

सरल, यह नहीं है (-:


5
क्या यह क्यों हम पुनरावृत्तियों का उपयोग नहीं करते हैं?
प्लैटिनम एज़्योर

@Pl PlatinumAzure यहां तक ​​कि पुनरावृत्तियों को सदस्य टाइपफेड होना चाहिए .. यदि आप कंटेनर प्रकार बदलते हैं, तो आपको भी जाना होगा और सभी पुनरावृत्त परिभाषाओं को बदलना होगा ... हालांकि यह c ++ 1x में ठीक हो गया है!
व्रध्न

4
जिज्ञासु के लिए, यह C ++ 11 में फिक्स है: auto myIterator = whateverCollection.begin(); // <-- immune to changes of container type
ब्लैक अप

1
typedef Collection<Foo*> CollectionOfFoo;पर्याप्त होगा ?
क्रेग मैकक्वीन

5
यह काफी संभावना नहीं है कि आप बाद में अपना दिमाग बदल सकते हैं और बस एक अलग कंटेनर में रख सकते हैं: कंटेनर-स्वतंत्र कोड के भ्रम से सावधान रहें
fredoverflow

1

मैंने मिकेल पर्सन के शानदार फ्लोचार्ट पर विस्तार किया । मैंने कुछ कंटेनर श्रेणियां, सरणी कंटेनर और कुछ नोट्स जोड़े। यदि आप अपनी स्वयं की प्रतिलिपि चाहते हैं, तो यहां Google आरेखण है। धन्यवाद, ग्राउंडवर्क करने के लिए मिकेल! सी ++ कंटेनर पिकर


1

मैंने इसका उत्तर एक अन्य प्रश्न में दिया, जिसे इस एक के रूप में चिह्नित किया गया है। लेकिन मुझे लगता है कि एक मानक कंटेनर चुनने के निर्णय के बारे में कुछ अच्छे लेखों को संदर्भित करना अच्छा है।

जैसा कि @ डेविड थॉर्ले ने उत्तर दिया, std :: वेक्टर एक ऐसा तरीका है यदि कोई अन्य विशेष आवश्यकताएं नहीं हैं। यह 2014 के ब्लॉग में C ++ के निर्माता, बज़्ने स्ट्रॉस्ट्रुप द्वारा दी गई सलाह है।

यहां लेख https://isocpp.org/blog/2014/06/stroustrup-lists के लिए लिंक दिया गया है

और उस एक से बोली,

और, हां, मेरी सिफारिश डिफ़ॉल्ट रूप से std :: वेक्टर का उपयोग करने की है।

टिप्पणियों में, उपयोगकर्ता @NathanOliver भी एक और अच्छा ब्लॉग प्रदान करता है, जिसमें अधिक ठोस माप हैं। https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.