HashMap जटिलता प्राप्त / डालते हैं


131

हमें यह कहने के लिए उपयोग किया जाता है कि HashMap get/putसंचालन ओ (1) हैं। हालाँकि यह हैश कार्यान्वयन पर निर्भर करता है। डिफ़ॉल्ट ऑब्जेक्ट हैश वास्तव में JVM हीप में आंतरिक पता है। क्या हम सुनिश्चित हैं कि यह दावा करना अच्छा है कि get/putO (1) हैं?

उपलब्ध मेमोरी एक और मुद्दा है। जैसा कि मैं javadocs से समझता हूं, HashMap load factor0.75 होना चाहिए। क्या होगा अगर हमारे पास जेवीएम में पर्याप्त मेमोरी नहीं है और load factorसीमा से अधिक है?

तो, ऐसा लगता है कि O (1) की गारंटी नहीं है। क्या यह समझ में आता है या मुझे कुछ याद आ रहा है?


1
आप अमूर्त जटिलता की अवधारणा को देखना चाह सकते हैं। उदाहरण के लिए यहां देखें: stackoverflow.com/questions/3949217/time-complexity-of-hash-table सबसे खराब मामला हैश तालिका के लिए सबसे महत्वपूर्ण उपाय नहीं है
डॉ। जी

3
सही - यह amortized O (1) है - उस पहले भाग को कभी न भूलें और आपके पास इस प्रकार के सवाल नहीं होंगे :)
इंजीनियर

यदि मैं गलत नहीं हूं तो जावा 1.8 के बाद से समय की सबसे खराब स्थिति ओ (लॉगएन) है।
तरुण कोला

जवाबों:


216

यह कई चीजों पर निर्भर करता है। यह आमतौर पर O (1) है, एक सभ्य हैश के साथ जो कि निरंतर समय है ... लेकिन आपके पास एक हैश हो सकता है जिसे गणना करने में लंबा समय लगता है, और अगर हैश मैप में कई आइटम हैं जो समान हैश कोड लौटाते हैं, एक मैच खोजने के लिए उनमें से प्रत्येक पर getकॉल equalsकरने के लिए उन पर चलना होगा ।

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

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

और हां, अगर आपके पास हैश मैप के लिए पर्याप्त मेमोरी नहीं है, तो आप मुश्किल में पड़ जाएंगे ... लेकिन यह सही है कि जो भी डेटा स्ट्रक्चर आप इस्तेमाल करेंगे।


@marcog: आप O (n लॉग एन) को एकल लुकअप के लिए मानते हैं ? वह मुझे बहुत बुरा लगता है। यह हैश और समानता कार्यों की जटिलता पर निर्भर करेगा, लेकिन यह नक्शे के आकार पर निर्भर होने की संभावना नहीं है।
जॉन स्कीट

1
@marcog: तो आप ओ (एन लॉग एन) होने के लिए क्या मान रहे हैं? एन आइटम का सम्मिलन?
जॉन स्कीट

1
एक अच्छे उत्तर के लिए +1। क्या आप अपने उत्तर में हैश तालिका के लिए इस विकिपीडिया प्रविष्टि की तरह लिंक प्रदान करेंगे ? इस तरह, अधिक रुचि रखने वाले पाठक इस बात को समझ सकते हैं कि आपने अपना जवाब क्यों दिया।
डेविड वेसर

