मुझे लिस्ट बनाम लिंक्डलिस्ट का उपयोग कब करना चाहिए


392

जब लिस्ट बनाम लिंक्डलिस्ट का उपयोग करना बेहतर होता है ?


3
जावा q , बहुत अलग नहीं होना चाहिए।
नवफाल

1
@ जोनाथन-एलन, कृपया स्वीकृत उत्तर को बदलने पर विचार करें। वर्तमान एक गलत और बेहद भ्रामक है।
Xpleria

जवाबों:


107

संपादित करें

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

मूल उत्तर ...

मुझे दिलचस्प परिणाम मिले:

// Temporary class to show the example
class Temp
{
    public decimal A, B, C, D;

    public Temp(decimal a, decimal b, decimal c, decimal d)
    {
        A = a;            B = b;            C = c;            D = d;
    }
}

लिंक की गई सूची (3.9 सेकंड)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.AddLast(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

सूची (2.4 सेकंड)

        List<Temp> list = new List<Temp>(); // 2.4 seconds

        for (var i = 0; i < 12345678; i++)
        {
            var a = new Temp(i, i, i, i);
            list.Add(a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

यहां तक ​​कि अगर आप केवल आवश्यक रूप से डेटा का उपयोग करते हैं, तो यह बहुत धीमा है !! मैं कहता हूं कि लिंक्डलिस्ट का इस्तेमाल कभी न करें।




यहाँ बहुत सारी आवेषणों की तुलना की जा रही है (हम सूची के बीच में एक आइटम डालने की योजना बनाते हैं)

लिंक की गई सूची (51 सेकंड)

        LinkedList<Temp> list = new LinkedList<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            var curNode = list.First;

            for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
                curNode = curNode.Next;

            list.AddAfter(curNode, a); // Insert it after
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

सूची (7.26 सेकंड)

        List<Temp> list = new List<Temp>();

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.Insert(i / 2, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

लिंक की गई सूची जिसमें स्थान का संदर्भ है जहाँ सम्मिलित करना है (.04 सेकंड)

        list.AddLast(new Temp(1,1,1,1));
        var referenceNode = list.First;

        for (var i = 0; i < 123456; i++)
        {
            var a = new Temp(i, i, i, i);

            list.AddLast(a);
            list.AddBefore(referenceNode, a);
        }

        decimal sum = 0;
        foreach (var item in list)
            sum += item.A;

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


99
LinkedList के ऊपर एक लाभ है (यह .net विशिष्ट): क्योंकि सूची एक आंतरिक सरणी द्वारा समर्थित है, यह एक सन्निहित ब्लॉक में आवंटित किया गया है। यदि वह आबंटित ब्लॉक आकार में 85000 बाइट्स से अधिक है, तो उसे बड़े ऑब्जेक्ट हीप पर, गैर-कॉम्पैक्ट करने योग्य पीढ़ी पर आवंटित किया जाएगा। आकार के आधार पर, यह ढेर का विखंडन, स्मृति रिसाव का एक हल्का रूप हो सकता है।
जेरकीबॉल

35
ध्यान दें कि यदि आप बहुत पहले से तैयारी कर रहे हैं (जैसा कि आप मूल रूप से अंतिम उदाहरण में कर रहे हैं) या पहली प्रविष्टि को हटा रहे हैं, तो एक लिंक की गई सूची लगभग हमेशा काफी तेज होगी, क्योंकि ऐसा करने के लिए कोई खोज या चलती / प्रतिलिपि नहीं है। एक सूची को ओ (एन) ऑपरेशन के बहाने बनाते हुए, नए आइटम को समायोजित करने के लिए सब कुछ एक जगह बढ़ने की आवश्यकता होगी।
cHao

6
list.AddLast(a);पिछले दो लिंक्डलिस्ट उदाहरणों में इन-लूप क्यों ? मैं इसे एक बार लूप से पहले कर रहा हूं, जैसे list.AddLast(new Temp(1,1,1,1));कि अगले लिंक्डलिस्ट में, लेकिन यह मुझे (मुझे) लगता है जैसे आप खुद लूप में कई टेंप ऑब्जेक्ट्स से दो बार जोड़ रहे हैं। (और जब मैं अपने आप को एक परीक्षण ऐप के साथ दोहराता हूं , तो निश्चित रूप से, लिंक्डलिस्ट में दो बार पर्याप्त रूप से।)
रफिन

7
मैंने इस उत्तर को अस्वीकार कर दिया। 1) आपकी सामान्य सलाह I say never use a linkedList.त्रुटिपूर्ण है क्योंकि आपकी बाद की पोस्ट से पता चलता है। आप इसे संपादित करना चाह सकते हैं। 2) आप समय क्या कर रहे हैं? तात्कालिकता, जोड़ और गणना एक कदम में पूरी तरह से? अधिकतर, तात्कालिकता और अभिज्ञान वे नहीं हैं जो ppl के बारे में चिंतित हैं, वे एक समय के कदम हैं। विशेष रूप से आवेषण और परिवर्धन का समय बेहतर विचार देगा। 3) सबसे महत्वपूर्ण बात, आप किसी लिंकलिस्ट से आवश्यकता से अधिक जोड़ रहे हैं। यह एक गलत तुलना है। लिंक्डलिस्ट के बारे में गलत विचार फैलाता है।
नवफाल

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

277

ज्यादातर मामलों में, List<T>अधिक उपयोगी है। LinkedList<T>सूची के मध्य में वस्तुओं को जोड़ने / हटाने के दौरान कम लागत होगी, जबकि सूची List<T>के अंत में केवल सस्ते में जोड़ / हटा सकते हैं ।

LinkedList<T>यदि आप अनुक्रमिक डेटा (या तो आगे या पीछे) का उपयोग कर रहे हैं, तो यह केवल सबसे कुशल है - यादृच्छिक अभिगम अपेक्षाकृत महंगा है क्योंकि इसे प्रत्येक बार श्रृंखला चलना चाहिए (इसलिए इसमें अनुक्रमणिका क्यों नहीं है)। हालाँकि, क्योंकि एक List<T>अनिवार्य रूप से सिर्फ एक सरणी (एक आवरण के साथ) यादृच्छिक पहुँच ठीक है।

List<T>भी समर्थन के तरीकों का एक बहुत प्रदान करता है - Find, ToArray, आदि; हालाँकि, ये LinkedList<T>.NET 3.5 / C # 3.0 एक्सटेंशन विधियों के माध्यम से भी उपलब्ध हैं - इसलिए यह एक कारक से कम नहीं है।


4
लिस्ट का एक फायदा <> बनाम लिंक्डलिस्ट <> मैंने उन चिंताओं के बारे में कभी नहीं सोचा था कि माइक्रोप्रोसेसर स्मृति के कैशिंग को कैसे लागू करते हैं। हालाँकि मैं इसे पूरी तरह से नहीं समझता, लेकिन इस ब्लॉग लेख के लेखक "संदर्भ की स्थानीयता" के बारे में बहुत सारी बातें करते हैं, जो कि किसी लिंक की गई सूची को ट्रेस करने की तुलना में किसी सरणी को अधिक तेज़ बनाता है , कम से कम अगर लिंक की गई सूची स्मृति में कुछ खंडित हो गई है । kjellkod.wordpress.com/2012/02/25/…
RenniePet

@ RenniePet सूची को एक डायनामिक ऐरे के साथ लागू किया गया है और सरणियाँ मेमोरी के सन्निहित ब्लॉक हैं।
केसी

2
चूंकि सूची एक गतिशील सरणी है, इसीलिए कभी-कभी कंस्ट्रक्टर में सूची की क्षमता निर्दिष्ट करना अच्छा होता है यदि आप इसे पहले से जानते हैं।
कार्डिन ली जेएच

क्या यह संभव है कि सी # का कार्यान्वयन, सभी, सरणी, सूची <टी> और लिंक्डलिस्ट <टी> एक बहुत ही महत्वपूर्ण मामले के लिए कुछ उप-प्रकार है: आपको एक बहुत बड़ी सूची, परिशिष्ट (AddLast) और अनुक्रमिक ट्रैवर्सल (एक दिशा में) की आवश्यकता है पूरी तरह से ठीक है: मैं चाहता हूं कि निरंतर ब्लॉकों को प्राप्त करने के लिए कोई भी आकार बदलना नहीं है (क्या यह प्रत्येक सरणी, यहां तक ​​कि 20 जीबी सरणियों के लिए गारंटी है?), और मुझे पहले से पता नहीं है आकार, लेकिन मैं पहले से ब्लॉक आकार का अनुमान लगा सकता हूं, जैसे 100 एमबी अग्रिम में हर बार आरक्षित करने के लिए। यह एक अच्छा कार्यान्वयन होगा। या सरणी / सूची के समान है, और मैं एक बिंदु याद किया?
फिलम

1
@Philm उस तरह का परिदृश्य है जहाँ आप अपनी चुनी हुई ब्लॉक रणनीति पर अपना खुद का शिम लिखते हैं; List<T>और T[]बहुत चंकी (सभी एक स्लैब) होने के लिए असफल हो जाएगा, LinkedList<T>बहुत दानेदार (प्रति तत्व स्लैब) होने के लिए विलीन हो जाएगा।
मार्क Gravell

212

एक सूची के रूप में एक लिंक की गई सूची के बारे में सोचना थोड़ा भ्रामक हो सकता है। यह एक श्रृंखला की तरह अधिक है। वास्तव में, .NET में, LinkedList<T>लागू नहीं होता है IList<T>। लिंक की गई सूची में सूचकांक की कोई वास्तविक अवधारणा नहीं है, भले ही ऐसा लगता है कि यह है। निश्चित रूप से कक्षा में प्रदान किए गए तरीकों में से कोई भी अनुक्रमणिका स्वीकार नहीं करता है।

लिंक की गई सूचियों को एकल रूप से जोड़ा जा सकता है, या दोगुना लिंक किया जा सकता है। यह संदर्भित करता है कि क्या श्रृंखला में प्रत्येक तत्व का लिंक केवल अगले एक (एकल रूप से जुड़ा हुआ) या दोनों पूर्व / अगले तत्वों (दोगुना जुड़ा हुआ) है। LinkedList<T>दोगुना जुड़ा हुआ है।

आंतरिक रूप से, List<T>एक सरणी द्वारा समर्थित है। यह स्मृति में एक बहुत कॉम्पैक्ट प्रतिनिधित्व प्रदान करता है। इसके विपरीत, LinkedList<T>क्रमिक तत्वों के बीच द्विदिश लिंक को संग्रहीत करने के लिए अतिरिक्त मेमोरी शामिल है। इसलिए LinkedList<T>वसीयत की स्मृति पदचिह्न आम तौर पर List<T>(कैविट के साथ बड़ा हो List<T>सकता है जो अप्रयुक्त आंतरिक सरणी तत्व हो सकते हैं जो परिशिष्ट संचालन के दौरान प्रदर्शन में सुधार करते हैं।)

उनकी विभिन्न प्रदर्शन विशेषताएँ भी हैं:

संलग्न

  • LinkedList<T>.AddLast(item) निरंतर समय
  • List<T>.Add(item) amortized निरंतर समय, रैखिक सबसे खराब स्थिति

प्रारंभ में लगा

  • LinkedList<T>.AddFirst(item) निरंतर समय
  • List<T>.Insert(0, item) रैखिक समय

निवेशन

  • LinkedList<T>.AddBefore(node, item) निरंतर समय
  • LinkedList<T>.AddAfter(node, item) निरंतर समय
  • List<T>.Insert(index, item) रैखिक समय

निष्कासन

  • LinkedList<T>.Remove(item) रैखिक समय
  • LinkedList<T>.Remove(node) निरंतर समय
  • List<T>.Remove(item) रैखिक समय
  • List<T>.RemoveAt(index) रैखिक समय

गिनती

  • LinkedList<T>.Count निरंतर समय
  • List<T>.Count निरंतर समय

शामिल

  • LinkedList<T>.Contains(item) रैखिक समय
  • List<T>.Contains(item) रैखिक समय

स्पष्ट

  • LinkedList<T>.Clear() रैखिक समय
  • List<T>.Clear() रैखिक समय

जैसा कि आप देख सकते हैं, वे ज्यादातर समान हैं। व्यवहार में, एपीआई का LinkedList<T>उपयोग करने के लिए अधिक बोझिल है, और इसकी आंतरिक आवश्यकताओं का विवरण आपके कोड में फैल जाता है।

हालाँकि, यदि आपको किसी सूची में से कई प्रविष्टि / निष्कासन करने की आवश्यकता है, तो यह निरंतर समय प्रदान करता है। List<T>सूची में अतिरिक्त आइटम डालने / हटाने के बाद चारों ओर फेरबदल किया जाना चाहिए क्योंकि रैखिक समय प्रदान करता है।


2
क्या लिंक लिस्टलिस्ट स्थिर है? मैंने सोचा था कि रैखिक होगा?
इयान बलार्ड

10
@ मुख्य, दोनों सूची वर्गों में गिनती की जाती है।
ड्रू नोक

3
आपने लिखा है कि "सूची <T> .Add (आइटम) लघुगणक समय", हालांकि यह वास्तव में "निरंतर" है यदि सूची क्षमता नए आइटम को संग्रहीत कर सकती है, और "रैखिक" यदि सूची में पर्याप्त स्थान और नया नहीं है पुनः प्राप्त किया जाना।
aStranger

@aStranger, बेशक आप सही हैं। मुझे यकीन नहीं है कि मैं ऊपर क्या सोच रहा था - शायद यह कि सामान्यीकृत सामान्य केस टाइम लॉगरिदमिक है, जो यह नहीं है। वास्तव में परिशोधन समय स्थिर है। मैं संचालन के सर्वोत्तम / सबसे खराब मामले में नहीं आया, एक सरल तुलना के लिए लक्ष्य। मुझे लगता है कि इस विस्तार को प्रदान करने के लिए ऐड ऑपरेशन काफी महत्वपूर्ण है। उत्तर को संपादित करेंगे। धन्यवाद।
आकर्षित नोक

1
@ झिलम, आपको संभवतः एक नया प्रश्न शुरू करना चाहिए, और आप यह नहीं कहते कि आप इस डेटा संरचना का उपयोग एक बार करने के लिए कैसे जा रहे हैं, लेकिन यदि आप एक लाख पंक्तियों पर बात कर रहे हैं, तो आप किसी तरह के हाइब्रिड (लिंक की गई सूची) को पसंद कर सकते हैं सरणी विखंडन या समान) ढेर विखंडन को कम करने के लिए, मेमोरी ओवरहेड को कम करने और LOH पर एक बड़ी वस्तु से बचने के लिए।
ड्रू नोक

