क्या हैश टेबल वास्तव में O (1) हो सकता है?


114

यह सामान्य ज्ञान है कि हैश टेबल ओ (1) प्राप्त कर सकते हैं, लेकिन यह मेरे लिए कभी भी समझ में नहीं आया है। क्या कोई इसे समझा सकता है? यहाँ दो परिस्थितियाँ हैं जो मन में आती हैं:

A. मूल्य हैश तालिका के आकार की तुलना में एक छोटा है। इसलिए, मान अपनी स्वयं की हैश है, इसलिए कोई हैश तालिका नहीं है। लेकिन अगर वहाँ था, तो यह ओ (1) होगा और अभी भी अक्षम होगा।

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

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

मुझे लगता है कि हैश टेबल भयानक हैं, लेकिन मुझे ओ (1) पदनाम नहीं मिलता है जब तक कि यह सिर्फ सैद्धांतिक नहीं माना जाता है।

हैश टेबल्स के लिए विकिपीडिया का लेख निरंतर लुकअप समय को संदर्भित करता है और हैश फ़ंक्शन की लागत को पूरी तरह से अनदेखा करता है। क्या यह वास्तव में एक उचित उपाय है?


संपादित करें: मैंने जो सीखा, उसे संक्षेप में बताने के लिए:

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

  • यह व्यवहार में सच है क्योंकि समय के साथ-साथ यह तब तक काम करता है जब तक हैश फ़ंक्शन और टेबल का आकार टकरावों को कम करने के लिए चुना जाता है, भले ही इसका मतलब है कि लगातार समय हैश फ़ंक्शन का उपयोग न करें।


31
यह O (1) नहीं, O (1) है।
kennytm

याद रखें ओ () बड़ी संख्या में संचालन के लिए सीमा है। 'औसत' पर आपके पास कई टकराव नहीं होंगे - यह आवश्यक नहीं है कि एक व्यक्तिगत ऑपरेशन में कोई टक्कर न हो।
मार्टिन बेकेट

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

@kennytm ज़रूर, इनपुट को एक बार देखने के बाद आप ओ (1) को संशोधित कर लेते हैं । लेकिन क्या हैश की गणना करने की लागत वास्तव में नगण्य है? मान लीजिए कि हम एक स्ट्रिंग हैशिंग हैं - एक चरित्र सरणी। हैश उत्पन्न करने के लिए, प्रत्येक वर्ण के माध्यम से पुनरावृत्त होता है, इसलिए एक स्ट्रिंग हैशिंग ओ (एन) है जहां एन स्ट्रिंग की लंबाई है। यह है कि यह C # के लिए कैसे प्रलेखित है और यह है कि जावा का hashCode()तरीका किस तरह लागू होता है Stringgrepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
Spaaarky21

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

जवाबों:


65

आपके यहाँ दो चर हैं, m और n, जहाँ m इनपुट की लंबाई है और n हैश में वस्तुओं की संख्या है।

O (1) लुकअप परफॉर्मेंस का दावा कम से कम दो अनुमान लगाता है:

  • O (1) समय की तुलना में आपकी वस्तुओं में समानता हो सकती है।
  • कुछ हैश टकराव होगा।

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

पर्याप्त रूप से कई मदों के लिए आइटमों की संख्या संभव हैश की संख्या से अधिक हो जाएगी और फिर आपको O (1) के ऊपर प्रदर्शन वृद्धि का कारण टकराव मिलेगा, उदाहरण के लिए O (n) एक साधारण लिंक किए गए सूची ट्रैवर्सल (या O (n) के लिए * m) यदि दोनों धारणाएँ झूठी हैं)।

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


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

1
@JeremyP: O (m) समानता की तुलना पर अच्छा बिंदु। मुझे वह याद आया - अद्यतन पोस्ट। धन्यवाद!
मार्क बायर्स

2
यह O(1)दावा सही है अगर आप हैशिंग है intया कुछ और जो मशीन शब्द में फिट बैठता है। हैशिंग पर सबसे अधिक सिद्धांत यही माना जाता है।
थॉमस अहले

मुझे आपका मार्क का यह स्पष्टीकरण पसंद आया, मैंने इसे अपने लेख में meshfields.de/hash-tables
स्टीव के

