डायनेमिक गेम ऑब्जेक्ट को स्टोर करने के लिए सबसे कुशल कंटेनर कौन सा है? [बन्द है]


20

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

मुझे लगता है कि उस मामले में यह एक सूची होगी ताकि स्मृति सन्निहित न हो और कोई भी पुन: आकार देने वाला न हो। लेकिन फिर मैं एक मानचित्र या सेट का उपयोग करने पर भी विचार कर रहा हूं। अगर किसी के पास कोई उपयोगी जानकारी है तो मैं उसकी सराहना करूंगा।

मैं इसे c ++ में वैसे लिख रहा हूँ।

इसके अलावा मैं एक समाधान के साथ आया था जो मुझे लगता है कि काम करेगा।

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


कोई विशिष्ट भाषा जिसे आप लक्षित कर रहे हैं?
Phill.Zitt

हार्डवेयर प्लेटफॉर्म, भाषा / रूपरेखा आदि सहित कई अन्य बारीकियों के बिना इस सवाल का जवाब देना बहुत कठिन है
PlayDeezGames

1
प्रो टिप, आप हटाए गए तत्वों की स्मृति में निशुल्क सूची को स्टोर कर सकते हैं (ताकि आपको अतिरिक्त कतार की आवश्यकता न हो)।
जेफ गेट्स

2
क्या इस प्रश्न में कोई प्रश्न है?
ट्रेवर पॉवेल

ध्यान दें कि आपको सबसे बड़े सूचकांक का ट्रैक रखने की आवश्यकता नहीं है और न ही कई तत्वों का प्रचार करना है। std :: वेक्टर आपके लिए उस सब का ध्यान रखता है।
एपीआई-जानवर

जवाबों:


33

इसका उत्तर हमेशा एक सरणी या std :: वेक्टर का उपयोग करना है। लिंक की गई सूची या एक std :: मानचित्र जैसे प्रकार आमतौर पर खेलों में बिल्कुल भयावह होते हैं , और इसमें निश्चित रूप से गेम ऑब्जेक्ट्स के संग्रह जैसे मामले शामिल होते हैं।

आपको सरणी / वेक्टर में ऑब्जेक्ट्स को स्वयं (उन्हें इंगित नहीं करना) स्टोर करना चाहिए।

आप सन्निहित स्मृति चाहते हैं । आप वास्तव में यह चाहते हैं। गैर-सन्निहित स्मृति में किसी भी डेटा पर Iterating, सामान्य रूप से बहुत सारी कैश मिस करता है और कंपाइलर और CPU के लिए प्रभावी कैश प्रीफ़ेटिंग करने की क्षमता को हटा देता है। यह अकेले प्रदर्शन को मार सकता है।

आप स्मृति आबंटन और डील-डौल से भी बचना चाहते हैं। वे बहुत धीमी गति से होते हैं, यहां तक ​​कि एक तेज मेमोरी आवंटन के साथ। मैंने देखा है कि प्रत्येक फ्रेम से कुछ सौ मेमोरी एलोकेशन हटाकर गेम को 10x FPS की टक्कर मिलती है। ऐसा नहीं लगता कि यह उतना बुरा होना चाहिए, लेकिन यह हो सकता है।

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

उदाहरण के लिए, गेम ऑब्जेक्ट को हटाने के लिए, आप स्वैप-एंड-पॉप का उपयोग कर सकते हैं। आसानी से कुछ के साथ लागू:

std::swap(objects[index], objects.back());
objects.pop_back();

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

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

आपकी गेम ऑब्जेक्ट में उनके मुख्य सरणी में एक इंडेक्स है। वे बहुत कुशलता से सिर्फ इस सूचकांक (एक नक्शा या एक हैश तालिका की तुलना में बहुत तेजी से) के साथ देखा जा सकता है। हालांकि, वस्तुओं को हटाते समय स्वैप और पॉप के कारण सूचकांक स्थिर नहीं होता है।