118

लिंक की गई सूची बहुत तेजी से प्रविष्टि या सूची सदस्य को हटाने की सुविधा प्रदान करती है। लिंक की गई सूची में प्रत्येक सदस्य के पास सूची में अगले सदस्य के लिए एक पॉइंटर होता है ताकि मैं किसी सदस्य को पद पर सम्मिलित कर सकूँ:

  • नए सदस्य को इंगित करने के लिए सदस्य i-1 में सूचक को अपडेट करें
  • सदस्य को इंगित करने के लिए नए सदस्य में सूचक सेट करें

एक लिंक की गई सूची का नुकसान यह है कि यादृच्छिक पहुंच संभव नहीं है। जब तक वांछित सदस्य नहीं मिल जाता, तब तक सदस्य तक पहुँचने के लिए सूची का पता लगाना आवश्यक है।


6
मैं जोड़ूंगा कि लिंक की गई सूचियों में लिंकडलिस्टस्टोड के माध्यम से ऊपर संग्रहीत प्रति आइटम ओवरहेड है जो पिछले और अगले नोड को संदर्भित करता है। उस की अदायगी स्मृति का एक सन्निहित ब्लॉक है जो सूची को संग्रहीत करने के लिए आवश्यक नहीं है, एक सरणी आधारित सूची के विपरीत।
16 अक्टूबर

