मैं शायद ही कभी लिंक्ड सूचियों के लिए टेल पॉइंटर का उपयोग करता हूं और अधिक बार एकल-लिंक्ड सूचियों का उपयोग करने की प्रवृत्ति रखता हूं जहां एक स्टैक जैसा धक्का / सम्मिलन और हटाने का पॉप पैटर्न (या बीच से सिर्फ रैखिक-समय को हटाने) पर्याप्त होता है। ऐसा इसलिए है क्योंकि मेरे सामान्य उपयोग के मामलों में, टेल पॉइंटर वास्तव में महंगा है, जिस तरह एकल-लिंक की गई सूची को दोगुनी-लिंक वाली सूची में बनाना महंगा है।
अक्सर एक एकल-लिंक की गई सूची के लिए मेरा सामान्य मामला उपयोग सैकड़ों लिंक की गई हजारों सूचियों को संग्रहीत कर सकता है जिनमें केवल कुछ सूची नोड्स होते हैं। मैं भी आम तौर पर लिंक्ड सूची के लिए संकेत का उपयोग नहीं करते। मैं सूचक को सरणी में उपयोग करता हूं क्योंकि सूचकांक 32-बिट हो सकता है, उदाहरण के लिए, 64-बिट पॉइंटर का आधा स्थान लेते हुए। मैं भी आम तौर पर एक बार में सूची नोड्स आवंटित नहीं करता हूं और इसके बजाय, फिर से, सभी नोड्स को संग्रहीत करने के लिए एक बड़े सरणी का उपयोग करें और फिर नोड्स को एक साथ जोड़ने के लिए 32-बिट सूचकांकों का उपयोग करें।
एक उदाहरण के रूप में, एक 400x400 ग्रिड का उपयोग करके एक वीडियो गेम की कल्पना करें जो टकराव का पता लगाने में तेजी लाने के लिए एक दूसरे के चारों ओर घूमता है और एक-दूसरे से उछलता है। उस मामले में, स्टोर करने के लिए एक बहुत ही कुशल तरीका 160,000 एकल-लिंक की गई सूचियों को संग्रहीत करना है, जो मेरे मामले में 160,000 32-बिट पूर्णांक (~ 640 किलोबाइट) और एक 32-बिट पूर्णांक ओवरहेड प्रति कण में अनुवाद करता है। अब जैसे कि कण स्क्रीन पर घूमते हैं, हमें बस इतना करना है कि एक कण को एक कोशिका से दूसरी कोशिका में स्थानांतरित करने के लिए कुछ 32-बिट पूर्णांकों को अपडेट किया जाए, जैसे:
... next
एक कण नोड के सूचकांक ("पॉइंटर") के साथ कोशिका में अगले कण के सूचकांक के रूप में सेवारत या अगले मुक्त कण को पुनः प्राप्त करने के लिए यदि कण मर गया है (मूल रूप से सूचकांकों का उपयोग करके एक मुक्त सूची आवंटन कार्यान्वयन):
सेल से लीनियर-टाइम रिमूवल वास्तव में एक ओवरहेड नहीं है क्योंकि हम सेल में कणों के माध्यम से पुनरावृत्ति करके कण तर्क को संसाधित कर रहे हैं, इसलिए एक डबल-लिंक की गई सूची बस एक तरह का ओवरहेड जोड़ देगी जो कि फायदेमंद नहीं है मेरे सभी मामले में एक पूंछ के रूप में मुझे या तो बिल्कुल भी फायदा नहीं होगा।
टेल पॉइंटर ग्रिड की मेमोरी के उपयोग को दोगुना कर देगा और साथ ही कैश मिस की संख्या भी बढ़ाएगा। यह जाँचने के लिए भी शाखा की आवश्यकता होती है कि शाखा रहित होने के बजाय सूची खाली है या नहीं। इसे एक डबल-लिंक्ड सूची बनाने से प्रत्येक कण की सूची ओवरहेड हो जाएगी। 90% समय मैं लिंक्ड लिस्ट का उपयोग करता हूं, यह इन जैसे मामलों के लिए है, और इसलिए टेल पॉइंटर वास्तव में स्टोर करने के लिए अपेक्षाकृत काफी महंगा होगा।
तो 4-8 बाइट्स वास्तव में अधिकांश संदर्भों में तुच्छ नहीं है, जिसमें मैं पहले स्थान पर लिंक की गई सूचियों का उपयोग करता हूं। बस वहाँ में चिप करना चाहता था क्योंकि यदि आप तत्वों की एक नाव लोड करने के लिए डेटा संरचना का उपयोग कर रहे हैं, तो 4-8 बाइट्स हमेशा इतनी नगण्य नहीं हो सकती हैं। मैं वास्तव में लिंक की गई सूचियों का उपयोग करता हूं ताकि मेमोरी के लिए आवश्यक संख्या और मेमोरी की मात्रा को कम किया जा सके, ऐसा कहना, ग्रिड के लिए विकसित होने वाले 160,000 डायनेमिक सरणियों को संग्रहीत करना, जिसमें विस्फोटक मेमोरी का उपयोग होगा (आमतौर पर एक पॉइंटर प्लस दो पूर्णांक कम से कम प्रति ग्रिड सेल ग्रिड सेल प्रति ढेर आवंटन के साथ-साथ प्रति पूर्णांक और शून्य हीप आवंटन प्रति सेल के विपरीत)।
मैं अक्सर कई लोगों को सामने / मध्य निष्कासन और सामने / मध्य सम्मिलन से जुड़ी उनकी निरंतर-समय की जटिलता के लिए लिंक किए गए सूचियों के लिए पहुंचता हूं, जब LLs अक्सर आकस्मिकता की कमी के कारण उन मामलों में खराब पसंद होते हैं। जहां LLs मेरे लिए एक प्रदर्शन के दृष्टिकोण से सुंदर हैं, बस कुछ बिंदुओं में हेरफेर करके एक तत्व को एक सूची से दूसरी में स्थानांतरित करने की क्षमता है, और एक चर-आकार मेमोरी आवंटन के बिना एक चर-आकार डेटा संरचना को प्राप्त करने में सक्षम है (जब से प्रत्येक नोड का एक समान आकार होता है, हम मुफ्त सूचियों का उपयोग कर सकते हैं, जैसे)। यदि प्रत्येक सूची नोड को व्यक्तिगत रूप से एक सामान्य-उद्देश्य आवंटनकर्ता के खिलाफ आवंटित किया जा रहा है, तो यह आमतौर पर तब होता है जब लिंक की गई सूची विकल्पों की तुलना में बहुत खराब होती है, और यह '
मैं इसके बजाय सुझाव देना चाहूंगा कि अधिकांश मामलों के लिए जहां लिंक की गई सूचियां सीधे विकल्प पर एक बहुत प्रभावी अनुकूलन के रूप में काम करती हैं, सबसे उपयोगी रूप आम तौर पर अकेले जुड़े हुए हैं, केवल एक सिर सूचक की आवश्यकता है, और प्रति सामान्य उद्देश्य स्मृति आवंटन की आवश्यकता नहीं है नोड और इसके बजाय अक्सर पूल मेमोरी पहले से ही प्रति नोड आवंटित की जा सकती है (पहले से आवंटित बड़े सरणी से, जैसे)। इसके अलावा प्रत्येक एसएलएल आम तौर पर उन मामलों में बहुत कम संख्या में तत्वों को संग्रहीत करता है, जैसे कि ग्राफ़ एक ग्राफ नोड से जुड़ा हुआ है (कई बड़े पैमाने पर लिंक की गई सूची के विपरीत कई छोटे लिंक)।
यह भी ध्यान में रखने योग्य है कि हमारे पास इन दिनों DRAM का बोट लोड है, लेकिन यह दूसरी सबसे धीमी प्रकार की मेमोरी उपलब्ध है। 64-बाइट कैश लाइनों के साथ L1 कैश की बात आने पर हम अभी भी 64 केबी प्रति कोर जैसे कुछ पर हैं। नतीजतन, उन छोटी बाइट बचत वास्तव में ऊपर कण कण की तरह एक प्रदर्शन-महत्वपूर्ण क्षेत्र में बात कर सकते हैं जब लाखों गुना अधिक अगर यह मतलब है कि एक कैश लाइन में दो बार के रूप में कई नोड्स भंडारण के बीच का अंतर है या नहीं, जैसे।