एक स्लॉट मैप में अप्रत्यक्ष की दो परतों की आवश्यकता होती है, लेकिन दोनों निरंतर सूचकांकों के साथ सरल सरणी लुकअप होते हैं। वो हैं तेज हैं । वास्तव में तेज।

मूल विचार यह है कि आपके पास तीन सरणियाँ हैं: आपकी मुख्य वस्तु सूची, आपकी अप्रत्यक्ष सूची और अप्रत्यक्ष सूची के लिए एक मुफ्त सूची। आपकी मुख्य वस्तु सूची में आपकी वास्तविक वस्तुएं होती हैं, जहां प्रत्येक वस्तु अपनी विशिष्ट आईडी जानती है। यूनिक आईडी एक इंडेक्स और एक वर्जन टैग से बना होता है। अप्रत्यक्ष सूची मुख्य वस्तु सूची के सूचकांकों की एक सरणी मात्र है। मुक्त सूची अप्रत्यक्ष सूची में सूचकांक का एक ढेर है।

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

जब आप किसी ऑब्जेक्ट को नष्ट करते हैं, तो आप स्वैप-एंड-पॉप को सामान्य करते हैं, लेकिन आप संस्करण संख्या भी बढ़ाते हैं। फिर आप अप्रत्यक्ष सूची इंडेक्स (ऑब्जेक्ट की यूनिक आईडी का हिस्सा) को भी मुफ्त सूची में जोड़ते हैं। किसी वस्तु को स्वैप-एंड-पॉप के हिस्से के रूप में ले जाने पर, आप अप्रत्यक्ष सूची में इसके नए स्थान पर इसकी प्रविष्टि को भी अपडेट करते हैं।

उदाहरण छद्म कोड:

Object:
  int index
  int version
  other data

SlotMap:
  Object objects[]
  int slots[]
  int freelist[]
  int count

  Get(id):
    index = indirection[id.index]
    if objects[index].version = id.version:
      return &objects[index]
    else:
      return null

  CreateObject():
    index = freelist.pop()

    objects[count].index = id
    objects[count].version += 1

    indirection[index] = count

    Object* object = &objects[count].object
    object.initialize()

    count += 1

    return object

  Remove(id):
    index = indirection[id.index]
    if objects[index].version = id.version:
      objects[index].version += 1
      objects[count - 1].version += 1

      swap(objects[index].data, objects[count - 1].data)

अप्रत्यक्ष परत आपको एक स्थिर पहचानकर्ता (इंडेक्स इनडायरेक्शन लेयर, जहाँ प्रविष्टियाँ नहीं चलती हैं) को एक संसाधन के लिए अनुमति देता है जो संघनन (मुख्य वस्तु सूची) के दौरान स्थानांतरित हो सकता है।

संस्करण टैग आपको किसी ऑब्जेक्ट को ID संग्रहीत करने की अनुमति देता है जिसे हटाया जा सकता है। उदाहरण के लिए, आपके पास आईडी (10,1) है। इंडेक्स 10 के साथ ऑब्जेक्ट को हटा दिया जाता है (कहते हैं, आपकी बुलेट किसी ऑब्जेक्ट को हिट करती है और नष्ट हो जाती है)। मुख्य वस्तु सूची में स्मृति के उस स्थान पर मौजूद वस्तु को उसका संस्करण संख्या टकराया हुआ है, जो उसे (10,2) देता है। यदि आप एक बासी आईडी से फिर से (10,1) देखने की कोशिश करते हैं, तो अनुक्रमणिका 10 के माध्यम से वह वस्तु वापस आ जाती है, लेकिन यह देख सकते हैं कि संस्करण संख्या बदल गई है, इसलिए आईडी अब मान्य नहीं है।

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

आधार एल्गोरिथ्म में आप कर सकते हैं विभिन्न सुधार। उदाहरण के लिए, मुख्य ऑब्जेक्ट सूची के लिए std :: deque जैसी किसी चीज़ का उपयोग करना; अप्रत्यक्षता की एक अतिरिक्त परत, लेकिन स्लॉटमैप से आपके द्वारा प्राप्त किए गए किसी भी अस्थायी संकेत को अमान्य किए बिना वस्तुओं को पूरी सूची में डालने की अनुमति देता है।

