क्या .NET संग्रह सबसे तेजी से खोज प्रदान करता है


143

मेरे पास 60k आइटम हैं जिन्हें 20k लुकअप सूची के खिलाफ जांचना आवश्यक है। वहाँ एक संग्रह वस्तु (की तरह है List, HashTable) जो एक exceptionly तेजी से प्रदान करता है Contains()विधि? या मुझे खुद लिखना पड़ेगा? अन्य पासवर्डों में, डिफ़ॉल्ट Contains()विधि बस प्रत्येक आइटम को स्कैन करती है या क्या यह एक बेहतर खोज एल्गोरिदम का उपयोग करती है।

foreach (Record item in LargeCollection)
{
    if (LookupCollection.Contains(item.Key))
    {
       // Do something
    }
}

ध्यान दें । लुकअप सूची पहले से ही क्रमबद्ध है।


सूची में शामिल वस्तुओं की सूची के लिए काम नहीं करता है क्योंकि यह संदर्भों की तुलना कर रहा है।
फि र

2
डेटा सॉर्ट किया गया? बाइनरी खोज - @ मार्क का उत्तर देखें।
हमीश स्मिथ

हैशटेबल मेरे अनुभव में 2 मी आइटम तक कुछ भी धड़कता है
क्रिस एस

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

2
यदि आप इस सामान को सरल बनाना चाहते हैं, लेकिन हैशसेट से बचें, तो System.Collections.Generic.SreadList (TKey, TValue) के बारे में मत भूलना।
ब्रायन

जवाबों:


141

सबसे सामान्य मामले में, System.Collections.Generic.HashSetआपके डिफ़ॉल्ट "वर्कनेश" वर्कहॉर्स डेटा संरचना के रूप में विचार करें, क्योंकि मूल्यांकन के लिए निरंतर समय लगता है Contains

"सबसे तेज़ खोज योग्य संग्रह क्या है" का वास्तविक उत्तर आपके विशिष्ट डेटा आकार, ऑर्डर-नेस, लागत-हैशिंग, और खोज आवृत्ति पर निर्भर करता है।


36
नोट: हैशकोड फ़ंक्शन को ओवरराइड करना न भूलें। अतिरिक्त प्रदर्शन के लिए, अपने कंस्ट्रक्टर में अपने हैशकोड को पहले से तैयार करें।
ब्रायन

1
@ ब्रायन: अच्छी बात है। मैं (आधारहीन) रिकॉर्ड मान रहा था। कुछ प्रकार का एक अंतर्निहित प्रकार था।
जिमी

3
@ ब्रायन: पहले से तैयार होने के बजाय मैं पहली बार जनरेट स्टोर करना पसंद करता हूं, तो कंस्ट्रक्टर को धीमा करने के लिए कुछ ऐसा क्यों है जिसे आप नहीं जानते कि इसका उपयोग किया जाएगा?
jmservera

8
FYI करें: प्रदर्शन परीक्षण - मैंने स्ट्रिंग्स के लिए सूची <T> और हैशसेट <T> के बीच तुलना की। मैंने पाया कि हैशसेट लिस्ट से लगभग 1000 गुना तेज था।
क्वांगो

10
@ क्यूंगो: 3 साल बाद, लेकिन वास्तव में यदि आप अपने डेटा के आकार को निर्दिष्ट नहीं करते हैं तो इस प्रदर्शन की तुलना का मतलब कुछ भी नहीं है: हैशसेट में ओ (1) खोज है, सूचियों में ओ (एन) खोज है, इसलिए प्रदर्शन का अनुपात आनुपातिक है एन।
क्लेमेंट

73

यदि आपको ऑर्डर करने की आवश्यकता नहीं है, तो प्रयास करें HashSet<Record>(.Net 3.5 पर नया)

यदि आप करते हैं, एक का उपयोग List<Record>और कॉल BinarySearch



