क्या एक जावा हैशमैप वास्तव में हे (1) है?


159

मैंने SO पुनः जावा हैशमैप और उनके O(1)लुकअप समय पर कुछ दिलचस्प दावे देखे हैं । क्या कोई समझा सकता है कि ऐसा क्यों है? जब तक ये हैशमैप किसी भी हैशिंग एल्गोरिदम से अलग नहीं होते हैं, जिन्हें मैं खरीदा गया था, हमेशा एक डेटासेट मौजूद होना चाहिए जिसमें टकराव होते हैं।

किस मामले में, लुकअप के O(n)बजाय होगा O(1)

कोई व्याख्या कर सकते हैं कि क्या वे कर रहे हैं हे (1) और, यदि हां, तो कैसे वे इस लक्ष्य को हासिल?


1
मुझे पता है कि यह एक उत्तर नहीं हो सकता है लेकिन मुझे याद है कि विकिपीडिया का इस बारे में बहुत अच्छा लेख है। प्रदर्शन विश्लेषण अनुभाग याद न करें
विजेता ह्यूगो

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

जवाबों:


127

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

पी टक्कर = एन / क्षमता

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

O (n) = O (k * n)

हम हैश मैप के प्रदर्शन को बेहतर बनाने के लिए इस सुविधा का उपयोग कर सकते हैं। हम इसके बजाय अधिकांश 2 टकरावों की संभावना के बारे में सोच सकते हैं।

p टक्कर x 2 = (n / क्षमता) 2

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

p टक्कर xk = (n / क्षमता) k

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

हम इस बारे में यह कहते हुए बात करते हैं कि हैश-मैप में उच्च संभावना के साथ ओ (1) का उपयोग होता है


HTML के साथ भी, मैं अभी भी अंशों से खुश नहीं हूं। यदि आप इसे करने का एक अच्छा तरीका सोच सकते हैं, तो उन्हें साफ करें।
सिंगलनेशन इलिमिनेशन

4
वास्तव में, ऊपर जो कहा गया है वह यह है कि ओ (लॉग एन) प्रभाव को दफन किया जाता है, एन के चरम मूल्यों के लिए, निर्धारित ओवरहेड द्वारा।
हॉट लिक्स

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

1
क्या यह परिशोधित विश्लेषण के समान है?
खोयासौल 29

1
@ OleV.V। एक हैशपॉप का अच्छा प्रदर्शन हमेशा आपके हैश फ़ंक्शन के अच्छे वितरण पर निर्भर करता है। आप अपने इनपुट पर क्रिप्टोग्राफिक हैशिंग फ़ंक्शन का उपयोग करके हैशिंग गति के लिए बेहतर हैश गुणवत्ता का व्यापार कर सकते हैं।
सिंगलनेशन इलिमिनेशन

38

आप औसत-केस (अपेक्षित) रनटाइम के साथ सबसे खराब व्यवहार को मिलाते हैं। सामान्य रूप से हैश तालिकाओं के लिए पूर्व वास्तव में O (n) है (अर्थात एक परिपूर्ण हैशिंग का उपयोग नहीं) लेकिन व्यवहार में यह शायद ही कभी प्रासंगिक है।

किसी भी भरोसेमंद हैश तालिका कार्यान्वयन, एक आधे सभ्य हैश के साथ मिलकर, ओ (1) की पुनर्प्राप्ति का प्रदर्शन बहुत कम कारक (2, वास्तव में) के साथ अपेक्षित मामले में, विचरण के बहुत ही संकीर्ण मार्जिन के भीतर होता है।


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

2
आपको संभवतः यह स्पष्ट करना चाहिए कि जब आप औसत रन के लिए बड़े ओ नोटेशन का उपयोग करते हैं तो आप अपेक्षित रनटाइम फ़ंक्शन पर ऊपरी बाउंड के बारे में बात कर रहे हैं जो स्पष्ट रूप से परिभाषित गणितीय फ़ंक्शन है। अन्यथा आपका जवाब बहुत मायने नहीं रखता।
ldog

1
gmatt: मुझे यकीन नहीं है कि मैं आपकी आपत्ति को समझता हूं: big-O अंकन परिभाषा के आधार पर फ़ंक्शन पर एक ऊपरी बाध्य है । इसलिए मुझे और क्या मतलब हो सकता है?
कोनराड रुडोल्फ

3
कंप्यूटर साहित्य में आमतौर पर आप बड़े ओ नोटेशन को एक एल्गोरिथ्म के रनटाइम या स्पेस जटिलता कार्यों पर एक ऊपरी हिस्से का प्रतिनिधित्व करते हुए देखते हैं। इस मामले में ऊपरी भाग वास्तव में उस अपेक्षा पर है जो स्वयं एक फ़ंक्शन नहीं है, लेकिन फ़ंक्शन (रैंडम वेरिएबल्स) पर एक ऑपरेटर है और वास्तव में वास्तव में एक अभिन्न (lebesgue) है। बहुत तथ्य यह है कि आपको इस तरह की बाध्यता नहीं लेनी चाहिए। के लिए दी गई है और तुच्छ नहीं है।
ldog