3
में "मीटर इनपुट की लंबाई है" - इनपुट ज्यादा अस्पष्ट है - यह सब चाबियाँ और मूल्यों डाला जा रहा है मतलब हो सकता है, लेकिन यह स्पष्ट बाद में (कम से कम जो लोग पहले से विषय को समझने के लिए) हो जाता है तुम्हारा मतलब कुंजी । स्पष्टता के उत्तर में "कुंजी" का उपयोग करने का सुझाव देना। BTW - ठोस उदाहरण - std::hashशाब्दिक कुंजियों के विज़ुअल C ++ के 10 अक्षर समान रूप से पाठ के साथ हैश मान में जोड़े जाते हैं, इसलिए यह O (1) पाठ लंबाई की परवाह किए बिना (लेकिन जीसीसी की तुलना में बड़े पैमाने पर अधिक टक्कर वाला है!)। अलग से, O (1) के दावों में एक और धारणा है (सामान्य रूप से सही ढंग से) कि m n से बहुत कम है ।
टोनी डेलरो

22

आपको हैश की गणना करनी है, इसलिए डेटा के आकार को देखने के लिए ऑर्डर O (n) है। O (n) कार्य करने के बाद लुकअप O (1) हो सकता है, लेकिन फिर भी मेरी आँखों में O (n) आता है।

क्या? किसी एक तत्व को हैश करने में निरंतर समय लगता है। यह कुछ और क्यों होगा? यदि आप nतत्वों को सम्मिलित कर रहे हैं, तो हाँ, आपको nहैश की गणना करनी है , और यह रैखिक समय लेता है ... एक तत्व को देखने के लिए, आप जो खोज रहे हैं, उसके एक एकल हैश की गणना करते हैं, फिर उसके साथ उपयुक्त बाल्टी खोजें । आप पहले से ही हैश तालिका में सब कुछ के हैश की फिर से गणना नहीं करते हैं।

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

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

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


आप अपने अन्य टिप्पणियों में से एक में कुंजी के रूप में तार का उपयोग करने का उल्लेख करते हैं। आप किसी स्ट्रिंग के हैश की गणना करने में लगने वाले समय के बारे में चिंतित हैं, क्योंकि इसमें कई वर्ण हैं? जैसा कि किसी और ने फिर से बताया, आपको हैश की गणना करने के लिए सभी वर्णों को देखने की आवश्यकता नहीं है, हालांकि अगर आपने किया तो यह बेहतर हैश का उत्पादन कर सकता है। उस स्थिति में, यदि mआपकी कुंजी में औसत वर्ण हैं, और आपने अपने हैश की गणना करने के लिए उन सभी का उपयोग किया है, तो मुझे लगता है कि आप सही हैं, कि लुकअप लगेगा O(m)। अगर m >> nतब आपको कोई समस्या हो सकती है। आप शायद उस मामले में BST के साथ बेहतर होंगे। या एक सस्ता हैशिंग फ़ंक्शन चुनें।


हैश टेबल BSTs का उपयोग नहीं करते हैं। BST को हैश मान की आवश्यकता नहीं है। मैप्स और सेट्स को BST के रूप में लागू किया जा सकता है।
निक डंडौलकिस

3
@ निक: एह? नहीं ... BST को हैश मान की आवश्यकता नहीं है ... यह बात है। हम मान रहे हैं कि इस बिंदु पर हमारे पास पहले से ही एक टक्कर है (एक ही हैश ... या कम से कम एक ही बाल्टी), इसलिए हमें सही तत्व, अर्थात वास्तविक मूल्य खोजने के लिए कुछ और देखने की जरूरत है।
mpen

ओह, मैं आपकी बात देख रहा हूं। लेकिन मुझे यकीन नहीं है कि बीएसटी और हैश को मिलाने से परेशानी हो सकती है। सिर्फ बीएसटी का उपयोग क्यों नहीं?
निक डंडौलकिस

2
मैं सिर्फ इतना कह रहा हूं कि आप टकराव के लिए इससे छुटकारा पा सकते हैंO(n) । यदि आप बहुत से टकरावों की उम्मीद कर रहे हैं , तो आप सही हैं, शायद पहले स्थान पर BST के साथ जाना बेहतर होगा।
mpen