2
या ImmutableSortedSetउससे भी बेहतर, System.ImmutableCollections से
अलेक्सई S

24

क्या आपने विचार किया List.BinarySearch(item)?

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


1
आप सही कह रहे हैं, एक हैश तब कुछ अवांछनीय समस्याएं ला सकता है जब एक कुंजी के रूप में उत्परिवर्तित वस्तुओं का उपयोग कर रहा है।
jmservera

10

आपको इस ब्लॉग को पढ़ना चाहिए कि गति ने एकल और बहु-थ्रेडेड तकनीकों का उपयोग करके प्रत्येक के लिए कई अलग-अलग प्रकार के संग्रह और विधियों का परीक्षण किया।

परिणामों के अनुसार, एक सूची और SortedList पर एक बाइनरीसर्च शीर्ष प्रदर्शन करने वाले थे जो लगातार गर्दन को एक "मूल्य" के रूप में देखते हैं।

"कुंजियों" के लिए अनुमति देने वाले संग्रह का उपयोग करते समय, शब्दकोश, समवर्ती, हैशसेट और हैशटेबल्स ने समग्र रूप से सर्वश्रेष्ठ प्रदर्शन किया।


4

दोनों सूचियों को क्रमबद्ध क्रम में x और y रखें।

यदि x = y, अपनी कार्रवाई करते हैं, यदि x <y, अग्रिम x, यदि y <x, अग्रिम y तब तक जब तक कि सूची खाली न हो।

इस चौराहे का रन समय न्यूनतम (आकार (x), आकार (y)) के समानुपाती होता है

एक .Contains () लूप चलाएं, यह x * y के लिए आनुपातिक है जो बहुत खराब है।


अधिक कुशल एल्गोरिथ्म के लिए +1। यहां तक ​​कि अगर सूचियां वर्तमान में अनसोल्ड हैं, तो पहले उन्हें सॉर्ट करना और फिर इस एल्गोरिथ्म को चलाना अधिक कुशल होगा।
मैट बोहम

हालांकि रनटाइम सबसे खराब स्थिति में अधिकतम (आकार (x), आकार (y) का आनुपातिक नहीं होगा? उदाहरण: int [] x = {99,100}; int [] y = {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
मैट बोएहम

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

3

यदि आपकी वस्तुओं को छांटना संभव है, तो ऐसा करने का बहुत तेज़ तरीका है फिर हैशटेबल या बी-ट्री में मुख्य लुकअप करना। यद्यपि यदि आप आइटम नहीं हैं तो आप वास्तव में उन्हें बी-ट्री में नहीं डाल सकते हैं।

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

Walk lookup list
   While items in check list <= lookup list item
     if check list item = lookup list item do something
   Move to next lookup list item

हां, यह सच है। यदि आपके पास दो छांटे गए सूची हैं, तो आपको केवल प्रत्येक बार एक बार पार करना होगा।
डेन्वर

3

यदि आप .net 3.5 का उपयोग कर रहे हैं, तो आप क्लीनर कोड का उपयोग कर सकते हैं:

foreach (Record item in LookupCollection.Intersect(LargeCollection))
{
  //dostuff
}

मेरे पास .Net 3.5 यहाँ नहीं है और इसलिए यह अप्रयुक्त है। यह एक विस्तार विधि पर निर्भर करता है। ऐसा नहीं है कि LookupCollection.Intersect(LargeCollection)शायद उतना ही नहीं है LargeCollection.Intersect(LookupCollection)... बाद वाला शायद बहुत धीमा है।

यह मानता है लुकअपलेक्शन एक है HashSet


2

यदि आप हशसेट या बाइनरी खोज का उपयोग करने का सुझाव ठोस है, तो आप प्रदर्शन के हर अंतिम बिट को निचोड़ने के बारे में चिंतित नहीं हैं। आपके डेटासेट अभी इतने बड़े नहीं हैं कि यह 99% समस्या बन जाए।

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

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