आप ऑब्जेक्ट के अंदर इंडेक्स को स्टोर करने से भी बच सकते हैं, क्योंकि इंडेक्स को ऑब्जेक्ट की मेमोरी एड्रेस (यह - ऑब्जेक्ट्स) से गणना की जा सकती है, और इससे भी बेहतर केवल उस ऑब्जेक्ट को हटाते समय होता है जिस स्थिति में आपके पास ऑब्जेक्ट की आईडी (और इसलिए) सूचकांक) एक पैरामीटर के रूप में।

लिखने के लिए माफी; मुझे नहीं लगता कि यह सबसे स्पष्ट विवरण हो सकता है। यह देर हो चुकी है और मेरे पास कोड नमूनों की तुलना में अधिक समय खर्च किए बिना समझाना मुश्किल है।


1
आप 'कॉम्पैक्ट' स्टोरेज के लिए हर एक्सेस पर एक अतिरिक्त डीरएफ़ और एक उच्च आवंटन / मुफ्त लागत (स्वैप) का व्यापार कर रहे हैं। वीडियो गेम के साथ मेरे अनुभव में, यह एक बुरा व्यापार है :) निश्चित रूप से YMMV।
जेफ गेट्स

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

1
मेरे अनुभव में: (1) वीडियो गेम को सबसे खराब स्थिति के प्रदर्शन पर आंका जाता है, औसत मामले के प्रदर्शन पर नहीं। (2) आपके पास सामान्य रूप से प्रति फ्रेम एक संग्रह पर 1 पुनरावृत्ति है, इस प्रकार बस जमा करना 'आपके सबसे खराब मामले को कम करता है'। (३) आपके पास अक्सर एक ही फ्रेम में कई अलाउंस / फ्रीज होते हैं, उच्च लागत का मतलब है कि आप उस क्षमता को सीमित करते हैं। (४) आपके पास प्रति फ्रेम में अनबाउंड डेरेफ़्स हैं (जिन खेलों में मैंने काम किया है, जिसमें डियाब्लो ३ भी शामिल है, अक्सर डेरेफ़ मध्यम अनुकूलन, सर्वर लोड के ५% के बाद सबसे अधिक पूर्ण लागत वाला ऑप था)। मैं अन्य समाधानों को खारिज करने का मतलब नहीं है, बस अपने अनुभवों और तर्क को इंगित करता हूं!
जेफ गेट्स

3
मुझे यह डेटा संरचना पसंद है। मुझे आश्चर्य है कि यह अधिक प्रसिद्ध नहीं है। यह सरल है और उन सभी समस्याओं को हल करता है जो मुझे महीनों तक मेरे सिर से टकराते रहे हैं। साझा करने के लिए धन्यवाद।
जो बेट्स

2
इसे पढ़ने वाले किसी भी नौसिखिया को इस सलाह से बहुत सावधान रहना चाहिए। यह बहुत ही भ्रामक जवाब है। "जवाब हमेशा एक सरणी या एसटीडी :: वेक्टर का उपयोग करने के लिए होता है। एक लिंक की गई सूची या एक एसटीडी :: मानचित्र जैसे प्रकार आमतौर पर खेल में बिल्कुल भयावह होते हैं, और इसमें निश्चित रूप से गेम ऑब्जेक्ट्स के संग्रह जैसे मामले शामिल होते हैं।" बहुत अतिरंजित है। कोई "ALWAYS" उत्तर नहीं है, अन्यथा ये अन्य कंटेनर नहीं बनाए जाते। कहने के लिए नक्शे / सूची "भयावह" भी अतिशयोक्तिपूर्ण है। वहाँ बहुत सारे वीडियो गेम हैं जो इनका उपयोग करते हैं। "सबसे कुशल" "सबसे व्यावहारिक" नहीं है और एक व्यक्तिपरक "सर्वश्रेष्ठ" के रूप में गलत हो सकता है।
user50286