31

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

तो, कभी-कभी इसकी तुलना कुछ वस्तुओं से करनी होगी, लेकिन आमतौर पर यह O (n) की तुलना में O (1) के अधिक निकट होता है। व्यावहारिक उद्देश्यों के लिए, आपको यह जानना चाहिए।


11
खैर, चूंकि बड़े-ओ को सीमाओं को निर्दिष्ट करना है, इसलिए इससे कोई फर्क नहीं पड़ता कि यह ओ (1) के करीब है या नहीं। यहां तक ​​कि O (n / 10 ^ 100) अभी भी O (n) है। मैं दक्षता लाने के बारे में अपनी बात रखता हूँ फिर नीचे अनुपात लेकिन वह अभी भी एल्गोरिथ्म को O (n) पर रखता है।
paxdiablo

4
हैश-मैप विश्लेषण आम तौर पर औसत मामले पर होता है, जो ओ (1) (कोलैशन के साथ) सबसे खराब स्थिति में, आपके पास ओ (एन) हो सकता है, लेकिन यह आमतौर पर ऐसा नहीं है। अंतर के बारे में - O (1) का मतलब है कि आपको चार्ट पर वस्तुओं की मात्रा की परवाह किए बिना एक ही एक्सेस समय मिलता है, और यह आमतौर पर मामला है (जब तक तालिका के आकार और 'n के बीच एक अच्छा अनुपात है ')
लिरन ओरवी

4
यह भी ध्यान देने योग्य है, कि यह अभी भी ठीक ओ (1) है, भले ही बाल्टी की स्कैनिंग में थोड़ा समय लगे क्योंकि इसमें कुछ तत्व पहले से मौजूद हैं। जब तक बाल्टियों का एक निश्चित अधिकतम आकार होता है, यह ओ () वर्गीकरण के लिए एक निरंतर कारक अप्रासंगिक है। लेकिन निश्चित रूप से "समान" कुंजियों के साथ और भी अधिक तत्व हो सकते हैं, ताकि ये बाल्टी ओवरफ्लो हो जाएं और आप एक निरंतर गारंटी नहीं दे सकते।
sth

@ क्यों बाल्टी कभी एक निश्चित अधिकतम आकार होगा !?
नविन

31

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

इसलिए टकराव कंटेनर को ओ (1) संचालन से रोकते नहीं हैं, जब तक कि प्रति बाल्टी कुंजियों की औसत संख्या एक निश्चित सीमा के भीतर रहती है।


16

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन वास्तव में इसका एक नया उत्तर है।

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

लेकिन यह पालन नहीं करता है कि वास्तविक समय जटिलता है O(n) कोई नियम नहीं है जो कहता है कि बाल्टी को एक रैखिक सूची के रूप में लागू किया जाना है।

वास्तव में, जावा 8 TreeMapsएक बार सीमा से अधिक होने पर बाल्टी को लागू करता है, जो वास्तविक समय बनाता है O(log n)


4

यदि बाल्टियों की संख्या (इसे बी कहा जाता है) को स्थिर (सामान्य स्थिति) रखा जाता है, तो वास्तव में लुकिंग O (n) है।
जैसे-जैसे n बड़ा होता है, प्रत्येक बकेट में तत्वों की संख्या n / b होती है। यदि टकराव का समाधान सामान्य तरीकों में से एक में किया जाता है (उदाहरण के लिए लिंक की गई सूची), तो लुकअप O (n / b) = O (n) है।

O संकेतन तब होता है जब n बड़ा और बड़ा होता है। कुछ एल्गोरिदम पर लागू होने पर यह भ्रामक हो सकता है, और हैश टेबल बिंदु में एक मामला है। हम कितने तत्वों के आधार पर बाल्टी की संख्या चुनते हैं जिनसे हम निपटने की उम्मीद कर रहे हैं। जब n, b के समान आकार के बारे में है, तो लुकअप लगभग स्थिर-समय है, लेकिन हम इसे O (1) नहीं कह सकते क्योंकि O को n → ∞ के रूप में एक सीमा के रूप में परिभाषित किया गया है।



2

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

यह भी समझाया गया है कि कड़ाई से बोलना इनपुट का निर्माण करना संभव है जो किसी निर्धारक हैश फ़ंक्शन के लिए ओ ( एन ) लुकअप की आवश्यकता है। लेकिन सबसे खराब स्थिति वाले अपेक्षित समय पर विचार करना भी दिलचस्प है , जो औसत खोज समय से अलग है। इस का उपयोग करते हुए ओ (1 + सबसे लंबी श्रृंखला की लंबाई) है, उदाहरण के लिए n (लॉग एन / लॉग एन एन ) जब α = 1।

यदि आप लगातार सबसे खराब स्थिति वाले अपेक्षित समय को प्राप्त करने के लिए सैद्धांतिक तरीकों में रुचि रखते हैं, तो आप डायनामिक परफेक्ट हैशिंग के बारे में पढ़ सकते हैं जो किसी अन्य हैश टेबल के साथ टकराव को हल करता है!