3
स्मृति का एक सन्निहित ब्लॉक आमतौर पर प्रभावित नहीं होता है?
जोनाथन एलन

7
हां, एक जटिल ब्लॉक यादृच्छिक अभिगम प्रदर्शन और मेमोरी खपत के लिए पसंद किया जाता है, लेकिन संग्रह के लिए जिन्हें आकार को नियमित रूप से बदलने की आवश्यकता होती है जैसे कि एक एरे को आम तौर पर एक नए स्थान पर कॉपी करने की आवश्यकता होती है, जबकि एक लिंक की गई सूची को केवल मेमोरी के प्रबंधन की आवश्यकता होती है नए सम्मिलित / हटाए गए नोड्स।
जिपरसन

6
यदि आपको कभी बहुत बड़ी सरणियों या सूचियों के साथ काम करना पड़ा है (एक सूची सिर्फ एक सरणी लपेटती है) तो आप मेमोरी मुद्दों में भागना शुरू कर देंगे, भले ही आपकी मशीन पर बहुत सारी मेमोरी उपलब्ध हो। जब वह अंतर्निहित सरणी में नई जगह आवंटित करता है तो सूची दोहरीकरण रणनीति का उपयोग करती है। तो एक 1000000 elemnt सरणी जो पूर्ण है उसे 2000000 तत्वों के साथ एक नए सरणी में कॉपी किया जाएगा। इस नए सरणी को एक सन्निहित स्मृति स्थान में बनाया जाना चाहिए जो इसे धारण करने के लिए पर्याप्त है।
एंड्रयू