1
@ Spaaarky21 राइट, लेकिन Nउस मामले में स्ट्रिंग की लंबाई है। हमें केवल यह निर्धारित करने के लिए एक स्ट्रिंग हैश करने की आवश्यकता है कि इसे किस बाल्टी में जाना है - यह हैशमैप की लंबाई के साथ नहीं बढ़ता है।
मपेन

5

हैश निश्चित आकार है - उपयुक्त हैश बाल्टी को देखना एक निश्चित लागत ऑपरेशन है। इसका मतलब है कि यह ओ (1) है।

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


3
हैश बाल्टी को देखना हे (1) है। लेकिन सही कुंजी का पता लगाना, एक O (n) प्रक्रिया है, जहाँ n हैश टकराव की संख्या पर निर्भर करता है।
निक डंडौलकिस

1
3 चरणों में से, हैश की गणना करें, बाल्टी ढूंढें, बाल्टी खोजें, मध्य चरण स्थिर है? बाल्टी की खोज आमतौर पर स्थिर होती है। हैश की गणना आमतौर पर बाल्टी को खोजने के अन्य साधनों की तुलना में सस्ता होने के कई आदेश हैं। लेकिन क्या यह वास्तव में निरंतर समय तक जोड़ता है? एक भोली विकल्प खोज में, आप दो लंबाई के लिए O (n * m) कहेंगे, तो यहाँ कुंजी की लंबाई की उपेक्षा क्यों की गई है?
drawnonward

एक निश्चित लंबाई की कुंजी केवल O (n) है यदि इसकी सूची समर्थित है, तो एक संतुलित ट्री समर्थित हैश तालिका O (लॉग (n))
jk होगी।

@Jk अच्छे हैश कार्यों के लिए, सबसे बुरी स्थिति हमेशा होती है logn, मेरा जवाब देखें stackoverflow.com/questions/4553624/hashmap-get-put-complexity/…
थॉमस अहले

टक्कर के मामले में सबसे खराब स्थिति जटिलता ओ (एन) होगी
सौरभ चंद्र पटेल

3

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

यदि आपकी कुंजी में n-बिट प्रतिनिधित्व है, तो आपका हैश फ़ंक्शन इन बिट्स में से 1, 2, ... n का उपयोग कर सकता है। एक हैश फ़ंक्शन के बारे में सोचना जो 1 बिट का उपयोग करता है। मूल्यांकन सुनिश्चित करने के लिए हे (1) है। लेकिन आप केवल कुंजी स्थान को 2 में विभाजित कर रहे हैं। इसलिए आप एक ही बिन में 2 ^ (n-1) कुंजी के रूप में मैप कर रहे हैं। BST खोज का उपयोग करते हुए लगभग पूर्ण होने पर किसी विशेष कुंजी का पता लगाने के लिए n-1 चरण तक ले जाता है।

आप यह देखने के लिए इसे बढ़ा सकते हैं कि यदि आपका हैश फ़ंक्शन K बिट्स का उपयोग करता है तो आपका बिन आकार 2 ^ (nk) है।

इसलिए K-bit हैश फ़ंक्शन ==> 2 से अधिक ^ K प्रभावी डिब्बे ==> 2 तक ^ (nK) n-बिट कुंजियाँ प्रति बिन ==> (nK) चरण (BST) टकराव को हल करने के लिए। वास्तव में अधिकांश हैश फ़ंक्शंस बहुत कम "प्रभावी" होते हैं और 2 ^ k डिब्बे का उत्पादन करने के लिए K बिट्स से अधिक की आवश्यकता होती है। तो भी यह आशावादी है।

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

हालाँकि, यह नहीं है कि आप कब / कब हैश तालिका का उपयोग करते हैं!

