क्या किसी संग्रह में जोड़ना और फिर उसे क्रमबद्ध संग्रह में जोड़ना तेज़ है?


79

अगर मेरे पास Mapऐसा है:

HashMap<Integer, ComparableObject> map;

और मैं प्राकृतिक ऑर्डरिंग का उपयोग करके सॉर्ट किए गए मानों का एक संग्रह प्राप्त करना चाहता हूं, जो सबसे तेज़ है?

(ए)

जैसे एक संग्रहणीय संग्रह का एक उदाहरण बनाएँ ArrayList , मान जोड़ें, फिर इसे क्रमबद्ध करें:

List<ComparableObject> sortedCollection = new ArrayList<ComparableObject>(map.values());
Collections.sort(sortedCollection);

(बी)

जैसे एक संग्रहित संग्रह का एक उदाहरण बनाएँ TreeSet, फिर मान जोड़ें:

Set<ComparableObject> sortedCollection = new TreeSet<ComparableObject>(map.values());

ध्यान दें कि परिणामी संग्रह कभी संशोधित नहीं होता है, इसलिए छंटाई केवल एक बार होने की आवश्यकता होती है।


यह इनपुट डेटा के क्रम पर निर्भर करता है - उदाहरण के लिए। अगर आपकी बहुत सारी पंक्तियाँ हैं और ORDER का उपयोग करें, तो यह एक मामला है - यदि आपके पास गाइड का यादृच्छिक सेट है - दूसरा।
बोरिस ट्रेखोव

इसके बजाय एक ट्रीपाइप का उपयोग क्यों नहीं किया जाता है?
थोर्बोजर्न रेवन एंडरसन

ट्री-मैप यहां मदद नहीं करेगा क्योंकि छंटाई के लिए मूल्यों पर जगह लेने की जरूरत है ( ComparableObject) कुंजी ( Integer) नहीं।
gutch

3
यह भी ध्यान दें कि एक सेट केवल विशिष्ट प्रविष्टियों का समर्थन करता है। दूसरी ओर एक HashMap के "मूल्यों" संग्रह में डुप्लिकेट हो सकते हैं। उस कोण से, ट्रीसेट एक अच्छा समाधान नहीं है।
14

@gutch, आपको उपयोगी होने के लिए " stackoverflow.com/questions/3759112/… " पर मेरा उत्तर मिल सकता है।
रिचर्ड

जवाबों:


87

log(n)ट्रीसेट में add()/remove()/contains()विधियों के लिए एक समय जटिलता की गारंटी है । एक ऑपरेशन ArrayListलेता n*log(n)है, लेकिन add()/get()केवल 1ऑपरेशन लेता है ।

इसलिए यदि आप मुख्य रूप से प्राप्त कर रहे हैं, और अक्सर सॉर्ट नहीं करते हैं, ArrayListतो बेहतर विकल्प है। यदि आप अक्सर छाँटते हैं, लेकिन यह नहीं TreeSetजानते कि एक बेहतर विकल्प होगा।


मेरे मामले में हमें केवल परिणामी संग्रह के माध्यम से पुनरावृति की आवश्यकता है, यह कभी भी संशोधित नहीं होता है। तो आपके उत्तर के आधार पर ArrayListयहाँ बेहतर विकल्प है।
gutch

इसके अतिरिक्त सरणी छँटाई समानांतर में किया जा सकता है और बेहतर कैश प्रदर्शन है।
कैसर

21

सैद्धांतिक रूप से, अंत में छंटनी तेज होनी चाहिए। प्रक्रिया के माध्यम से सॉर्ट की गई स्थिति को बनाए रखने में अतिरिक्त CPU समय शामिल हो सकता है।

CS के दृष्टिकोण से, दोनों ऑपरेशन NlogN हैं, लेकिन 1 प्रकार में कम निरंतर होना चाहिए।


4
+1 उन मामलों में से एक जहां सिद्धांत और वास्तविकता काट दी जाती है। :) मेरे अनुभव में, अंत में छंटनी की वजह से परिमाण का क्रम तेज़ हो जाता है ...
स्टेवल्स