1
मेरे पास एक विशिष्ट मामला था, जहां मैंने सभी को जोड़ा और हटा रहा था, और एक-एक करके लूपिंग कर रहा था ... यहां लिंक की गई सूची सामान्य सूची से कहीं बेहतर थी ..
पीटर

26

मेरा पिछला उत्तर पर्याप्त सटीक नहीं था। जैसा कि वास्तव में यह भयानक था: डी लेकिन अब मैं बहुत अधिक उपयोगी और सही उत्तर पोस्ट कर सकता हूं।


मैंने कुछ अतिरिक्त परीक्षण किए। आप इसे निम्न लिंक से प्राप्त कर सकते हैं और इसे अपने पर्यावरण पर अपने हिसाब से देख सकते हैं: https://github.com/ukushu/DataStructuresTestsAndOther.git

छोटे परिणाम:

  • सरणी का उपयोग करने की आवश्यकता है:

    • तो अक्सर संभव है। यह तेज़ है और समान मात्रा की जानकारी के लिए सबसे छोटी रैम रेंज लेता है।
    • यदि आप आवश्यक कोशिकाओं की सटीक गिनती जानते हैं
    • यदि डेटा सरणी में सहेजा जाता है <85000 b (85000/32 = 2656 पूर्णांक डेटा के लिए तत्व)
    • यदि उच्च रैंडम एक्सेस गति की आवश्यकता है
  • सूची का उपयोग करने की आवश्यकता है:

    • यदि सूची के अंत में कोशिकाओं को जोड़ने की आवश्यकता है (अक्सर)
    • यदि सूची के आरंभ / मध्य में सेल जोड़ने की आवश्यकता है (NOT OFTEN)
    • यदि डेटा सरणी में सहेजा जाता है <85000 b (85000/32 = 2656 पूर्णांक डेटा के लिए तत्व)
    • यदि उच्च रैंडम एक्सेस गति की आवश्यकता है
  • लिंक्डलिस्ट को उपयोग करने की आवश्यकता है:

    • यदि सूची के आरंभ / मध्य / अंत में कोशिकाओं को जोड़ने की आवश्यकता है (अक्सर)
    • यदि केवल अनुक्रमिक पहुंच (आगे / पिछड़े) की आवश्यकता है
    • यदि आपको LARGE आइटम को सहेजने की आवश्यकता है, लेकिन आइटम की संख्या कम है।
    • बड़ी मात्रा में वस्तुओं के लिए बेहतर उपयोग न करें, क्योंकि यह लिंक के लिए अतिरिक्त मेमोरी का उपयोग करता है।

अधिक जानकारी:

निस्संदेह сюда описание изображения जानना दिलचस्प है:

  1. LinkedList<T>आंतरिक रूप से .NET में एक सूची नहीं है। यह भी लागू नहीं होता है IList<T>। और इसीलिए अनुक्रमणिका से संबंधित अनुपस्थित सूचकांक और विधियाँ हैं।

  2. LinkedList<T>नोड-पॉइंटर आधारित संग्रह है। .NET में यह दोगुना लिंक्ड इंप्लीमेंटेशन है। इसका अर्थ है कि पूर्व / अगले तत्वों का वर्तमान तत्व से लिंक है। और डेटा खंडित है - विभिन्न सूची ऑब्जेक्ट्स रैम के विभिन्न स्थानों में स्थित हो सकते हैं। इसके अलावा या ऐरे की LinkedList<T>तुलना में अधिक मेमोरी का उपयोग किया जाएगा List<T>

  3. List<T>.Net में जावा का विकल्प है ArrayList<T>। इसका मतलब है कि यह सरणी आवरण है। तो यह डेटा के एक सन्निहित ब्लॉक के रूप में मेमोरी में आवंटित किया जाता है। यदि आवंटित डेटा आकार 85000 बाइट्स से अधिक है, तो इसे बड़े ऑब्जेक्ट हीप में ले जाया जाएगा। आकार के आधार पर, यह ढेर विखंडन (स्मृति रिसाव का एक हल्का रूप) हो सकता है। लेकिन एक ही समय में यदि आकार <85000 बाइट्स - यह स्मृति में एक बहुत ही कॉम्पैक्ट और तेज़-पहुंच प्रतिनिधित्व प्रदान करता है।

  4. एकल सन्निहित ब्लॉक को यादृच्छिक अभिगम प्रदर्शन और स्मृति की खपत के लिए पसंद किया जाता है, लेकिन संग्रह के लिए जिन्हें आकार को नियमित रूप से बदलने की आवश्यकता होती है जैसे कि एक सरणी को आम तौर पर एक नए स्थान पर कॉपी करने की आवश्यकता होती है जबकि एक लिंक की गई सूची को केवल नए सम्मिलित किए गए मेमोरी को प्रबंधित करने की आवश्यकता होती है / हटाए गए नोड्स।


1
प्रश्न: "सरणी में सहेजे गए डेटा के साथ <या> 85.000 बाइट" का अर्थ है आप प्रति सरणी डेटा को सूचीबद्ध करते हैं / सूची आप करते हैं? यह समझा जा सकता है कि आप का मतलब पूरे सरणी का
डेटासेट है

मेमोरी में क्रमिक रूप से स्थित ऐरे तत्व। तो प्रति सरणी। मुझे तालिका में गलती के बारे में पता है, बाद में मैं इसे ठीक कर दूंगा :) (मुझे आशा है कि ....)
एंड्रयू

आवेषण में सूचियां धीमी होने के साथ, यदि किसी सूची में बहुत अधिक टर्नअराउंड (बहुत सारे आवेषण / हटाए गए) हैं तो हटाए गए स्थान पर कब्जा कर ली गई मेमोरी है और यदि ऐसा है, तो क्या इससे "पुनः" तेज हो जाता है?
रोब

18

सूची और लिंक्डलिस्ट के बीच अंतर उनके अंतर्निहित कार्यान्वयन में निहित है। सूची सरणी आधारित संग्रह (ArrayList) है। LinkedList नोड-पॉइंटर आधारित संग्रह (LinkedListNode) है। एपीआई स्तर के उपयोग पर, दोनों बहुत अधिक समान हैं, क्योंकि दोनों समान इंटरफेस जैसे कि ICollection, IEnumerable, आदि को लागू करते हैं।

प्रदर्शन के मामले में महत्वपूर्ण अंतर आता है। उदाहरण के लिए, यदि आप उस सूची को लागू कर रहे हैं जिसमें "INSERT" ऑपरेशन भारी है, लिंक्डलिस्ट आउटपरफॉर्म लिस्ट। चूंकि लिंक्डलिस्ट इसे ओ (1) समय में कर सकता है, लेकिन सूची में अंतर्निहित सरणी के आकार का विस्तार करने की आवश्यकता हो सकती है। अधिक जानकारी / विवरण के लिए आप लिंक्डलिस्ट और एरे डेटा संरचनाओं के बीच एल्गोरिथम अंतर पर पढ़ना चाह सकते हैं। http://en.wikipedia.org/wiki/Linked_list और Array

उममीद है कि इससे मदद मिलेगी,


4
सूची <T> सरणी आधारित (T []) है, न कि ArrayList आधारित। पुन: सम्मिलित करें: सरणी आकार समस्या नहीं है (दोहरीकरण एल्गोरिथ्म का अर्थ है कि अधिकांश समय इसे करने की आवश्यकता नहीं है): मुद्दा यह है कि इसे पहले सभी मौजूदा डेटा को ब्लॉक-कॉपी करना होगा, जिसमें थोड़ा सा लगता है समय।
मार्क ग्रेवेल

2
@Marc, 'दोहरीकरण एल्गोरिथ्म "केवल इसे O (logN) बनाता है, लेकिन यह O (1) से भी बदतर है
Ilya Ryzhenkov

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

@IlyaRyzhenkov - आप उस मामले के बारे में सोच रहे हैं जहां Addहमेशा मौजूदा सरणी के अंत में होता है। Listउस पर "काफी अच्छा" है, भले ही ओ (1) न हो। गंभीर समस्या तब होती है जब आपको कई Addएस की आवश्यकता होती है जो अंत में नहीं होती हैं । मार्क इशारा कर रहा है कि आपके द्वारा डाले जाने पर हर बार मौजूदा डेटा को स्थानांतरित करने की आवश्यकता है (न कि केवल जब रिसाइज की आवश्यकता हो) अधिक प्रदर्शन लागत है List
टूलमेकरसेव

समस्या यह है कि सैद्धांतिक बिग ओ अंकन पूरी कहानी नहीं बताते हैं। कंप्यूटर विज्ञान में, जिसकी सभी को कभी भी परवाह है, लेकिन वास्तविक दुनिया में इससे कहीं अधिक चिंतित है।
मैट

11

सरणियों से जुड़ी सूचियों का प्राथमिक लाभ यह है कि लिंक हमें वस्तुओं को कुशलता से पुनर्व्यवस्थित करने की क्षमता प्रदान करते हैं। सेडगेविक, पी। 91