जटिलता विश्लेषण मानता है कि n-बिट कुंजियों के लिए, आपके पास तालिका में O (2 ^ n) कुंजी हो सकती हैं (उदाहरण के लिए सभी संभावित कुंजियों का 1/4)। लेकिन सबसे ज्यादा अगर हम हैश टेबल का उपयोग नहीं करते हैं, तो हमारे पास तालिका में केवल n-बिट कुंजियों की एक निरंतर संख्या होती है। यदि आप केवल तालिका में निरंतर संख्या की कुंजी चाहते हैं, तो कहें कि C आपकी अधिकतम संख्या है, तो आप O (C) डिब्बे की हैश तालिका बना सकते हैं, जो अपेक्षित निरंतर टक्कर (एक अच्छे हैश फ़ंक्शन के साथ) की गारंटी देता है; और कुंजी में n बिट्स के ~ logC का उपयोग करके एक हैश फ़ंक्शन। फिर हर क्वेरी O (logC) = O (1) है। यह है कि लोग दावा करते हैं कि "हैश टेबल एक्सेस हे (1) है" /

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

इस मामले में, उदाहरण के लिए, BST जैसे विकल्प पर विचार करें। C कुंजियाँ हैं, इसलिए एक संतुलित BST O (logC) गहराई से होगा, इसलिए एक खोज O (logC) कदम उठाती है। हालाँकि इस मामले में तुलना O (n) ऑपरेशन होगी ... इसलिए ऐसा प्रतीत होता है कि हैशिंग इस मामले में बेहतर विकल्प है।


1

TL; DR: O(1)यदि आप अपने हैश फ़ंक्शन को समान रूप से हैश फ़ंक्शन के एक सार्वभौमिक परिवार से यादृच्छिक रूप से चुनते हैं, तो हश टेबल सबसे खराब समय की गारंटी देता है। अपेक्षित सबसे खराब स्थिति औसत मामले के समान नहीं है।

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

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

सबसे खराब स्थिति के बारे में तर्क देना

विभिन्न प्रकार के सबसे खराब मामले विश्लेषण हैं। यहाँ अब तक सबसे अधिक जवाब देने वाला विश्लेषण सबसे खराब स्थिति नहीं है, बल्कि औसत मामला [ 2 ] है। औसत केस विश्लेषण अधिक व्यावहारिक हो जाता है। हो सकता है कि आपके एल्गोरिथ्म में एक सबसे खराब केस इनपुट हो, लेकिन वास्तव में अन्य सभी संभावित इनपुट के लिए अच्छी तरह से काम करता हो। बॉटमलाइन आपका रनटाइम डेटासेट पर निर्भर करता है आप चल रहे हैं।

getहैश तालिका की विधि के निम्नलिखित छद्मकोश पर विचार करें । यहाँ मैं मान रहा हूं कि हम टकराव से टकराते हैं, इसलिए तालिका की प्रत्येक प्रविष्टि (key,value)जोड़े की एक सूचीबद्ध सूची है । हम यह भी मानते हैं कि बाल्टी की संख्या mनिश्चित है O(n), लेकिन nइनपुट में तत्वों की संख्या कहां है।

function get(a: Table with m buckets, k: Key being looked up)
  bucket <- compute hash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

जैसा कि अन्य उत्तर बताते हैं, यह औसत O(1)और सबसे खराब स्थिति में चलता हैO(n) । हम यहां चुनौती के द्वारा प्रमाण का थोड़ा स्केच बना सकते हैं। चुनौती इस प्रकार है:

(1) आप अपने हैश टेबल एल्गोरिथ्म को एक विरोधी को देते हैं।

(२) विरोधी इसका अध्ययन कर सकता है और जब तक वह चाहे तब तक तैयारी कर सकता है।

(३) अंत में विरोधी आपको nअपनी तालिका में सम्मिलित करने के लिए आकार का एक इनपुट देता है ।

सवाल यह है कि प्रतिकूल इनपुट पर आपकी हैश टेबल कितनी तेज है?

चरण (1) से विरोधी आपके हैश फ़ंक्शन को जानता है; चरण के दौरान (2) विरोधी nउसी के साथ तत्वों की एक सूची तैयार कर सकता है hash modulo m, उदाहरण के लिए, तत्वों के एक समूह के बेतरतीब ढंग से कंप्यूटिंग; और फिर (3) वे आपको वह सूची दे सकते हैं। लेकिन लो और निहारना, चूंकि सभी nतत्व एक ही बाल्टी में हैश करते हैं, आपके एल्गोरिथ्म को O(n)उस बाल्टी में लिंक की गई सूची को पार करने में समय लगेगा । कोई फर्क नहीं पड़ता कि हम कितनी बार चुनौती का सामना करते हैं, विरोधी हमेशा जीतता है, और यह कि आपका एल्गोरिथ्म कितना बुरा है, सबसे खराब स्थिति O(n)

