इतनी देर पहले मैंने गिनती नहीं की थी।
java.util.LinkedList
का उपयोग
java.util.LinkedList
के कार्यान्वयन के रूप में करने के लिए कोई बहाना नहीं है। लेकिन कुछ ने मुझे उसके लिए खोजा। चलिए इसका पता लगाते हैं। किसी भी सक्षम जावा विशेषज्ञ को पता है कि
java.util.ArrayList
का उपयोग तब किया जाना चाहिए जब हमें सूचकांक द्वारा त्वरित पहुंच की आवश्यकता हो, और
java.util.LinkedList
अगर हमें सूची के बीच में तत्वों को सम्मिलित करने या हटाने की आवश्यकता है। उनमें से बहुतों का अनुमान नहीं है कि यदि हम सूची के मध्य में तत्वों को सम्मिलित करते हैं या हटाते हैं
remove(int index)
और
add(int index, E element)
विधियों का, तो सूची
O(N)
के आकार के लिए आवश्यक तत्व आनुपातिक की खोज में औसत समय लगेगा। । तो
java.util.LinkedList
का उपयोग करने का लाभ कब है?
पुनरावृत्तियों का उपयोग करते समय। अधिक सटीक रूप से, जब आप
java.util.ListIterator
माध्यम से तत्वों को हटाते या सम्मिलित करते हैं। अंत में, बहाने की तलाश में, मुझे एक बहुत ही वास्तविक कोड उदाहरण मिला, जिस पर
java.util.LinkedList
पर एक महत्वपूर्ण लाभ देता है। यह सबसे सरल फ़िल्टरिंग एल्गोरिथ्म है जो सूची से उन सभी तत्वों को हटा देता है जो निर्दिष्ट स्थिति को संतुष्ट नहीं करते हैं।
for (Iterator<E> i = list.iterator(); i.hasNext(); ) { E val = i.next(); if (!condition(val)) { i.remove(); } }
एक ही कोड को आसानी से एक अतिरिक्त सूची का उपयोग करके फिर से लिखा जा सकता है, और फिर
java.util.ArrayList
साथ एल्गोरिदम, कम से कम, मूल आकार पर एक द्विघात निर्भरता नहीं होगी।
List<E> list1 = new ArrayList<E>(); for (Iterator<E> i = list.iterator(); i.hasNext(); ) { E val = i.next(); if (condition(val)) { list1.add(val); } } list.clear(); list.addAll(list1);
लेकिन यह सही नहीं है कि डेटा संरचना हमारे लिए एक एल्गोरिथ्म तय करती है। लेकिन यह एल्गोरिथ्म था जिसने मुझे यह सोचने के लिए प्रेरित किया कि एक ऐसी सूची कैसे बनाई जाए जो कि
O(1)
दौरान अधिकांश संचालन करेंगे।
ऐसा करने के लिए, हमें इस धारणा की आवश्यकता है: "ऑपरेशन सम्मिलित करें और हटाएं। कंधे से कंधा मिलाकर।" बेशक, हम एक ऐसी स्थिति की कल्पना कर सकते हैं जिसमें सम्मिलित और हटाए जाने वाले ऑपरेशन बेतरतीब ढंग से घटित होंगे, लेकिन इस मामले में न तो
java.util.ArrayList
और न ही
java.util.ArrayList
हमें बचाएगा।
java.util.LinkedList
कि हम लड़ते हैं। दरअसल, एक मनमाना तत्व जोड़ने या हटाने के लिए,
java.util.ArrayList
को आमतौर पर सरणी के तत्वों की संख्या को O (N) के आकार के आनुपातिक रूप से स्थानांतरित करना चाहिए, और
java.util.LinkedList
को इसे
O(N)
करना चाहिए।
विचार यह है। सूची एक सरणी में संग्रहीत नहीं है, लेकिन 2x में है। इसके अलावा, प्रत्येक सरणी इसे अपनी संपूर्णता में समायोजित कर सकती है।

सूची के बीच में एक तत्व सम्मिलित करते समय, हम इसे अंतराल में सम्मिलित करते हैं। लेकिन आखिरकार, हम उस तत्व को गलत जगह डालना चाहते हैं जहां अलगाव होता है। ऐसा करने के लिए, हम तत्वों का हिस्सा स्थानांतरित करते हैं ताकि अंतराल सही जगह पर चले।

