किसी सरणी / सरणी सूची में लिंक की गई सूची का उपयोग कब करें?


176

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


जावा में, ArrayList और LinkedList कंस्ट्रक्टर के अलावा बिल्कुल उसी कोड का उपयोग करते हैं। आपकी "सरणी सूची ... लिंक की गई सूची की तुलना में आसानी से या जितनी आसानी से उपयोग की जाती है" इसका कोई मतलब नहीं है। कृपया एक लिंक्डलिस्ट की तुलना में "आसान" होने के लिए एक ArrayList का एक उदाहरण प्रदान करें।
एस.लॉट

2
इसे भी देखें, stackoverflow.com/questions/322715/…
NoNaMe


3
यह सच नहीं है। जावा ArrayList एक एरे के चारों ओर एक आवरण है, जिसमें कुछ उपयोगिता कार्य जोड़े गए हैं। एक लिंक की गई सूची, जाहिर है, एक लिंक्ड सूची है। डेवलपर
.classpath.org

जवाबों:


261

लिंक की गई सूचियाँ सरणियों पर बेहतर हैं जब:

  1. आपको सूची से निरंतर-समय सम्मिलन / विलोपन की आवश्यकता होती है (जैसे वास्तविक समय कंप्यूटिंग में जहां समय की भविष्यवाणी बिल्कुल महत्वपूर्ण है)

  2. आप नहीं जानते कि सूची में कितने आइटम होंगे। सरणियों के साथ, आपको सरणी को बहुत बड़ा होने पर मेमोरी को फिर से घोषित करने और कॉपी करने की आवश्यकता हो सकती है

  3. आपको किसी भी तत्व के लिए यादृच्छिक अभिगम की आवश्यकता नहीं है

  4. आप सूची के बीच में आइटम सम्मिलित करना चाहते हैं (जैसे कि प्राथमिकता कतार)

ऐरे को प्राथमिकता दी जाती है जब:

  1. आपको तत्वों की अनुक्रमित / यादृच्छिक पहुँच की आवश्यकता है

  2. आप समय से पहले सरणी में तत्वों की संख्या जानते हैं ताकि आप सरणी के लिए सही मात्रा में मेमोरी आवंटित कर सकें

  3. अनुक्रम में सभी तत्वों के माध्यम से पुनरावृत्ति करते समय आपको गति की आवश्यकता होती है। आप प्रत्येक तत्व तक पहुंचने के लिए सरणी पर पॉइंटर गणित का उपयोग कर सकते हैं, जबकि आपको लिंक्ड सूची में प्रत्येक तत्व के लिए पॉइंटर के आधार पर नोड को देखने की आवश्यकता होती है, जिसके परिणामस्वरूप पृष्ठ दोष हो सकते हैं जो प्रदर्शन हिट हो सकते हैं।

  4. स्मृति एक चिंता का विषय है। लिंक किए गए सूचियों की तुलना में भरे हुए सरणियाँ कम मेमोरी लेती हैं। सरणी में प्रत्येक तत्व सिर्फ डेटा है। प्रत्येक लिंक किए गए सूची नोड को लिंक किए गए सूची में अन्य तत्वों को डेटा के साथ-साथ एक (या अधिक) पॉइंटर्स की आवश्यकता होती है।

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


7
अच्छी शुरुआत, लेकिन इससे महत्वपूर्ण चीजें निकलती हैं: सूची समर्थन संरचना साझाकरण, सरणियाँ घनी हैं और बेहतर स्थानीयता है।
डेरिक बेकन

1
व्यावहारिक रूप से, सरणी और सरणियों के बीच प्रदर्शन अंतर नगण्य है। यह मानता है कि आप तुलना करने योग्य हैं और, उदाहरण के लिए, जब आप पहले से आकार जानते हैं, तो आप इसके बारे में सरणी सूची को बताते हैं।
२१:

40
चूंकि लिंक्डलिस्ट में ओ (1) इंसर्ट / डिलीट होता है (जो कि मुझे लगता है कि जब आप लगातार टाइम इंसर्ट / डिलीट कहते हैं ) एक
लिंक्डलिस्ट

28
लिंक्डलिस्ट में ओ (1) इंसर्ट होते हैं अगर आप पहले से इंसर्शन के स्थान पर होते हैं (एक इटरेटर के माध्यम से)। हालांकि, हमेशा नहीं।
एडम

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