1
IMO यह उत्तर होना चाहिए। लिंक्डलिस्ट का उपयोग तब किया जाता है जब एक गारंटीकृत ऑर्डर महत्वपूर्ण होता है।
राबार्दा

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

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

4

लिंक्डलिस्ट का उपयोग करने के लिए एक सामान्य परिस्थिति इस प्रकार है:

मान लीजिए कि आप एक बड़े आकार के साथ तार की एक सूची से कई निश्चित तारों को निकालना चाहते हैं, 100,000 का कहना है। हटाने के लिए तार को हाससेट डिक में देखा जा सकता है, और माना जाता है कि तार की सूची में 30,000 से 60,000 के बीच के तार शामिल हैं।

फिर 100,000 स्ट्रिंग्स के भंडारण के लिए सबसे अच्छी प्रकार की सूची क्या है? जवाब है लिंक्डलिस्ट। यदि वे एक ऐरेलिस्ट में संग्रहीत होते हैं, तो उस पर पुनरावृत्ति करना और मिलान किए गए स्ट्रिंग्स को हटा देना, अरबों परिचालनों तक ले जाता है, जबकि एक इटेरेटर और निष्कासन () विधि का उपयोग करके केवल लगभग 100,000 ऑपरेशन होते हैं।

LinkedList<String> strings = readStrings();
HashSet<String> dic = readDic();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()){
    String string = iterator.next();
    if (dic.contains(string))
    iterator.remove();
}

6
आप बहुत सी वस्तुओं को इधर-उधर किए बिना RemoveAllवस्तुओं को हटाने के लिए उपयोग कर सकते हैं List, या Whereदूसरी सूची बनाने के लिए LINQ से उपयोग कर सकते हैं। LinkedListहालांकि यहाँ उपयोग करने से अन्य प्रकार के संग्रहों की तुलना में नाटकीय रूप से अधिक मेमोरी का उपभोग होता है और मेमोरी लोकलिटी के खो जाने का अर्थ है कि यह इरीटेट करने के लिए काफी धीमा होगा, जिससे यह काफी खराब हो जाएगा List
सर्व

@Servy, ध्यान दें कि @ टॉम का उत्तर जावा का उपयोग करता है। मुझे यकीन नहीं है कि RemoveAllजावा में एक बराबर है।
आर्टुरो टॉरेस सांचेज़

3
@ ArturoTorresSánchez खैर यह सवाल विशेष रूप से बताता है कि यह .NET के बारे में है, ताकि यह जवाब बहुत कम उपयुक्त हो।
15

@ सरवाइव, तो आपको शुरू से ही इसका उल्लेख करना चाहिए।
आर्टुरो टॉरेस सेंचेज

यदि RemoveAllइसके लिए उपलब्ध नहीं है List, तो आप एक "संघनन" एल्गोरिथ्म कर सकते हैं, जो टॉम के लूप की तरह दिखेगा, लेकिन दो सूचकांकों के साथ और आइटम को सूची के आंतरिक सरणी में एक बार में रखने के लिए स्थानांतरित करने की आवश्यकता है। दक्षता ओ (एन) है, टॉम के एल्गोरिथ्म के लिए समान है LinkedList। दोनों संस्करणों में, स्ट्रिंग्स के लिए हाशसेट कुंजी की गणना करने का समय हावी है। यह कब उपयोग करना है इसका अच्छा उदाहरण नहीं है LinkedList
टूलमेकरसेव

2

जब आपको अंतर्निहित अनुक्रमणित पहुंच की आवश्यकता होती है, तो छंटनी (और इस बाइनरी खोज के बाद), और "ToArray ()" विधि, आपको सूची का उपयोग करना चाहिए।


2

अनिवार्य रूप से, एक List<>.NET एक सरणी पर एक आवरण है । A LinkedList<> लिंक की गई सूची है । तो यह सवाल नीचे आता है कि किसी सरणी और लिंक की गई सूची में क्या अंतर है, और लिंक की गई सूची के बजाय किसी सरणी का उपयोग कब किया जाना चाहिए। संभवतः आपके निर्णय के दो सबसे महत्वपूर्ण कारक जिनका उपयोग करना नीचे आता है:

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

1

यह टोनो नाम से अनुकूलित है के स्वीकृत उत्तर इसमें कुछ गलत माप को सही किया गया है।

कसौटी:

static void Main()
{
    LinkedListPerformance.AddFirst_List(); // 12028 ms
    LinkedListPerformance.AddFirst_LinkedList(); // 33 ms

    LinkedListPerformance.AddLast_List(); // 33 ms
    LinkedListPerformance.AddLast_LinkedList(); // 32 ms

    LinkedListPerformance.Enumerate_List(); // 1.08 ms
    LinkedListPerformance.Enumerate_LinkedList(); // 3.4 ms

    //I tried below as fun exercise - not very meaningful, see code
    //sort of equivalent to insertion when having the reference to middle node

    LinkedListPerformance.AddMiddle_List(); // 5724 ms
    LinkedListPerformance.AddMiddle_LinkedList1(); // 36 ms
    LinkedListPerformance.AddMiddle_LinkedList2(); // 32 ms
    LinkedListPerformance.AddMiddle_LinkedList3(); // 454 ms

    Environment.Exit(-1);
}

और कोड:

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

namespace stackoverflow
{
    static class LinkedListPerformance
    {
        class Temp
        {
            public decimal A, B, C, D;