जब तक वे O (N) न हों, जो पूर्णांक डेटा का मामला होगा। प्राथमिकता कतारों में सम्मिलन, हटाने और प्रबंधन के लिए ओ (लॉग एन) संचालन भी शामिल है।
रिचर्ड

10

दोनों दुनिया के सर्वश्रेष्ठ का उपयोग क्यों नहीं करते? यदि आप इसे फिर से उपयोग नहीं कर रहे हैं, तो ट्रीसेट का उपयोग करें और सामग्री के साथ एक ArrayList को इनिशियलाइज़ करें

List<ComparableObject> sortedCollection = 
    new ArrayList<ComparableObject>( 
          new TreeSet<ComparableObject>(map.values()));

संपादित करें:

मैंने एक बेंचमार्क बनाया है (आप इसे pastebin.com/5pyPMJav पर एक्सेस कर सकते हैं तीन दृष्टिकोणों (ArrayList + Collections.sort, TreeSet और मेरे दोनों दुनिया के दृष्टिकोण के सर्वश्रेष्ठ) का परीक्षण करने के लिए ) बनाया है और मेरा हमेशा जीतता है। परीक्षण फ़ाइल 10000 तत्वों के साथ एक नक्शा बनाती है, जिनमें से मूल्यों में एक जानबूझकर भयानक तुलनित्र होता है, और फिर तीनों रणनीतियों में से प्रत्येक को डेटा पर (बी) डेटा सॉर्ट करने का मौका मिलता है। यहाँ कुछ नमूना आउटपुट है (आप इसे स्वयं परीक्षण कर सकते हैं):

संपादित करें: मैंने एक पहलू को जोड़ा है जो Thingy.compareTo (थिंगी) पर कॉल लॉग करता है और मैंने प्रायोरिटी क्यू के आधार पर एक नई रणनीति भी जोड़ी है जो पिछले समाधानों (या कम से कम छंटाई) में से बहुत तेज है।

compareTo() calls:123490
Transformer ArrayListTransformer
    Creation: 255885873 ns (0.255885873 seconds) 
    Iteration: 2582591 ns (0.002582591 seconds) 
    Item count: 10000

compareTo() calls:121665
Transformer TreeSetTransformer
    Creation: 199893004 ns (0.199893004 seconds) 
    Iteration: 4848242 ns (0.004848242 seconds) 
    Item count: 10000

compareTo() calls:121665
Transformer BestOfBothWorldsTransformer
    Creation: 216952504 ns (0.216952504 seconds) 
    Iteration: 1604604 ns (0.001604604 seconds) 
    Item count: 10000

compareTo() calls:18819
Transformer PriorityQueueTransformer
    Creation: 35119198 ns (0.035119198 seconds) 
    Iteration: 2803639 ns (0.002803639 seconds) 
    Item count: 10000

अजीब बात है, मेरा दृष्टिकोण चलना में सबसे अच्छा प्रदर्शन करता है (मुझे लगता है कि चलना में ArrayList दृष्टिकोण के लिए कोई मतभेद नहीं होगा, क्या मेरे बेंचमार्क में बग है?)

डिस्क्लेमर: मुझे पता है कि यह शायद एक बहुत बड़ा बेंचमार्क है, लेकिन यह आपको पूरे बिंदु को पाने में मदद करता है और मैंने निश्चित रूप से अपने दृष्टिकोण को जीतने के लिए इसमें हेरफेर नहीं किया है।

(कोड में बराबर / हैशकोड / तुलना करने वाले बिल्डरों के लिए कॉमन्स / लैंग अपाचे के लिए एक निर्भरता है, लेकिन इसे बाहर रिफैक्ट करने के लिए आसान होना चाहिए)


3
यह वास्तव में दोनों दुनिया का सबसे बुरा नहीं होगा? मुझे केवल प्राकृतिक क्रम में एक संग्रह की आवश्यकता है, जो कि new TreeSet<ComparableObject>(map.values())रिटर्न है। लपेटकर है कि एक ArrayListमें सिर्फ अनावश्यक संचालन जोड़ने जा रहा है।
10

1
अंतिम लक्ष्य एक हल था Collection... जो TreeSetहै। मुझे लगता है कि कोई मूल्य सेट को यहां सूची में परिवर्तित नहीं कर रहा है।
गन्सलिंगर