हेहिंग कैसे हे (1) है?

पिछली चुनौती में हमें फेंक दिया गया था कि विरोधी हमारे हैश फ़ंक्शन को अच्छी तरह से जानते थे, और उस ज्ञान का उपयोग सबसे खराब इनपुट को तैयार करने के लिए कर सकते थे। क्या होगा अगर हमेशा एक निश्चित हैश फ़ंक्शन का उपयोग करने के बजाय, हमारे पास वास्तव में हैश फ़ंक्शन का एक सेट होता है H, जो कि एल्गोरिथ्म यादृच्छिक रूप से रनटाइम से चुन सकता है? यदि आप उत्सुक हैं, Hतो हैश फ़ंक्शन [ 3 ] का एक सार्वभौमिक परिवार कहा जाता है । ठीक है, चलो इस में कुछ यादृच्छिकता जोड़ने का प्रयास करें।

पहले मान लें कि हमारी हैश तालिका में एक बीज भी शामिल है r, और rनिर्माण समय पर एक यादृच्छिक संख्या को सौंपा गया है। हम इसे एक बार असाइन करते हैं और फिर इसे उस हैश टेबल उदाहरण के लिए तय किया जाता है। अब हम अपने स्यूडोकोड पर दोबारा गौर करते हैं।

function get(a: Table with m buckets and seed r, k: Key being looked up)
  rHash <- H[r]
  bucket <- compute rHash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

यदि हम चुनौती को एक और बार आज़माते हैं: चरण 1 (1) से तो विरोधी हमारे पास मौजूद सभी हैश कार्यों को जान सकता है H, लेकिन अब हम जिस विशिष्ट हैश फ़ंक्शन का उपयोग करते हैं, वह निर्भर करता है r। मूल्य rहमारी संरचना के लिए निजी है, विरोधी इसे रनटाइम पर निरीक्षण नहीं कर सकता है, और न ही समय से पहले इसकी भविष्यवाणी कर सकता है, इसलिए वह ऐसी सूची को व्यक्त नहीं कर सकता है जो हमारे लिए हमेशा खराब है। मान लेते हैं कि चरण (2) में विरोधी यादृच्छिक रूप से एक कार्य hashको चुनता है H, फिर वह nटकरावों की एक सूची तैयार करता है hash modulo m, और चरण (3) के लिए भेजता है, उंगलियों को पार करता है कि रनटाइम H[r]में वही होगा जो hashउन्होंने चुना था।

यह प्रतिकूल के लिए एक गंभीर शर्त है, जिस सूची को वह तैयार करता है, उसके तहत टकराता है hash, लेकिन किसी अन्य हैश फ़ंक्शन के तहत बस एक यादृच्छिक इनपुट होगा H। यदि वह इस शर्त को जीतता है तो हमारा रन टाइम O(n)पहले की तरह सबसे खराब स्थिति में होगा , लेकिन अगर वह हार जाता है तो अच्छी तरह से हमें सिर्फ एक यादृच्छिक इनपुट दिया जा रहा है जो औसत O(1)समय लेता है । और वास्तव में अधिकांश बार विरोधी हार जाएगा, वह केवल एक बार हर |H|चुनौतियों को जीतता है , और हम |H|बहुत बड़े हो सकते हैं ।

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


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


0

दो सेटिंग्स हैं जिनके तहत आप ओ (1) सबसे खराब स्थिति में प्राप्त कर सकते हैं ।

  1. यदि आपका सेटअप स्थिर है, तो FKS हैशिंग आपको सबसे खराब स्थिति वाला O (1) गारंटी प्रदान करेगी । लेकिन जैसा कि आपने संकेत दिया, आपकी सेटिंग स्थिर नहीं है।
  2. यदि आप कोयल हैशिंग का उपयोग करते हैं, तो प्रश्न और विलोपन O (1) सबसे खराब स्थिति है, लेकिन प्रविष्टि केवल O (1) अपेक्षित है। कोयल हैशिंग काफी अच्छी तरह से काम करती है यदि आपके पास आवेषण की कुल संख्या पर ऊपरी सीमा है, और तालिका का आकार लगभग 25% बड़ा है।