2

यह ओ (1) है केवल अगर आपका हैशिंग फ़ंक्शन बहुत अच्छा है। जावा हैश तालिका कार्यान्वयन बुरे हैश कार्यों से रक्षा नहीं करता है।

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


2

हाशपैप के अंदर के तत्वों को लिंक की गई सूची (नोड) के एक सरणी के रूप में संग्रहीत किया जाता है, सरणी में प्रत्येक लिंक की गई सूची एक या अधिक कुंजियों के अद्वितीय हैश मान के लिए एक बाल्टी का प्रतिनिधित्व करती है।
HashMap में एक प्रविष्टि जोड़ते समय, कुंजी के हैशकोड का उपयोग सरणी में बाल्टी के स्थान को निर्धारित करने के लिए किया जाता है:

location = (arraylength - 1) & keyhashcode

यहां बिट और एंड ऑपरेटर का प्रतिनिधित्व करता है।

उदाहरण के लिए: 100 & "ABC".hashCode() = 64 (location of the bucket for the key "ABC")

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

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

जावा 8 के मामले में, लिंक्ड लिस्ट की बाल्टी को ट्रीपाउपर से बदल दिया जाता है यदि आकार 8 से अधिक हो जाता है, तो यह ओ (लॉग एन) के लिए सबसे खराब स्थिति खोज दक्षता कम कर देता है।


1

यह मूल रूप से अधिकांश प्रोग्रामिंग भाषाओं में अधिकांश हैश टेबल कार्यान्वयन के लिए जाता है, क्योंकि एल्गोरिथ्म में वास्तव में परिवर्तन नहीं होता है।

यदि तालिका में कोई टक्कर मौजूद नहीं है, तो आपको केवल एक ही लुक-अप करना होगा, इसलिए चलने का समय ओ (1) है। यदि टक्कर मौजूद हैं, तो आपको एक से अधिक लुक-अप करना होगा, जो ओ (एन) की ओर प्रदर्शन को कम करता है।


1
यह मानते हैं कि चल रहे समय को लुकअप टाइम द्वारा बाउंड किया गया है। व्यवहार में आपको बहुत सारी स्थितियाँ मिलेंगी जहाँ हैश फ़ंक्शन सीमा प्रदान करता है (स्ट्रिंग)
Stephan Eggermont

1

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


1

व्यावहारिक दृष्टिकोण से एक तरफ शिक्षाविदों को, HashMaps को एक असंगत प्रदर्शन प्रभाव के रूप में स्वीकार किया जाना चाहिए (जब तक कि आपका प्रोफाइलर आपको अन्यथा नहीं बताता है।)


4
व्यावहारिक अनुप्रयोगों में नहीं। जैसे ही आप एक कुंजी के रूप में एक स्ट्रिंग का उपयोग करते हैं, आप देखेंगे कि सभी हैश फ़ंक्शन आदर्श नहीं हैं, और कुछ वास्तव में धीमी हैं।
स्टेपहान एगरमोंट

1

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


0

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

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


"यह ज्यादातर मामलों में है"। अधिक विशेष रूप से, कुल समय K समय N (जहां K स्थिर है) की ओर झुकाव करेगा क्योंकि N, अनंत की ओर जाता है।
क्रिस जु

7
ये गलत है। हैश तालिका में सूचकांक निर्धारित किया जा रहा है hashCode % tableSizeजिसके माध्यम से निश्चित रूप से टकराव हो सकता है। आपको 32-बिट्स का पूर्ण उपयोग नहीं मिल रहा है। यह हैश टेबल्स की तरह है ... आप एक बड़े इंडेक्सिंग स्पेस को एक छोटे से कम करते हैं।
फोगबर्ड

1
"आपको गारंटी दी जाती है कि कोई टक्कर नहीं होगी" नहीं, क्योंकि आप नहीं हैं क्योंकि मानचित्र का आकार हैश के आकार से छोटा है: उदाहरण के लिए यदि मानचित्र का आकार दो है, तो टक्कर की गारंटी है (कोई बात नहीं) क्या हैश) अगर / जब मैं तीन तत्वों को सम्मिलित करने का प्रयास करता हूं।
क्रिस डब्ल्यूडब्ल्यू

लेकिन आप O (1) में मेमोरी एड्रेस की कुंजी से कैसे परिवर्तित होते हैं? मेरा मतलब है x = array ["key"]। कुंजी स्मृति पता नहीं है, इसलिए इसे अभी भी O (n) लुकअप होना होगा।
paxdiablo

1
"मेरा मानना ​​है कि यदि आप हैशकोड लागू नहीं करते हैं, तो यह ऑब्जेक्ट के मेमोरी एड्रेस का उपयोग करेगा"। यह उपयोग कर सकता है, लेकिन मानक ओरेकल जावा के लिए डिफ़ॉल्ट हैशकोड वास्तव में ऑब्जेक्ट हेडर में संग्रहीत 25-बिट यादृच्छिक संख्या है, इसलिए 64/32-बिट का कोई परिणाम नहीं है।
बोआन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.