आप कहेंगे: "हाँ, हमने
java.util.ArrayList
के मामले की तुलना में कम तत्वों को स्थानांतरित किया है, लेकिन यह अभी भी सूची के आकार के समानुपाती है।" आप सही हैं, लेकिन अगर हम अपनी धारणा को याद करते हैं, तो हर बार, पहले को छोड़कर, हम आगे बढ़ेंगे। तत्वों की एक छोटी संख्या।
डिलीट करते समय भी यही बात होती है। अंतर उस स्थान पर स्थानांतरित कर दिया जाता है जहां से तत्व हटा दिया गया था।
मैंने जल्दी से इस सूची का कार्यान्वयन लिखा। और उन्होंने परीक्षणों को चलाया: भरने, अनुक्रमिक स्कैनिंग, सूचकांक द्वारा स्कैनिंग, फ़िल्टरिंग, एक तत्व द्वारा पूरी सूची को सिर से हटाना। क्योंकि परिणाम विभिन्न सूचियों के लिए व्यापक रूप से भिन्न होते हैं; उन्हें कल्पना करना काफी कठिन है। तो सिर्फ टेबल दिखाओ। चार्ट होंगे, लेकिन बाद में। टेबल मिलीसेकंड में विभिन्न संस्करणों में विभिन्न कार्यों के निष्पादन का समय दिखाते हैं।
ArrayList
आकार | भरण | अनुक्रम | सूची | छानने का काम | पहले हटाओ |
20000 | 0 | 0 | 0 | 94 | 47 |
40000 | 0 | 0 | 0 | 406 | 187 |
60000 | 16 | 0 | 0 | 891 | 437 |
80000 | 0 | 0 | 0 | 1578 | 782 |
100000 | 0 | 15 | 0 | 2453 | 1219 |
120000 | 16 | 0 | 15 | 3516 | 1750 |
140000 | 16 | 0 | 0 | 4796 | 2391 |
160000 | 16 | 0 | 15 | 6219 | 3125 |
180000 | 16 | 0 | 15 | 7969 | 3984 |
200000 | 63 | 0 | 0 | 9859 | 4844 |
जैसा कि आप टेबल से देख सकते हैं,
java.util.ArrayList
को भरने और किसी भी स्कैनिंग के साथ पूरी तरह से मुकाबला करता है, और फ़िल्टरिंग और यहां तक कि सिर से सूची को हटाने पर एक कुचल हार का सामना करना पड़ता है।
LinkedList
आकार | भरण | अनुक्रम | सूची | छानने का काम | पहले हटाओ |
20000 | 0 | 0 | 406 | 0 | 0 |
40000 | 31 | 0 | 1985 | 0 | 0 |
60000 | 15 | 0 | 3828 | 16 | 0 |
80000 | 0 | 0 | 8359 | 0 | 0 |
100000 | 16 | 0 | 24,891 | 0 | 15 |
120000 | 16 | 0 | 43,562 | 16 | 0 |
140000 | 16 | 15 | 52,985 | 0 | 15 |
160000 | 16 | 0 | 57,047 | 15 | 0 |
180000 | 79 | 0 | 121,531 | 0 | 15 |
200000 | 32 | 15 | 152,250 | 16 | 16 |
java.util.LinkedList
का कमजोर बिंदु इंडेक्स एक्सेस है, लेकिन फ़िल्टरिंग ऑपरेशन बहुत तेज है।
DoubleArrayList
आकार | भरण | अनुक्रम | सूची | छानने का काम | पहले हटाओ |
20000 | 0 | 0 | 0 | 0 | 0 |
40000 | 16 | 0 | 0 | 0 | 0 |
60000 | 0 | 0 | 0 | 15 | 0 |
80000 | 0 | 0 | 16 | 0 | 0 |
100000 | 16 | 0 | 0 | 15 | 0 |
120000 | 16 | 0 | 0 | 15 | 0 |
140000 | 16 | 16 | 0 | 15 | 0 |
160000 | 16 | 16 | 0 | 15 | 0 |
180000 | 47 | 16 | 0 | 15 | 0 |
200000 | 32 | 0 | 15 | 0 | 16 |
और अंत में,
org.kefirsf.list.DoubleArrayList
का मेरा कार्यान्वयन किसी भी परीक्षण पर विफल नहीं होता है।
चलो बड़े संस्करणों पर लिंक्डलिस्ट के साथ तुलना करें।
भरने

छानने

सिर निकालना

इन सभी
DoubleArrayList
यह देखा जा सकता है कि
DoubleArrayList
java.util.LinkedList
तुलनीय समय के लिए विभिन्न परिचालनों पर काम कर रहा है। भले ही हमेशा बेहतर न हो। मुख्य बात यह है कि सरणी के आकार पर कोई द्विघात निर्भरता नहीं है, और सभी ऑपरेशन
O(N)
, जिसका अर्थ है कि
O(1)
में औसतन एकल ऑपरेशन किए जाते हैं। इस प्रकार, लक्ष्य प्राप्त किया जाता है।
कोड
org.kefirsf.list.DoubleArrayList
GitHub पर उपलब्ध है:
github.com/kefirfromperm/multi-array-listसावधानी: औद्योगिक विकास में इसका उपयोग करने का प्रयास न करें।
org.kefirsf.list.DoubleArrayList
अभी भी परीक्षणों द्वारा अच्छी तरह से कवर नहीं किया गया है, इसके उपयोग से मेमोरी लीक हो सकती है।