मैं वेक्टर का उपयोग छल के लिए क्यों करना पसंद करूंगा


86

जबसे

  1. वे दोनों सन्निहित मेमोरी कंटेनर हैं;
  2. बुद्धिमान के रूप में, deque में लगभग सब कुछ वेक्टर है, लेकिन अधिक है, क्योंकि यह सामने से सम्मिलित करने के लिए अधिक कुशल है।

क्यों किसी को भी पसंद करते std::vectorहैं std::deque?


2
विजुअल C ++ के कार्यान्वयन में std::dequeबहुत छोटा अधिकतम ब्लॉक आकार है (~ 16 बाइट्स, अगर मुझे सही याद है; शायद 32), और जैसे कि यथार्थवादी अनुप्रयोगों के लिए बहुत अच्छा प्रदर्शन नहीं करता है। एक deque<T>जहां sizeof(T) > 8(या 16? यह एक छोटी संख्या है) एक के रूप में ही प्रदर्शन विशेषताओं के बारे में है vector<T*>, जहां प्रत्येक तत्व गतिशील आवंटित किया जाता है। अन्य कार्यान्वयन में अलग-अलग अधिकतम ब्लॉक आकार होते हैं, इसलिए विभिन्न प्लेटफार्मों पर अपेक्षाकृत समान प्रदर्शन विशेषताओं वाले कोड लिखना मुश्किल होता है deque
जेम्स मैकनेलिस

12
Deque एक निरंतर मेमोरी कंटेनर नहीं है।
मोहम्मद अल-नकिब

इस सवाल पर इशारा करते हुए @ravil नहीं, वह डुप्लिकेट है।

1
एक विश्वासघाती असंतुष्ट तथ्यात्मक त्रुटि के साथ एक प्रश्न पर विश्वास करना मुश्किल था, 34 वोटों के संतुलन पर बैठा था
अंडरस्कोर_ड

2
@underscore_d यही कारण है कि यह एक सवाल है। अलग कहानी अगर यह एक जवाब था;)
एसिमिलाटर

जवाबों:


115

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

इसके अलावा, जैसा कि स्टैकऑवरफ्लो पर कहीं और बताया गया है , यहाँ और भी अच्छी चर्चा है: http://www.gotw.ca/gotw/054.htm


3
ऐसा प्रतीत होता है कि "कहीं और" का लिंक अब मर चुका है (मॉडरेशन के कारण?)।
एस्किल करें

37

अंतर जानने के लिए पता होना चाहिए कि dequeआम तौर पर कैसे लागू किया जाता है। मेमोरी को समान आकारों के ब्लॉकों में आवंटित किया जाता है, और वे एक साथ जंजीर (एक सरणी या संभवतः एक वेक्टर के रूप में) होते हैं।

तो nth तत्व को खोजने के लिए, आप उपयुक्त ब्लॉक को खोजते हैं और फिर उसके भीतर के तत्व को एक्सेस करते हैं। यह निरंतर समय है, क्योंकि यह हमेशा 2 लुकअप होता है, लेकिन यह अभी भी वेक्टर से अधिक है।

vectorएपीआई के साथ भी अच्छी तरह से काम करता है जो एक सन्निहित बफर चाहते हैं क्योंकि वे या तो सी एपीआई हैं या एक पॉइंटर और लंबाई लेने में सक्षम होने में अधिक बहुमुखी हैं। (इस प्रकार आप एक वेक्टर के नीचे या एक नियमित सरणी रख सकते हैं और अपने मेमोरी ब्लॉक से एपीआई कॉल कर सकते हैं)।

dequeइसके सबसे बड़े फायदे कहां हैं:

  1. जब दोनों छोर से संग्रह बढ़ रहा है या सिकुड़ रहा है
  2. जब आप बहुत बड़े संग्रह आकारों के साथ काम कर रहे हों।
  3. जब बूल के साथ काम करते हैं और आप वास्तव में एक बिटसेट के बजाय बूल चाहते हैं।

इनमें से दूसरा कम ज्ञात है, लेकिन बहुत बड़े संग्रह के आकार के लिए:

  1. वसूली की लागत बड़ी है
  2. एक सन्निहित मेमोरी ब्लॉक को खोजने का ओवरहेड प्रतिबंधात्मक है, जिससे आप मेमोरी से तेजी से बाहर निकल सकते हैं।