54

Arrays में O (1) रैंडम एक्सेस है, लेकिन इसमें सामान जोड़ना या उससे सामान निकालना वास्तव में महंगा है।

लिंक की गई सूचियाँ कहीं भी और पुनरावृति करने के लिए वस्तुओं को जोड़ने या हटाने के लिए वास्तव में सस्ती हैं, लेकिन यादृच्छिक अभिगम O (n) है।


3
किसी सरणी के अंत से आइटम हटाना आकस्मिक-समय है, क्योंकि लिंक की गई सूची के दोनों छोर से आइटम सम्मिलित करना / निकालना है । बीच में ... इतना भी नहीं है।
जॉय

1
@Joey लिंक्ड सूची O (n) के अंत में प्रविष्टि / विलोपन नहीं है? जब तक आप पहले से ही पेनल्टी लिंक पर तैनात नहीं होते हैं, तब भी आपको अंतिम तत्व को खोजने के लिए ओ (एन) चरणों की आवश्यकता होगी, नहीं?
एलेक्स मूर-नीमी

@ एलेक्समोर-नीमी: एकल-जुड़ी सूची के लिए, हां। लेकिन कई में आगे और पीछे लिंक होते हैं, और इस तरह या तो अंत तक संकेत देते रहते हैं।
जॉय

2
एक दोहरी लिंक वाली सूची होने से आप आगे और पीछे की खोज कर सकते हैं, जब तक कि आपके एलएल ने मूल्यों का आदेश नहीं दिया है ... और अभी भी सबसे खराब स्थिति ओ (एन) है
9

"लिंक की गई सूचियाँ वास्तव में कहीं भी आइटम जोड़ने या निकालने के लिए सस्ती हैं और पुनरावृति करने के लिए" पूरी तरह से सच नहीं है। यदि मैं किसी ऐसी सूची को हटाना चाहता हूं जो किसी लिंक की गई सूची के बीच में है, तो मुझे सूची में उस आइटम तक पहुंचने तक शुरुआत से चलना पड़ेगा। इसका O (n / 2) समय जहां n = सूची में आइटम की संख्या। आपके उत्तर से ऐसा लगता है कि आप इसके निरंतर समय O (1) का सुझाव दे रहे हैं, जैसे यह सरणी में है। किसी लिंक किए गए सूची के सिर / रूट नोड से जोड़ने / हटाने के लिए निरंतर समय है।
यवर मुर्तजा

22
Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

ArrayLists लिखने-एक बार पढ़ने वाले कई या ऐपेंडर्स के लिए अच्छे हैं, लेकिन सामने या बीच से जोड़ने / हटाने पर बुरा है।


14

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

किसी सरणी सूची में तत्वों तक पहुँच एक लिंक की गई सूची से भी तेज़ है, भले ही पहुँच अनुक्रमिक हो। ऐसा इसलिए है क्योंकि सरणी तत्वों को सन्निहित स्मृति में संग्रहीत किया जाता है और आसानी से कैश किया जा सकता है। लिंक की गई सूची नोड्स संभवतः कई अलग-अलग पृष्ठों पर बिखरे हुए हो सकते हैं।

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


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

7

सूचियों का लाभ तब दिखाई देता है जब आपको बीच में आइटम सम्मिलित करने की आवश्यकता होती है और सरणी को आकार देना और चीजों को शिफ्ट करना शुरू नहीं करना चाहते हैं।

आप सही हैं कि यह आमतौर पर ऐसा नहीं है। मेरे पास कुछ बहुत ही विशिष्ट मामले हैं, लेकिन बहुत सारे नहीं हैं।


सरणी को शिफ्ट करना और आकार बदलना, वास्तव में तब होता है जब आप बीच में आक्रमण करते हैं। यदि आप परिशोधन बाध्य नहीं करते हैं, तो आपको केवल आकार बदलने के बिना स्थानांतरण की आवश्यकता होगी।
9

3

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

  • खोज कर

चूंकि सरणी अनुक्रमणिका आधारित डेटा संरचना है। अरेंजिंग (इंडेक्स) ओ (1) समय लेगा, जबकि लिंक्डलिस्ट इंडेक्स डीएस नहीं है, इसलिए आपको इंडेक्स तक जाने की आवश्यकता होगी, जहां इंडेक्स <= n, एन लिंक्ड लिस्ट का आकार है, जब तत्वों की यादृच्छिक पहुँच होती है, तो सरणी लिंक की गई सूची से तेज़ होती है।