यहां से नकल की गई


0

यह यहाँ चर्चा पर आधारित लगता है, कि यदि X (# तालिका के तत्वों की #) सीमा की छत है, तो एक बेहतर उत्तर है O (log (X)) जो बिन लुकअप के एक कुशल कार्यान्वयन का अनुमान लगा रहा है।


0

A. मूल्य हैश तालिका के आकार की तुलना में एक छोटा है। इसलिए, मान अपनी स्वयं की हैश है, इसलिए कोई हैश तालिका नहीं है। लेकिन अगर वहाँ था, तो यह ओ (1) होगा और अभी भी अक्षम होगा।

यह एक ऐसा मामला है जहां आप अलग-अलग बाल्टियों की चाबियों का मानचित्रण कर सकते हैं, इसलिए एक सरणी हैश तालिका की तुलना में डेटा संरचना का एक बेहतर विकल्प लगता है। फिर भी, अक्षमताएं तालिका आकार के साथ नहीं बढ़ती हैं।

(आप अभी भी हैश टेबल का उपयोग कर सकते हैं क्योंकि आप प्रोग्राम के विकसित होते ही टेबल आकार से छोटे रहने के लिए ints पर भरोसा नहीं करते हैं, आप कोड को संभावित रूप से पुन: प्रयोज्य बनाना चाहते हैं जब वह संबंध नहीं रखता है, या आप बस नहीं करते हैं लोगों को मानसिक प्रयास को समझने और रिश्ते को बनाए रखने के लिए कोड को पढ़ने / बनाए रखने के लिए चाहते हैं)।

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

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

एक टेलीफोन बुक पर विचार करें: आपके पास ऐसे नाम हो सकते हैं जो काफी लंबे हैं, लेकिन क्या किताब में 100 नाम हैं, या 10 मिलियन हैं, औसत नाम की लंबाई काफी सुसंगत है, और इतिहास में सबसे खराब स्थिति है ...

किसी के द्वारा उपयोग किए जाने वाले सबसे लंबे नाम के लिए गिनीज विश्व रिकॉर्ड एडोल्फ ब्लेन चार्ल्स डेविड अर्ल फ्रेडरिक गेराल्ड इरविन जॉन केनेथ लॉयड मार्टिन नीरो ओलिवर पॉल क्विनसी रैंडोल्फ शैंड्स थॉमस अनसस विक्टर विलियम एक्सरेक्स येंसी वोल्फस्केलस्टेनजोनबर्गरडॉर्फ, सीनियर द्वारा निर्धारित किया गया था।

... wcमुझसे कहता है कि 215 वर्ण - जो वह नहीं है एक कठिन कुंजी लंबाई करने के लिए ऊपरी बाध्य है, लेकिन हम जा रहा है वहाँ के बारे में चिंता की जरूरत नहीं है बड़े पैमाने पर अधिक।

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

एक निश्चित आकार की कुंजी डेटा से हैश बनाना भी संभव है। उदाहरण के लिए, Microsoft का विजुअल C ++ एक मानक लाइब्रेरी कार्यान्वयन के साथ जहाज std::hash<std::string>एक हैश बनाता है जिसमें स्ट्रिंग के साथ समान रूप से केवल दस बाइट्स होते हैं, इसलिए यदि स्ट्रिंग्स केवल अन्य सूचकांकों में भिन्न होती हैं, तो आपको टकराव मिलते हैं (और इसलिए अभ्यास में गैर O (1) व्यवहार होते हैं। टक्कर के बाद खोज पक्ष), लेकिन हैश बनाने का समय एक कठिन ऊपरी सीमा है।

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

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

उदाहरण के लिए, 1.0 के लोड फैक्टर के साथ, उन रैखिक खोजों की लंबाई के लिए औसतन ~ 1.58 है, चाहे कीज़ की संख्या की परवाह किए बिना ( मेरा उत्तर यहां देखें )। के लिए बंद कर दिया हैशिंग उसे कुछ अतिरिक्त जटिल, लेकिन बहुत ज्यादा नहीं बदतर है जब लोड फैक्टर बहुत अधिक नहीं है।

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

इस तरह की बात याद आती है। किसी भी प्रकार की साहचर्य संबंधी डेटा संरचना को अंततः कुंजी के हर हिस्से में कभी-कभी ऑपरेशन करना पड़ता है (असमानता कभी-कभी कुंजी के सिर्फ एक हिस्से से निर्धारित की जा सकती है, लेकिन समानता को आमतौर पर हर बिट पर विचार करने की आवश्यकता होती है)। कम से कम, यह एक बार हैश की हैश और हैश मान को स्टोर कर सकता है, और यदि यह एक मजबूत पर्याप्त हैश फ़ंक्शन का उपयोग करता है - जैसे 64-बिट एमडी 5 - यह व्यावहारिक रूप से एक ही मूल्य (एक कंपनी) के लिए दो कुंजी हैशिंग की संभावना को भी अनदेखा कर सकता है। मैंने वितरित डेटाबेस के लिए ठीक वैसा ही काम किया: हैश-जनरेशन का समय अभी भी WAN- वाइड नेटवर्क ट्रांस्फ़ॉर्मेशन की तुलना में महत्वहीन था)। इसलिए, कुंजी को संसाधित करने की लागत के बारे में बहुत अधिक ध्यान देने योग्य बात नहीं है: डेटा संरचना की परवाह किए बिना कुंजी संग्रहीत करने में निहित है, और जैसा कि ऊपर कहा गया है - doesn '