जब मैं अतीत में बड़े संग्रह के साथ काम कर रहा था और एक सन्निहित मॉडल से ब्लॉक मॉडल में चला गया, तो हम 32-बिट सिस्टम में मेमोरी से बाहर भाग जाने से पहले लगभग 5 गुना बड़े संग्रह को स्टोर करने में सक्षम थे। यह आंशिक रूप से है, क्योंकि जब पुन: आवंटन होता है, तो वास्तव में पुराने ब्लॉक को संग्रहीत करने की आवश्यकता होती है और तत्वों को कॉपी करने से पहले नया भी होता है।

यह सब कहने के बाद, आप उन std::dequeसिस्टम पर मुसीबत में पड़ सकते हैं जो "आशावादी" मेमोरी आवंटन का उपयोग करते हैं। vectorवसीयत के पुन: आवंटन के लिए एक बड़े बफर आकार का अनुरोध करने के अपने प्रयासों के बावजूद , शायद कुछ के साथ एक बिंदु पर अस्वीकार कर दिया जाएगा bad_alloc, आवंटनकर्ता की आशावादी प्रकृति हमेशा एक ए के द्वारा अनुरोध किए गए छोटे बफर के लिए अनुरोध देने की dequeसंभावना है और इसके कारण होने की संभावना है ऑपरेटिंग सिस्टम कुछ मेमोरी प्राप्त करने की कोशिश करने के लिए एक प्रक्रिया को मारने के लिए। जो भी इसे चुनता है वह बहुत सुखद नहीं हो सकता है।

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


29

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

यदि आपको एक डबल एंडेड कतार की आवश्यकता है, तो डीक स्पष्ट विजेता है। लेकिन अगर आप अपने अधिकांश आवेषण कर रहे हैं और पीछे हट रहे हैं, तो वेक्टर स्पष्ट विजेता बनने जा रहा है। जब आप अनिश्चित हो जाते हैं, तो अपने कंटेनर को एक टाइपडिफ के साथ घोषित करें (ताकि आगे और पीछे स्विच करना आसान हो), और माप करें।


3
प्रश्न - क्या समिति ने दोनों के हाइब्रिड (जैसे, "डेक") को C ++ में जोड़ने पर विचार किया है? (यानी एक डबल-एंडेड vector।) मैंने अपने जवाब में नीचे से जुड़ा एक कार्यान्वयन लिखा है । यह उतनी ही तेजी से हो सकता है, vectorलेकिन बहुत अधिक व्यापक रूप से लागू (जैसे, तेज कतार बनाते समय)।
user541686

5

std::dequeनिरंतर मेमोरी की गारंटी नहीं है - और यह अक्सर अनुक्रमित पहुंच के लिए कुछ धीमा है। एक छलावा को आमतौर पर "वेक्टर की सूची" के रूप में लागू किया जाता है।


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

2

Http://www.cplusplus.com/reference/stl/deque/ के अनुसार , "वैक्टर के विपरीत, देवताओं को सन्निहित भंडारण स्थानों में अपने सभी तत्वों को रखने की गारंटी नहीं है, इस प्रकार सूचक अंकगणित के माध्यम से सुरक्षित पहुंच की संभावना समाप्त हो जाती है।"

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

(पहले, मेरे जवाब में मानकीकरण की कमी थी (ऊपर से उसी स्रोत से, "विशिष्ट पुस्तकालयों द्वारा विभिन्न तरीकों से देवताओं को लागू किया जा सकता है"), लेकिन यह वास्तव में किसी भी मानक पुस्तकालय डेटा प्रकार के बारे में लागू होता है।)


5
std::dequeसे कम मानकीकृत नहीं है std::vector। मेरा मानना ​​है कि जटिल आवश्यकताओं को जटिल std::dequeभंडारण से पूरा किया जा सकता है।
जेरी कॉफ़िन

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

1
@ जेरी कॉफ़िन: dequeसन्निहित भंडारण के साथ कौन सी जटिलता आवश्यकताओं को पूरा नहीं किया जा सकता है?
user541686

1
@ मेहरदाद: ईमानदार होने के लिए, मुझे याद नहीं है कि मेरे मन में क्या था। मैंने हाल ही में मानक के उस हिस्से को पर्याप्त रूप से देखा नहीं है कि मैं स्पष्ट रूप से यह बताते हुए सहज महसूस करता हूं कि मेरी पूर्व टिप्पणी गलत थी, लेकिन अभी इसे देखते हुए, मैं यह नहीं सोच सकता कि यह कैसे सही होगा।
जेरी कॉफिन