प्र। इसके पीछे की सुंदरता क्या है?

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

  • निवेशन

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

  • विलोपन

यह सरणी की तरह लिंक्डइन में सम्मिलन और बेहतर की तरह काम करता है।


2

वे संग्रह के सबसे आम उपयोग किए गए कार्यान्वयन हैं।

सारणी सूची:

  • अंत में आमतौर पर O (1) सबसे खराब स्थिति O (n) डालें / हटाएं

  • बीच में डालें / हटाएं O (n)

  • किसी भी स्थिति को प्राप्त करें O (1)

लिंक्ड सूची:

  • किसी भी स्थिति में डालें / हटाएं O (1) (ध्यान दें कि यदि आपके पास तत्व का संदर्भ है)

  • मध्य O (n) में पुनः प्राप्त करें

  • पहले या अंतिम तत्व को पुनः प्राप्त करें O (1)

वेक्टर: इसका उपयोग न करें। यह ArrayList के समान एक पुराना कार्यान्वयन है लेकिन सभी विधियों के साथ सिंक्रनाइज़ किया गया है। यह एक बहुस्तरीय वातावरण में एक साझा सूची के लिए सही दृष्टिकोण नहीं है।

हैश मैप

ओ (1) में कुंजी द्वारा डालें / हटाएं / पुनः प्राप्त करें

ट्रीसेट सम्मिलित करें / हटाएं / ओ में शामिल हैं (लॉग एन)

ओ (1) में हैशसेट डालें / निकालें / शामिल करें / आकार दें


1

वास्तविकता में स्मृति स्थानीयता वास्तविक प्रसंस्करण में एक बड़ा प्रदर्शन प्रभाव है।

"बिग डेटा" प्रोसेसिंग बनाम रैंडम एक्सेस में डिस्क स्ट्रीमिंग के बढ़ते उपयोग से पता चलता है कि इसके आस-पास आपके एप्लिकेशन को कैसे संरचित किया जा सकता है, यह बड़े पैमाने पर प्रदर्शन में सुधार कर सकता है।

यदि किसी सरणी को क्रमिक रूप से एक्सेस करने का कोई तरीका है जो अब तक का सबसे अच्छा प्रदर्शन है। यदि लक्ष्य महत्वपूर्ण है तो इसे लक्ष्य के रूप में डिजाइन करना कम से कम माना जाना चाहिए।


0

हम्म, Arraylist मामलों में इस्तेमाल किया जा सकता है जैसे मुझे लगता है:

  1. आप सुनिश्चित नहीं हैं कि कितने तत्व मौजूद होंगे
  2. लेकिन आपको अनुक्रमण के माध्यम से सभी तत्वों को यादृच्छिक रूप से एक्सेस करने की आवश्यकता है

उदाहरण के लिए, आपको संपर्क सूची में सभी तत्वों को आयात और एक्सेस करने की आवश्यकता है (जिसका आकार आपके लिए अज्ञात है)


0

रेडिक्स के लिए लिंक की सूची का उपयोग करें सरणियों पर छाँटें और बहुपद संचालन के लिए।


0

1) के रूप में डालने और हटाने के संचालन के ऊपर समझाया ArrayList (O (n)) की तुलना में लिंक्डलिस्ट में अच्छा प्रदर्शन (O (1)) देते हैं। इसलिए यदि आवेदन में लगातार जोड़ और विलोपन की आवश्यकता है तो लिंक्डलिस्ट एक सर्वोत्तम विकल्प है।

2) Arraylist (O (1)) में Search (get Method) ऑपरेशन तेज हैं, लेकिन LinkedList (O (n)) में नहीं हैं इसलिए यदि कम ऐड हैं और ऑपरेशंस को हटाते हैं और ऑपरेशन की अधिक आवश्यकता होती है, तो ArrayList आपका सबसे अच्छा दांव होगा।


0

मुझे लगता है कि मुख्य अंतर यह है कि क्या आपको अक्सर सूची के शीर्ष से सामान डालने या निकालने की आवश्यकता होती है।

किसी सरणी के साथ, यदि आप सूची के शीर्ष से कुछ हटाते हैं तो जटिलता ओ (n) है क्योंकि सरणी तत्वों के सभी सूचकांकों को स्थानांतरित करना होगा।