12


आंतरिक आकार की सूची (O (1) आवंटित / मुफ्त, स्थिर संकेत) के
साथ निश्चित आकार की सरणी (रैखिक मेमोरी) कमजोर संदर्भ कुंजियों के साथ (स्लॉट का पुन: उपयोग कुंजी को अमान्य)
शून्य ओवरहेड डीरेफेरेंस (जब ज्ञात-मान्य)

struct DataArray<T>
{
  void Init(int count); // allocs items (max 64k), then Clear()
  void Dispose();       // frees items
  void Clear();         // resets data members, (runs destructors* on outstanding items, *optional)

  T &Alloc();           // alloc (memclear* and/or construct*, *optional) an item from freeList or items[maxUsed++], sets id to (nextKey++ << 16) | index
  void Free(T &);       // puts entry on free list (uses id to store next)

  int GetID(T &);       // accessor to the id part if Item

  T &Get(id)            // return item[id & 0xFFFF]; 
  T *TryToGet(id);      // validates id, then returns item, returns null if invalid.  for cases like AI references and others where 'the thing might have been deleted out from under me'

  bool Next(T *&);      // return next item where id & 0xFFFF0000 != 0 (ie items not on free list)

  struct Item {
    T item;
    int id;             // (key << 16 | index) for alloced entries, (0 | nextFreeIndex) for free list entries
  };

  Item *items;
  int maxSize;          // total size
  int maxUsed;          // highest index ever alloced
  int count;            // num alloced items
  int nextKey;          // [1..2^16] (don't let == 0)
  int freeHead;         // index of first free entry
};

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

प्रश्न: "एक गतिशील सरणी का उपयोग क्यों नहीं किया जाता है?" A: डायनेमिक सरणियाँ क्रैश का कारण बनती हैं। सरल उदाहरण:

foreach(Foo *foo in array)
  if (ShouldSpawnBaby(*foo))
    Foo &baby = array.Alloc();
    foo->numBabies++; // crash!

आप अधिक जटिलता (जैसे गहरी कॉलस्टैक) के साथ मामलों की कल्पना कर सकते हैं। यह सभी प्रकार के कंटेनर के लिए सही है। खेल बनाते समय, प्रदर्शन के बदले में हर चीज पर आकार और बजट को लागू करने के लिए हमारी समस्या के बारे में हमारी पर्याप्त समझ है।

और मैं इसे पर्याप्त नहीं कह सकता: वास्तव में, यह अब तक की सबसे अच्छी बात है। (यदि आप सहमत नहीं हैं, तो अपना बेहतर समाधान पोस्ट करें! कैविएट - इस पोस्ट के शीर्ष पर सूचीबद्ध मुद्दों को संबोधित करना चाहिए: रैखिक स्मृति / पुनरावृत्ति, ओ (1) आवंटित / मुक्त, स्थिर सूचकांकों, कमजोर संदर्भों, शून्य ओवरहेड डेरेफ़्स या एक अद्भुत कारण है कि आपको उनमें से एक की आवश्यकता क्यों नहीं है;)


गतिशील सरणी के साथ आपका क्या मतलब है ? मैं यह पूछ रहा हूँ क्योंकि DataArrayयह भी लगता है कि ctor में गतिशील रूप से एक array आवंटित कर रहा है। तो मेरी समझ से इसका कुछ अलग अर्थ हो सकता है।
Eonil

मेरा मतलब एक ऐसा सरणी है जो इसके उपयोग के दौरान / इसके निर्माण के अनुरूप / याद रखता है। एक stl वेक्टर एक उदाहरण है जिसे मैं एक गतिशील सरणी कहूंगा।
जेफ गेट्स