यह रैपिंग नहीं है, यह प्रारंभिक है। और सरणीसूची पुन: प्राप्त करने के लिए बेहतर है, जबकि ट्रीसेट छँटाई में बेहतर है
सीन पैट्रिक फ्लोयड

4
मैं बेंचमार्क लिखने में आपके द्वारा किए गए प्रयास की सराहना करता हूं! हालांकि मुझे लगता है कि इसमें दोष है। ऐसा प्रतीत होता है कि जेवीएम Transformerऐसे उदाहरणों को चलाता है जो बाद में पहले की तुलना में तेजी से सूची में हैं: BestOfBothWorldsTransformerपहले रखो और यह अचानक बहुत धीमी गति से चलता है। इसलिए मैंने बेतरतीब ढंग से एक ट्रांसफार्मर का चयन करने और परिणामों को औसत करने के लिए आपके बेंचमार्क को फिर से लिखा है। मेरे परीक्षण में TreeSetTransformerलगातार धड़कता है BestOfBothWorldsTransformer, जो लगातार धड़कता है ArrayListTransformer- वह नहीं जो मुझे उम्मीद थी! हालांकि अंतर छोटा है। देखें pastebin.com/L0t5QDV9
gutch

1
मुझे पता है कि आपका अगला सवाल क्या है: प्रायोरिटी क्यूट्रांसफॉर्मर के बारे में क्या? क्या यह सामूहिक रूप से दूसरों की तुलना में तेज़ नहीं है? हां हां यह बहुत बुरा है, हालांकि यह आदेश सही नहीं है! ऊपर मेरे कोड में प्रत्येक ट्रांसफार्मर द्वारा उत्पन्न सूचियों पर एक नज़र डालें, और आप देखेंगे कि प्रायोरिटी क्यूट्रांसफॉर्मर वास्तव में क्रम में नहीं है! शायद मैं PriorityQueueगलत तरीके से उपयोग कर रहा हूं ? क्या आपके पास इसका एक उदाहरण है जो वास्तव में सही तरीके से छंटनी कर रहा है?
गच

6

यदि आप B को लागू करना चाहते हैं, तो नीचे दिए गए TreeSet के बारे में मेरी टिप्पणी को पढ़ना सुनिश्चित करें)

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

हालाँकि, यदि आप चाहते हैं कि सभी प्रकार के समय की गारंटी दी जाए या आप संभवतः तत्वों को बार-बार जोड़ / हटा रहे हैं, तो क्रमबद्ध संग्रह का उपयोग करें और पुनरावृति पर हिट लें।

इसलिए आपके मामले में मैं कहूंगा कि A) बेहतर विकल्प है। सूची को एक बार क्रमबद्ध किया जाता है, बदलता नहीं है और इसलिए एक सरणी होने से लाभ होता है। Iteration बहुत तेज़ होना चाहिए, खासकर यदि आप इसके ArrayList को जानते हैं और Iterator के बजाय सीधे ArrayList.get () का उपयोग कर सकते हैं।

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


1
के बारे में अच्छी बात TreeSetहै, तो compareTo रिटर्न 0. मैं निर्धारित किया है कि इस विशेष मामले में compareTo कार्यान्वयन वापस कभी नहीं होगा 0 संभावित डेटा गुम, दोनों बहुत TreeSetऔर ArrayListएक ही व्यवहार करेगा। हालाँकि मुझे रिमाइंडर के लिए धन्यवाद देने से पहले ही उस समस्या ने पकड़ लिया है!
gutch

ट्रीसैट की तुलना में एक वरीयता क्रमबद्ध करने के लिए प्रायोरिटीक्यू शायद बेहतर है।
लॉकर

हाँ, मेरे बेंचमार्क में (मेरा जवाब देखें) प्रायोरिटी क्यू आउटफॉर्मफॉर्म ट्रीसेट को 600 से 700% तक।
सीन पैट्रिक फ्लोयड