के रूप में बड़े पर्याप्त हैश ताल नीचे टकराव लाने के लिए, कि बिंदु भी याद आ रही है। अलग-अलग चेनिंग के लिए, आपके पास किसी भी दिए गए लोड फैक्टर पर लगातार औसत टक्कर श्रृंखला की लंबाई होती है - यह केवल तब अधिक होता है जब लोड फैक्टर अधिक होता है, और यह संबंध गैर-रैखिक होता है। मेरे उत्तर पर SO उपयोगकर्ता हंस की टिप्पणियाँ भी इसके ऊपर जुड़ी हुई हैं :

गैर-खाली बाल्टी पर वातानुकूलित औसत बाल्टी लंबाई दक्षता का एक बेहतर उपाय है। यह a / (1-e ^ {- a}) [जहां a लोड फैक्टर है, e 2.71828 है ...]

तो, लोड फैक्टर अकेले उन सम्मिलित कुंजियों की औसत संख्या निर्धारित करता है जिन्हें आपको सम्मिलित / मिटा / संचालन के दौरान खोजना है। अलग-अलग चैनिंग के लिए, लोड फैक्टर कम होने पर यह स्थिर नहीं रहता है - यह हमेशा स्थिर रहता है। खुले पते के लिए हालांकि आपके दावे में कुछ वैधता है: कुछ टकराने वाले तत्वों को वैकल्पिक बाल्टियों पर पुनर्निर्देशित किया जाता है और फिर अन्य कुंजियों पर संचालन में हस्तक्षेप कर सकते हैं, इसलिए उच्च लोड कारकों (विशेष रूप से> .8 या .9) पर टकराव की श्रृंखला की लंबाई अधिक नाटकीय रूप से बदतर हो जाती है।

यह व्यवहार में सच है क्योंकि समय के साथ-साथ यह तब तक काम करता है जब तक हैश फ़ंक्शन और टेबल का आकार टकरावों को कम करने के लिए चुना जाता है, भले ही इसका मतलब है कि लगातार समय हैश फ़ंक्शन का उपयोग न करें।

ठीक है, टेबल साइज का परिणाम एक हैन लोड फैक्टर में होता है जिसे क्लोज हैशिंग या अलग-अलग चेनिंग का विकल्प दिया जाता है, लेकिन यह भी कि अगर हैश फंक्शन थोड़ा कमजोर है और चाबी बहुत रैंडम नहीं है, तो प्राइम संख्या में बकेट्स को कम करने में मदद मिलती है। टक्कर भी ( hash-value % table-sizeफिर इस तरह के चारों ओर लपेटता है कि केवल उच्च-क्रम बिट या हैश-मूल्य में दो अभी भी बाल्टी को हैश-टेबल के विभिन्न हिस्सों में यादृच्छिक रूप से फैलाने के लिए हल करता है)।

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