            public Temp(decimal a, decimal b, decimal c, decimal d)
            {
                A = a; B = b; C = c; D = d;
            }
        }



        static readonly int start = 0;
        static readonly int end = 123456;
        static readonly IEnumerable<Temp> query = Enumerable.Range(start, end - start).Select(temp);

        static Temp temp(int i)
        {
            return new Temp(i, i, i, i);
        }

        static void StopAndPrint(this Stopwatch watch)
        {
            watch.Stop();
            Console.WriteLine(watch.Elapsed.TotalMilliseconds);
        }

        public static void AddFirst_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(0, temp(i));

            watch.StopAndPrint();
        }

        public static void AddFirst_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddFirst(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Add(temp(i));

            watch.StopAndPrint();
        }

        public static void AddLast_LinkedList()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (int i = start; i < end; i++)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        public static void Enumerate_List()
        {
            var list = new List<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        public static void Enumerate_LinkedList()
        {
            var list = new LinkedList<Temp>(query);
            var watch = Stopwatch.StartNew();

            foreach (var item in list)
            {

            }

            watch.StopAndPrint();
        }

        //for the fun of it, I tried to time inserting to the middle of 
        //linked list - this is by no means a realistic scenario! or may be 
        //these make sense if you assume you have the reference to middle node

        //insertion to the middle of list
        public static void AddMiddle_List()
        {
            var list = new List<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
                list.Insert(list.Count / 2, temp(i));

            watch.StopAndPrint();
        }

        //insertion in linked list in such a fashion that 
        //it has the same effect as inserting into the middle of list
        public static void AddMiddle_LinkedList1()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            LinkedListNode<Temp> evenNode = null, oddNode = null;
            for (int i = start; i < end; i++)
            {
                if (list.Count == 0)
                    oddNode = evenNode = list.AddLast(temp(i));
                else
                    if (list.Count % 2 == 1)
                        oddNode = list.AddBefore(evenNode, temp(i));
                    else
                        evenNode = list.AddAfter(oddNode, temp(i));
            }

            watch.StopAndPrint();
        }

        //another hacky way
        public static void AddMiddle_LinkedList2()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start + 1; i < end; i += 2)
                list.AddLast(temp(i));
            for (int i = end - 2; i >= 0; i -= 2)
                list.AddLast(temp(i));

            watch.StopAndPrint();
        }

        //OP's original more sensible approach, but I tried to filter out
        //the intermediate iteration cost in finding the middle node.
        public static void AddMiddle_LinkedList3()
        {
            var list = new LinkedList<Temp>();
            var watch = Stopwatch.StartNew();

            for (var i = start; i < end; i++)
            {
                if (list.Count == 0)
                    list.AddLast(temp(i));
                else
                {
                    watch.Stop();
                    var curNode = list.First;
                    for (var j = 0; j < list.Count / 2; j++)
                        curNode = curNode.Next;
                    watch.Start();

                    list.AddBefore(curNode, temp(i));
                }
            }

            watch.StopAndPrint();
        }
    }
}

आप देख सकते हैं कि परिणाम सैद्धांतिक प्रदर्शन के अनुसार हैं जो अन्य लोगों ने यहां प्रलेखित किए हैं। काफी स्पष्ट - LinkedList<T>सम्मिलन के मामले में बड़ा समय। मैंने सूची के मध्य से हटाने के लिए परीक्षण नहीं किया है, लेकिन परिणाम समान होना चाहिए। बेशक List<T>अन्य क्षेत्रों में यह O (1) यादृच्छिक पहुँच की तरह बेहतर प्रदर्शन करता है।


0

LinkedList<>कब का उपयोग करें

  1. आप नहीं जानते कि बाढ़ गेट के माध्यम से कितनी वस्तुएं आ रही हैं। उदाहरण के लिए,Token Stream
  2. जब आप सिरों पर \ डालने को हटाना चाहते थे।

बाकी सभी चीजों के लिए, इसका उपयोग करना बेहतर है List<>


6
मुझे नहीं लगता कि बिंदु 2 क्यों समझ में आता है। जब आप संपूर्ण सूची में कई सम्मिलन / विलोपन कर रहे हों, तो लिंक की गई सूचियाँ बहुत अच्छी हैं।
ड्रू नोक

इस तथ्य के कारण कि लिंक्डलिस्ट इंडेक्स आधारित नहीं हैं, आपको वास्तव में सम्मिलन या विलोपन के लिए पूरी सूची को स्कैन करना होगा जो O (n) जुर्माना लगाता है। सूची <> दूसरी तरफ Array रीसाइज़िंग से पीड़ित है, लेकिन फिर भी, लिंक्डलिस्ट की तुलना में IMO एक बेहतर विकल्प है।
एंटनी थॉमस

1
यदि आप LinkedListNode<T>अपने कोड में वस्तुओं का ट्रैक रखते हैं, तो आपको प्रविष्टि / विलोपन के लिए सूची को स्कैन करने की आवश्यकता नहीं है । यदि आप ऐसा कर सकते हैं, तो यह उपयोग करने से बेहतर है List<T>, विशेष रूप से बहुत लंबी सूचियों के लिए जहां आवेषण / निष्कासन अक्सर होते हैं।
ड्रू नोक