PriorityQueueवास्तव में तेजी से प्रदर्शन करता है, लेकिन जब मैंने कोशिश की कि मूल्यों को वास्तव में हल नहीं किया गया था - जाहिर है कि यह इतनी तेजी से क्यों था! हो सकता है कि मैंने यह गलत समझा हो कि प्रायोरिटी क्यू का उपयोग कैसे करें ... इसका एक उदाहरण वास्तव में काम करना उपयोगी होगा।
गच

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

1

Collections.sort मर्जसेट का उपयोग करता है जिसमें O (nlog n) है।

TreeSetमें रेड-ब्लैक ट्री अंतर्निहित है, बुनियादी कार्यों में O (logn) है। इसलिए n तत्वों में O (nlog n) भी है।

तो दोनों एक ही बड़े O एल्गोरिथ्म हैं।


6
हालांकि यह सच है, यह कुछ महत्वपूर्ण लागतों को शामिल करता है। MergeSort O (n log n) समय में काम करता है, लेकिन Red-Black को सम्मिलन के लिए O (n लॉग एन) की आवश्यकता होगी और फिर से हटाने के लिए। बिग-ओ नोटेशन एल्गोरिदम में महत्वपूर्ण अंतर छुपाता है।
रिचर्ड

0

SortedSet में सम्मिलित करना O (log (n)) है (BUT! वर्तमान n और अंतिम n नहीं)। सूची में सम्मिलित करना 1 है।

एक SortedSet में छंटनी पहले से ही सम्मिलित करने में शामिल है, इसलिए यह 0. एक सूची में छंटनी हे (n * log (n)) है।

तो SortedSet कुल जटिलता O (n * k) है, k <log (n) सभी मामलों के लिए लेकिन अंतिम है। इसके बजाय, सूची कुल जटिलता हे (एन * लॉग (एन) + एन), इसलिए हे (एन * लॉग (एन))।

तो, SortedSet गणितीय सर्वश्रेष्ठ प्रदर्शन किया है। लेकिन अंत में, आपके पास एक सूची के बजाय एक सेट होता है (क्योंकि SortedList मौजूद नहीं है) और सेट आपको सूची से कम सुविधाएँ प्रदान करता है। तो मेरी राय में, उपलब्ध सुविधाओं और प्रदर्शन के लिए सबसे अच्छा समाधान शॉन पैट्रिक फ्लोयड द्वारा प्रस्तावित एक है:

  • डालने के लिए एक SortedSet का उपयोग करें,
  • वापस जाने के लिए एक सूची बनाने के लिए एक पैरामीटर के रूप में SortedSet रखो।

0

शानदार सवाल और शानदार जवाब। बस मैंने सोचा कि कुछ बिंदुओं को ध्यान में रखूंगा:

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

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

सॉर्ट -> इसका उपयोग करें -> भूल जाओ

यदि आप सॉर्ट किए गए संग्रह में एक नया तत्व जोड़ते हैं, तो आपको फिर से संग्रह को सॉर्ट करना होगा, क्योंकि नए तत्व को सम्मिलित करते समय आदेश की गारंटी नहीं है।

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

औचित्य: आप हर समय संग्रह के आदेश की परवाह करते हैं। आप चाहते हैं कि इसे हर हाल में सुलझाया जाए। इसलिए यदि आप लगातार उन तत्वों को जोड़ते या हटाते हैं जिनकी गारंटी है कि संग्रह को क्रमबद्ध किया गया है। तो मूल रूप से:

सम्मिलित करें / निकालें -> इसका उपयोग करें (आपके पास हर समय यह गारंटी है कि संग्रह क्रमबद्ध है)

कोई विशिष्ट क्षण नहीं है जहां आपको संग्रह को सॉर्ट करने की आवश्यकता है, इसके बजाय, आप चाहते हैं कि संग्रह को हर समय सॉर्ट किया जाए।

ट्रीसेट का उपयोग करने का नकारात्मक पहलू यह है कि इसे सॉर्ट किए गए संग्रह को रखने की आवश्यकता है। यह एक लाल-काले पेड़ का उपयोग करता है, और इसे प्राप्त करने के लिए ओ (लॉग एन) समय की आवश्यकता होती है, संचालन करते हैं।

जबकि अगर आप एक साधारण संग्रह का उपयोग करते हैं, जैसे कि ArrayList, get, add संचालन तो O (1) निरंतर समय है।

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