एक लिंक की गई सूची के साथ, यह ओ (1) है क्योंकि आपको केवल नोड बनाने की आवश्यकता है, सिर को फिर से असाइन करें और पिछले सिर के रूप में अगले को संदर्भ असाइन करें।

जब सूची के अंत में बार-बार सम्मिलित या हटाया जाता है, तो सरणियाँ बेहतर होती हैं क्योंकि जटिलता ओ (1) होगी, कोई रीइन्डेक्सिंग की आवश्यकता नहीं है, लेकिन एक लिंक की गई सूची के लिए यह ओ (एन) होगा क्योंकि आपको सिर से जाने की आवश्यकता है पिछले नोड के लिए।

मुझे लगता है कि लिंक की गई सूची और सरणियों दोनों में खोज ओ (लॉग एन) होगी क्योंकि आप शायद एक द्विआधारी खोज का उपयोग कर रहे होंगे।


0

मैंने कुछ बेंचमार्किंग की, और पाया कि सूची वर्ग वास्तव में यादृच्छिक डालने के लिए लिंक्डलिस्ट की तुलना में तेज़ है:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = 20000;
            Random rand = new Random(12345);

            Stopwatch watch = Stopwatch.StartNew();
            LinkedList<int> ll = new LinkedList<int>();
            ll.AddLast(0);
            for (int i = 1; i < count; i++)
            {
                ll.AddBefore(ll.Find(rand.Next(i)),i);

            }
            Console.WriteLine("LinkedList/Random Add: {0}ms", watch.ElapsedMilliseconds);

            watch = Stopwatch.StartNew();
            List<int> list = new List<int>();
            list.Add(0);
            for (int i = 1; i < count; i++)
            {
                list.Insert(list.IndexOf(rand.Next(i)), i);

            }
            Console.WriteLine("List/Random Add: {0}ms", watch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

लिंक की गई सूची के लिए 900 ms और सूची वर्ग के लिए 100ms लगते हैं।

यह बाद के पूर्णांक संख्याओं की सूची बनाता है। प्रत्येक नया पूर्णांक एक यादृच्छिक संख्या के बाद डाला जाता है जो पहले से ही सूची में है। हो सकता है कि सूची वर्ग केवल एक सरणी से बेहतर कुछ का उपयोग करता है।


सूची एक इंटरफेस है, एक वर्ग नहीं
बोर्गमाटर

0

Arrays, अब तक, सबसे व्यापक रूप से उपयोग की जाने वाली डेटा संरचनाएं हैं। हालांकि, लिंक की गई सूचियाँ अपने स्वयं के अनूठे तरीके से उपयोगी साबित होती हैं, जहाँ सरणियाँ अनाड़ी हैं - या महंगी, कम से कम कहने के लिए।

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

बाइनरी ट्री और बाइनरी सर्च ट्री, हैश टेबल, और कोशिश कुछ डेटा संरचनाएं हैं जिनमें - कम से कम सी में - आपको उन्हें बनाने के लिए एक मूलभूत घटक के रूप में लिंक की गई सूचियों की आवश्यकता है।

हालांकि, लिंक्ड सूची को उन स्थितियों से बचा जाना चाहिए, जहां इसके सूचकांक द्वारा किसी भी मनमाने तत्व को कॉल करने में सक्षम होने की उम्मीद है।


0

प्रश्न का एक सरल उत्तर इन बिंदुओं का उपयोग करके दिया जा सकता है:

  1. समान प्रकार के डेटा तत्वों के संग्रह की आवश्यकता होने पर एरे का उपयोग किया जाता है। जबकि, लिंक की गई सूची मिश्रित प्रकार के डेटा से जुड़े तत्वों का एक संग्रह है जिसे नोड्स के रूप में जाना जाता है।

  2. सरणी में, कोई भी ओ (1) समय में किसी भी तत्व का दौरा कर सकता है। जबकि, लिंक की गई सूची में हमें O (n) समय लेने वाले सिर से पूरी लिंक की गई सूची को आवश्यक नोड तक ले जाना होगा।

  3. सरणियों के लिए, एक विशिष्ट आकार को शुरू में घोषित करने की आवश्यकता होती है। लेकिन लिंक्ड लिस्ट आकार में गतिशील हैं।

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