@JeffGates वास्तव में इस उत्तर को पसंद करता है। मानक केस रनटाइम लागत के रूप में सबसे खराब स्थिति को स्वीकार करने पर पूरी तरह सहमत हैं। मौजूदा सरणी का उपयोग करके निशुल्क लिंक की गई सूची का समर्थन करना बहुत ही सुरुचिपूर्ण है। प्रश्न Q1: अधिकतम उपयोग का उद्देश्य? प्र २: आवंटन प्रविष्टियों के लिए आईडी के निम्न क्रम के बिट्स में सूचकांक को संग्रहीत करने का क्या उद्देश्य है? 0 क्यों नहीं? Q3: यह कैसे संभालती है इकाई पीढ़ी? यदि ऐसा नहीं होता है, तो मैं चाहता हूं कि ushort जनरेशन काउंट के लिए Q2 के कम-ऑर्डर बिट्स का उपयोग किया जाए। - धन्यवाद।
इंजीनियर

1
A1: अधिकतम उपयोग आप अपने पुनरावृत्ति टोपी की अनुमति देता है। इसके अलावा आप किसी भी निर्माण लागत को परिशोधन करते हैं। A2: 1) आप अक्सर आइटम -> आईडी से जाते हैं। 2) यह तुलना को सस्ता / स्पष्ट करता है। A3: मुझे यकीन नहीं है कि 'पीढ़ियों' का क्या मतलब है। मैं इसकी व्याख्या करता हूं कि 'आप 6 वें आइटम से स्लॉट 7 में आवंटित 5 आइटम को कैसे अलग करते हैं?' जहां 5 और 6 पीढ़ियां हैं। प्रस्तावित योजना सभी स्लॉट के लिए विश्व स्तर पर एक काउंटर का उपयोग करती है। (हम वास्तव में इस काउंटर को प्रत्येक DataArray उदाहरण के लिए और आसानी से अंतर करने के लिए एक अलग संख्या में शुरू करते हैं।) मुझे यकीन है कि आप प्रति आइटम ट्रैकिंग बिट्स को रिजेक्ट कर सकते हैं महत्वपूर्ण था।
जेफ गेट्स

1
@JeffGates - मुझे पता है कि यह एक पुराना विषय है लेकिन मुझे वास्तव में यह विचार पसंद है, क्या आप मुझे शून्य मुक्त (आईडी) पर शून्य मुक्त (टी एंड) के आंतरिक कामकाज के बारे में कुछ जानकारी दे सकते हैं?
द स्टैटेहज

1

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

यदि आप अक्सर वस्तुओं को हटा रहे हैं और उन्हें फिर से बना रहे हैं, तो मैं आपको सुझाव देता हूं कि ऑब्जेक्ट-पूल कैसे लागू किए जाते हैं।

संपादित करें: स्लॉट्स के साथ चीजों को जटिल क्यों करें और क्या नहीं। क्यों नहीं बस एक स्टैक का उपयोग करें और अंतिम आइटम को पॉप करें और उसका पुन: उपयोग करें? इसलिए जब आप एक जोड़ते हैं, तो आप ++ करेंगे, जब आप एक पॉप करते हैं, तो आप अपने एंड इंडेक्स पर नज़र रख सकते हैं।


एक साधारण स्टैक उस मामले को नहीं संभालता है जहां आइटम को मनमाने ढंग से हटा दिया जाता है।
जेफ गेट्स

निष्पक्ष होना, उसका लक्ष्य बिल्कुल स्पष्ट नहीं था। कम से कम मुझे तो नहीं।
सिडार

1

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


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

आमतौर पर आप एक सूची का उपयोग करना चाहते हैं यदि आप चाहते हैं कि आपकी वस्तु सूची क्रोनोक्यली की तुलना में एक अलग तरीके से सॉर्ट की जाए और इस तरह नई वस्तुओं को सम्मिलित करना है, तो अपेंड करें, अन्यथा। एक विकट ने वेक्टर पर फ्लेक्सिबलिटी बढ़ा दी है, लेकिन वास्तव में इसमें बहुत ज्यादा गिरावट नहीं है।

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


सत्य नहीं पुन: सूची Deque सलाह पूरी तरह से deque कार्यान्वयन पर निर्भर करती है, जो गति और निष्पादन में बेतहाशा भिन्न होती है।
कायापलट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.