3
@ जेरेकॉफिन: जटिलता की आवश्यकताएं वास्तव में तुच्छ हैं: आप एक बड़े सरणी को आवंटित कर सकते हैं और अपने अनुक्रम को मध्य से बाहर की ओर धकेलना शुरू कर सकते हैं (मुझे लगता है कि यह मेहरदाद कार्यान्वयन क्या करता है), फिर समाप्त होने पर प्राप्त करें। इस दृष्टिकोण के साथ समस्या यह है कि यह आवश्यकताओं में से एक को संतुष्ट नहीं करता है deque, अर्थात् सिरों पर सम्मिलन मौजूदा तत्वों को संदर्भित नहीं करेगा । इस आवश्यकता का तात्पर्य है बंद स्मृति।
याकोव गल्का

0

एक छल एक अनुक्रम कंटेनर है जो इसके तत्वों को यादृच्छिक रूप से एक्सेस करने की अनुमति देता है लेकिन सन्निहित भंडारण की गारंटी नहीं है।


0

मुझे लगता है कि प्रत्येक मामले का सही परीक्षण करने के लिए अच्छा विचार है। और इस परीक्षण पर भरोसा करने का निर्णय लें।

मैं पसंद करते हैं std::dequeकी तुलना में std::vectorज्यादातर मामलों में।


1
प्रश्न, यदि कोई भी तथ्यात्मक त्रुटियों और लापता शब्दों के बीच से आसुत हो सकता है, तो कोई क्यों पसंद करेगा vector। हम यह अनुमान लगा सकते हैं कि कोरोलरी क्यों नहीं है। यह कहना कि आप dequeअनिर्दिष्ट परीक्षणों से, अज्ञात कारणों से, पसंद करते हैं , एक उत्तर नहीं है।
अंडरस्कोर_ड

0

आप इन परीक्षण परिणामों (स्रोत के साथ) को रिकॉर्ड करने के लिए वेक्टर को बहाना पसंद नहीं करेंगे

बेशक, आपको अपने ऐप / वातावरण में परीक्षण करना चाहिए, लेकिन सारांश में:

  • push_back मूल रूप से सभी के लिए समान है
  • सम्मिलित करें, मिटाने में मिटाएँ सूची की तुलना में बहुत तेज़ हैं और वेक्टर की तुलना में थोड़ी तेज़ी से

कुछ और musings, और परिपत्र_बफर पर विचार करने के लिए एक नोट।


0

एक तरफ, सदिश काफी अक्सर सादा है, जो छल से तेज है। यदि आपको वास्तव में छल की सभी विशेषताओं की आवश्यकता नहीं है, तो वेक्टर का उपयोग करें।

दूसरी ओर, कभी-कभी आपको ऐसे फीचर्स की जरूरत होती है, जो वेक्टर आपको नहीं देता है, इस स्थिति में आपको एक डीके का उपयोग करना चाहिए। उदाहरण के लिए, मैं किसी को भी इस कोड को फिर से लिखने का प्रयास करता हूं , बिना किसी छल का उपयोग किए और एल्गोरिथ्म में भारी फेरबदल किए बिना।


वास्तव में, का एक ही श्रृंखला पर push_backऔर pop_backसंचालन, deque<int>कम से कम 20% से अधिक तेजी से हमेशा होता है vector<int>मेरी परीक्षण (ओ 3 के साथ जीसीसी) में। मुझे लगता है यही कारण dequeहै कि चीजों के लिए मानक पसंद है std::stack...
igel

-1

ध्यान दें कि सरणी के बढ़ने पर वेक्टर मेमोरी फिर से आवंटित की जाती है। यदि आपके पास वेक्टर तत्वों के संकेत हैं, तो वे अमान्य हो जाएंगे।

साथ ही, यदि आप किसी तत्व को मिटाते हैं, तो पुनरावृत्तियाँ अमान्य हो जाती हैं (लेकिन "for (auto ...)") नहीं।

संपादित करें: 'deque' को 'वेक्टर' में बदला


-1: आरंभ या समाप्ति पर सम्मिलित करें और मिटाएं अन्य तत्वों के संदर्भ और संकेत को अमान्य नहीं करता है। (हालांकि बीच में डालने और मिटाने का काम करता है)
सोजर्ड

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