आपका मतलब हैशटेबल है? यदि ऐसा है, तो यह विशिष्ट स्पेस \ टाइम ट्रेडऑफ़ होगा जो कि प्रत्येक कंप्यूटर प्रोग्रामर को समस्या डोमेन के आधार पर एक विकल्प बनाना चाहिए :) लेकिन हाँ, यह तेजी से बना देगा।
एंटनी थॉमस

1
@AntonyThomas - नहीं, वह तत्वों के संदर्भों के आसपास से गुजरने के बजाय नोड्स के संदर्भ में गुजरने का मतलब है । यदि आपके पास एक तत्व है , तो सूची और लिंक्डलिस्ट दोनों का प्रदर्शन खराब है, क्योंकि आपको खोजना होगा। अगर आपको लगता है "लेकिन सूची के साथ मैं सिर्फ एक सूचकांक में पास कर सकता हूं": यह केवल तभी मान्य होगा जब आप सूची के बीच में एक नया तत्व नहीं डालेंगे। लिंक्डलिस्ट में यह सीमा नहीं है, यदि आप एक नोड पर पकड़ (और जब भी आप मूल तत्व का उपयोग करते हैं)। इसलिए आप नोड्स के साथ काम करने के लिए एल्गोरिथ्म को फिर से लिखते हैं, न कि कच्चे मानों के साथ। node.Value
ToolmakerSteve

0

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

लेकिन, मैं सिर्फ यह जोड़ना चाहता हूं कि ऐसे कई उदाहरण हैं जहां लिंक्डलिस्ट बेहतर दक्षता के लिए सूची से बेहतर विकल्प हैं।

  1. मान लें कि आप तत्वों के माध्यम से ट्रैवर्स कर रहे हैं और आप बहुत सारे सम्मिलन / विलोपन करना चाहते हैं; LinkedList इसे रैखिक O (n) समय में करता है, जबकि सूची इसे द्विघात O (n ^ 2) समय में करता है।
  2. मान लीजिए कि आप बड़ी वस्तुओं को बार-बार एक्सेस करना चाहते हैं, तो लिंक्डलिस्ट बहुत अधिक उपयोगी हो जाता है।
  3. लिंक्डलिस्ट का उपयोग करके Deque () और queue () को बेहतर तरीके से कार्यान्वित किया जाता है।
  4. एक बार जब आप कई और बड़ी वस्तुओं के साथ काम कर रहे होते हैं तो लिंक्डलिस्ट का आकार बढ़ाना बहुत आसान और बेहतर होता है।

आशा है कि कोई व्यक्ति इन टिप्पणियों को उपयोगी पाएगा।


ध्यान दें कि यह सलाह .NET के लिए है, जावा के लिए नहीं। जावा की लिंक्ड सूची कार्यान्वयन में आपके पास "वर्तमान नोड" की अवधारणा नहीं है, इसलिए आपको प्रत्येक प्रविष्टि के लिए सूची को पीछे करना होगा।
जोनाथन एलन

यह उत्तर केवल आंशिक रूप से सही है: 2) यदि तत्व बड़े हैं, तो तत्व को एक वर्ग नहीं एक संरचना लिखें, ताकि सूची केवल एक संदर्भ रखती है। तब तत्व का आकार अप्रासंगिक हो जाता है। 3) यदि आप सूची को "परिपत्र बफ़र" के रूप में उपयोग करते हैं, तो प्रारंभ में डालने या हटाने के बजाय, सूची और पंक्ति को कुशलतापूर्वक किया जा सकता है स्टीफनक्लेरी का डेक्स । 4) आंशिक रूप से सच है: जब कई वस्तुओं, एलएल के समर्थक को विशाल सन्निहित स्मृति की आवश्यकता नहीं होती है; नीचे नोड नोडर्स के लिए अतिरिक्त मेमोरी है।
टूलमेकरसैट

-2

इतने सारे औसत उत्तर यहाँ ...

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

लिंक की गई सूचियों का उपयोग करें जब

1) आप थ्रेड सुरक्षा चाहते हैं। आप बेहतर थ्रेड सेफ एल्गो बना सकते हैं। लॉकिंग लागत एक समवर्ती शैली सूची पर हावी होगी।

2) यदि आपके पास संरचनाओं की तरह एक बड़ी कतार है और हर समय कहीं भी हटाना या जोड़ना चाहते हैं। > 100K सूचियां मौजूद हैं लेकिन ये आम नहीं हैं।


3
यह प्रश्न दो सी # कार्यान्वयन के बारे में था, सामान्य रूप से लिंक की गई सूची नहीं।
जोनाथन एलन

प्रत्येक भाषा में समान
user1496062

-2

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


1
अपने बयान है कि पुन Dequeहै "लिंक्ड सूची के समान है, लेकिन बेहतर प्रदर्शन के साथ" । कि बयान अर्हता प्राप्त करें: Dequeतुलना में बेहतर प्रदर्शन है LinkedList, अपने विशिष्ट कोड के लिए । आपके लिंक के बाद, मैं देखता हूं कि दो दिन बाद आपने इवान स्टोव से सीखा कि यह लिंक्डलिस्ट की अक्षमता नहीं थी, बल्कि आपके कोड में एक अक्षमता थी। (और यहां तक ​​कि अगर यह लिंक्डलिस्ट की अक्षमता थी, तो यह एक सामान्य कथन को उचित नहीं ठहराएगा कि डी अधिक कुशल है; केवल विशिष्ट मामलों में।)
टूलमेकरसैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.