2
@SleimanJneidi: यह अभी भी है अगर कुंजी तुलनीय <T> `को लागू नहीं करता है - लेकिन जब मेरे पास अधिक समय होगा तो मैं उत्तर को अपडेट करूंगा।
जॉन स्कीट

1
@ ip696: हाँ, put"amortized O (1)" है - आमतौर पर O (1), कभी-कभी O (n) - लेकिन बाहर संतुलन के लिए शायद ही कभी पर्याप्त होता है।
जॉन स्कीट

9

मुझे यकीन नहीं है कि डिफ़ॉल्ट हैशकोड पता है - मैंने कुछ समय पहले हैशकोड पीढ़ी के लिए OpenJDK स्रोत पढ़ा है, और मुझे याद है कि यह कुछ अधिक जटिल है। अभी भी कुछ ऐसा नहीं है जो एक अच्छे वितरण की गारंटी देता है, शायद। हालाँकि, यह कुछ हद तक लूट है, कुछ वर्ग जिन्हें आप हैशमैप में कुंजियों के रूप में डिफ़ॉल्ट हैशकोड का उपयोग करते हैं - वे अपने स्वयं के कार्यान्वयन की आपूर्ति करते हैं, जो अच्छा होना चाहिए।

उसके शीर्ष पर, जो आप नहीं जानते हैं (फिर से, यह पढ़ने के स्रोत में आधारित है - इसकी गारंटी नहीं है) यह है कि हैशपॉप उपयोग करने से पहले हैश को स्टिर करता है, पूरे शब्द से एन्ट्रापी को नीचे के बिट्स में मिलाता है, जो कि यह है सभी के लिए जरूरी लेकिन सबसे बड़ा हैशमैप। यह हैश से निपटने में मदद करता है जो विशेष रूप से स्वयं ऐसा नहीं करते हैं, हालांकि मैं किसी भी सामान्य मामलों के बारे में नहीं सोच सकता हूं जहां आप देखेंगे।

अंत में, जब तालिका अतिभारित होती है तो क्या होता है कि यह समानांतर लिंक्ड सूचियों के एक सेट में पतित हो जाता है - प्रदर्शन O (n) हो जाता है। विशेष रूप से, ट्रैवर्स किए गए लिंक की संख्या औसतन आधा लोड फैक्टर होगी।


6
Dammit। मैं यह मानना ​​चाहता हूं कि अगर मुझे फ्लिपिंग मोबाइल फोन टचस्क्रीन पर टाइप नहीं करना होता, तो मैं जॉन शीट को पंच मार सकता था। उस के लिए एक बिल्ला है, है ना?
टॉम एंडरसन

8

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

अब स्मृति के बारे में सवाल का दूसरा हिस्सा आ रहा है, तो हाँ स्मृति बाधा जेवीएम द्वारा ध्यान रखा जाएगा।


8

यह पहले ही उल्लेख किया गया है कि हैशमैप O(n/m)औसत हैं, यदि nआइटम की संख्या mहै और आकार है। यह भी उल्लेख किया गया है कि सिद्धांत रूप में पूरी बात O(n)क्वेरी समय के साथ एक एकल लिंक की गई सूची में ढह सकती है । (यह सब मानता है कि हैश की गणना निरंतर समय है)।

हालांकि, जो अक्सर उल्लेख नहीं किया जाता है, वह यह है कि संभावना के साथ कम से कम 1-1/n(इसलिए 1000 वस्तुओं के लिए जो 99.9% संभावना है) सबसे बड़ी बाल्टी से अधिक नहीं भरी जाएगी O(logn)! इसलिए बाइनरी सर्च ट्री की औसत जटिलता का मिलान। (और निरंतर अच्छा है, एक तंग बाध्य है (log n)*(m/n) + O(1))।

इस सैद्धांतिक बाध्यता के लिए आवश्यक सभी यह है कि आप यथोचित अच्छे हैश फ़ंक्शन का उपयोग करें (देखें विकिपीडिया: यूनिवर्सल हैशिंग । यह उतना ही सरल हो सकता है a*x>>m)। और निश्चित रूप से आपको हैश करने के लिए मान देने वाला व्यक्ति नहीं जानता है कि आपने अपने यादृच्छिक स्थिरांक को कैसे चुना है।

टीएल; डीआर: वेरी हाई प्रोबेबिलिटी के साथ सबसे खराब स्थिति एक हैशमप की जटिलता को मिलती है O(logn)


(और ध्यान दें कि इनमें से कोई भी यादृच्छिक डेटा नहीं मानता है। संभावना विशुद्ध रूप से हैश फ़ंक्शन के विकल्प से उत्पन्न होती है)
थॉमस अहले

मेरे पास हैश मैप में लुकअप की रनटाइम जटिलता के बारे में भी यही सवाल है। ऐसा लगता है कि यह O (n) है क्योंकि निरंतर कारकों को गिराया जाना चाहिए। 1 / m एक स्थिर कारक है और इस प्रकार O (n) को छोड़ दिया जाता है।
निकु।

4

मैं सहमत हूं:

  • O (1) की सामान्य परिशोधन जटिलता
  • एक खराब hashCode()कार्यान्वयन कई टकरावों का परिणाम हो सकता है, जिसका अर्थ है कि सबसे खराब स्थिति में प्रत्येक वस्तु एक ही बाल्टी में जाती है, इस प्रकार ओ ( एन ) यदि प्रत्येक बाल्टी एक द्वारा समर्थित है List
  • चूंकि जावा 8, HashMapडायनेमिक रूप से प्रत्येक बकेट में इस्तेमाल किए गए नोड्स (लिंक्ड लिस्ट) को ट्रीनोड्स (लाल-काला पेड़ जब एक सूची 8 तत्वों से बड़ा हो जाता है) की जगह लेती है, जिसके परिणामस्वरूप ओ ( लॉगएन ) का सबसे खराब प्रदर्शन होता है ।

लेकिन, यह पूर्ण सत्य नहीं है यदि हम 100% सटीक होना चाहते हैं। कार्यान्वयन hashCode()और कुंजी के प्रकार Object(अपरिवर्तनीय / कैशेड या एक संग्रह होने के नाते) भी सख्त शब्दों में वास्तविक जटिलता को प्रभावित कर सकते हैं।

आइए निम्नलिखित तीन मामलों को मानें:

  1. HashMap<Integer, V>
  2. HashMap<String, V>
  3. HashMap<List<E>, V>

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

मान लेते हैं कि उपरोक्त सभी सरणियों / सूचियों का आकार k है । फिर, HashMap<String, V>और HashMap<List<E>, V>O (k) परिमित जटिलता होगी और इसी तरह, Java8 में O ( k + logN ) सबसे खराब स्थिति है।

* ध्यान दें कि Stringकुंजी का उपयोग करना अधिक जटिल मामला है, क्योंकि यह अपरिवर्तनीय है और जावा hashCode()एक निजी चर में परिणाम देता है hash, इसलिए यह केवल एक बार गणना की जाती है।

/** Cache the hash code for the string */
    private int hash; // Default to 0

लेकिन, उपरोक्त भी अपना सबसे खराब मामला है, क्योंकि कंप्यूटिंग से पहले जावा का String.hashCode()कार्यान्वयन जाँच कर रहा है । लेकिन हे, ऐसे गैर-रिक्त स्ट्रिंग्स हैं जो शून्य का उत्पादन करते हैं, जैसे कि "f5a5a608", यहां देखें , जिसमें संस्मरण सहायक नहीं हो सकता है।hash == 0hashCodehashcode


2

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

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

व्यक्तिगत तत्वों का वर्णन करने के लिए आवश्यक बिट्स की संख्या लॉग (एन) है, जहां एन तत्वों की अधिकतम संख्या है, इसलिए वास्तव में ओ (लॉग एन) हैं।

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

अंत में, यदि किसी भी डेटा संरचना में एक तत्व ओ (1) था, तो हम पतली हवा के बारे में जानकारी बनाएंगे। N एलिमेंट का डेटा स्ट्रक्चर होने से मैं एक एलिमेंट को अलग-अलग तरीके से चुन सकता हूं। इसके साथ, मैं लॉग (एन) बिट जानकारी को एन्कोड कर सकता हूं। अगर मैं शून्य बिट (जो कि O (1) का अर्थ है) में सांकेतिक शब्दों में बदलना कर सकता हूं, तो मैंने एक अनंत रूप से संकुचित ज़िप एल्गोरिथ्म बनाया।


पेड़ सेट के लिए जटिलता नहीं होनी चाहिए O(log(n) * log(max(n))), फिर? जबकि हर नोड पर तुलना होशियार हो सकती है, सबसे खराब स्थिति में इसे सभी O(log(max(n))बिट्स का निरीक्षण करने की आवश्यकता है , है ना?
मातरिनस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.