2011-05-04 13 views
6

मुझे पता है कि हैशकोड और बराबर सवार होने पर सामान्य सर्वोत्तम प्रथाओं के बारे में अन्य प्रश्न हैं, लेकिन मेरे पास एक बहुत ही विशिष्ट सवाल है।जावा में हैशकोड को एक विशिष्ट मामले के लिए ओवरराइड करना

मेरे पास एक कक्षा है जो एक आवृत्ति चर के रूप में है, एक ही कक्षा की एक सरणी है। अधिक स्पष्ट होने के लिए, यहाँ कोड है:

Class Node{ 
    Node arr[] = new Node[5]; 
} 

मैं कक्षा नोड के लिए hashCode अधिलेखित करने के लिए की जरूरत है, और सरणी निर्धारित करता है कि दो नोड्स एक ही हैं में एक महत्वपूर्ण, निर्णायक कारक है। मैं हैशकोड की गणना में सरणी को प्रभावी ढंग से कैसे शामिल कर सकता हूं?

--Edit--

मैं, यदि दो नोड्स एक ही हैं जाँच करने के लिए कोशिश कर रहा हूँ, जिसका अर्थ है कि वे बच्चों की एक ही नंबर है, और कहा कि उन बच्चों को ठीक उसी राज्यों के लिए सीसा। इसलिए, मैं दो नोड पर subtrees की तुलना करने की प्रभावी कोशिश कर रहा हूँ। मैं सोच रहा हूं कि क्या मैं इस समानता जांच करने के लिए हैशिंग का उपयोग कर सकता हूं।

मुझे लगता है कि मुझे वास्तव में पूरे उपश्री को हैश करने की ज़रूरत है, लेकिन मुझे यकीन नहीं है कि मैं अपनी कक्षा परिभाषा की पुनरावर्ती प्रकृति को देखते हुए कैसे करूँगा।

+2

मुझे लगता है कि आप नोड्स के पेड़ को किसी बिंदु पर समाप्त करते हैं और अनंत नहीं हैं? – justkt

+0

हाँ, यह समाप्त हो जाता है। – efficiencyIsBliss

+1

@ दक्षताIsBliss - जब तक कोई भी बच्चा नोड्स पैरेंट नोड्स को संदर्भित करता है, तब तक आप सरणी पर deepHashCode और deepEquals का उपयोग करने में सक्षम होना चाहिए। – justkt

उत्तर

4

हैशकोड() कार्यान्वयन के हिस्से के रूप में http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#hashCode (java.lang.Object []) शामिल करें।

+0

मैंने अभी अपनी आवश्यकताओं को और अधिक सटीक रूप से प्रतिबिंबित करने के लिए प्रश्न संपादित किया है। यह देखते हुए कि मैं subtrees की समानता की जांच करना चाहता हूं, मुझे नहीं लगता कि मैं उस विधि का उपयोग कर सकता हूं जिसका आप संदर्भ दे रहे हैं। गहरी हैशकोड() नामक एक अन्य विधि भी देखी गई थी, लेकिन वर्णन में कहा गया है कि इसका उपयोग उस सरणी पर नहीं किया जा सकता है जिसमें स्वयं शामिल है, हालांकि मुझे यकीन नहीं है कि मेरी सरणी में 'स्वयं शामिल है'। – efficiencyIsBliss

+0

@ दक्षता bliss यदि आप गारंटी नहीं दे सकते कि आपके नोड्स के बीच कोई रिकर्सिव/चक्रीय संदर्भ नहीं है, तो आप अनंत लूप का जोखिम लेते हैं। वितरित जावा विधियां इन परिस्थितियों की जांच नहीं करती हैं। – JVerstry

1

यह समानता के लिए आपके मानदंडों पर निर्भर करता है। क्या सरणी में ऑर्डर महत्वपूर्ण है? यदि ऐसा है, तो आप शायद हैश कोड को सरणी में नोड्स के क्रम पर निर्भर करना चाहते हैं। यदि नहीं, तो आप सरणी के भीतर सभी नोड्स के हैश कोडों को XOR-ing करना चाहते हैं। संभवतः कुछ मूल्य शून्य हो सकते हैं (इसलिए उस से सावधान रहें)।

असल में, आपको hashCode और equals को लगातार ओवरराइड करने की आवश्यकता है जैसे कि यदि दो ऑब्जेक्ट बराबर हैं, तो उनके पास एक ही हैश कोड होगा। वह सुनहरा नियम है।

एरिक लिपर्ट के पास great blog post about GetHashCode in .NET है - सलाह जावा के लिए समान रूप से अच्छी तरह से लागू होती है।

एक संभावित समस्या के बारे में पता होना चाहिए - यदि आप अपने नोड्स में एक चक्र के साथ समाप्त होते हैं (नोड बी के संदर्भ में नोड ए के संदर्भ में और इसके विपरीत) आप हैश कोड में एक चक्र समाप्त कर सकते हैं गणना भी

1

आप Arrays.hashCode() और Arrays.equals() विधियों का उपयोग कर सकते हैं।

2

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

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

वही ऑब्जेक्ट्स समान हैश मान उत्पन्न करेगा, लेकिन दो अलग-अलग ऑब्जेक्ट्स जो समान नहीं हैं, वही हैश भी उत्पन्न कर सकते हैं।दूसरे शब्दों में, यदि हैश मान अलग हैं, तो आप निश्चित रूप से जानते हैं कि ऑब्जेक्ट अलग हैं। बस।

यदि आप समानता का परीक्षण करना चाहते हैं, तो आपको बराबर लागू करने की आवश्यकता है। आपके मामले में, एक खतरा है कि आपकी विधि रिकर्सिव हो जाएगी और एक स्टैक ओवरफ़्लो उकसाएगी। क्या होगा यदि आपकी ऑब्जेक्ट में स्वयं का संदर्भ है?

यदि आप हैश उत्पन्न करना चाहते हैं, तो आप सरणी का आकार खाते में ले सकते हैं (और तथ्य यह है कि यह शून्य है या नहीं), लेकिन मैं सरणी में ऑब्जेक्ट्स के हैश मान का उपयोग करने की कोशिश नहीं करता , संभावित अनंत लूप की वजह से। यह सही नहीं है, लेकिन यह काफी अच्छा है।

एक और कट्टरपंथी विधि है जो भी अच्छे परिणाम प्रदान कर सकती है। हैश मानों को गतिशील रूप से कंप्यूटिंग करने के बजाय, प्रत्येक नोड ऑब्जेक्ट इंस्टेंस के लिए एक यादृच्छिक int मान सेट करें (मेरा मतलब है सृजन पर सभी के लिए और हमेशा उस मान को वापस करें)। आपके मामले में, आप अपने सरणी में ऑब्जेक्ट इंस्टेंस के हैश मान को लेकर अनंत लूप का जोखिम नहीं उठाएंगे।

यदि हैश बराबर हैं, तो आपको सरणी ऑब्जेक्ट उदाहरणों की तुलना करना प्रारंभ करना होगा।

आरईएम: यदि नोड्स में अन्य विशेषताएं हैं, तो इन अन्य विशेषताओं पर हैश की गणना करें और सरणी के बारे में भूल जाएं। सरणी सामग्री/आकार के बारे में जांच करना शुरू करें यदि केवल और यदि हैश दो ऑब्जेक्ट्स के बीच समान हैं।

आरईएम 2: टिप्पणियां डीएजी ग्राफ का उल्लेख करती हैं, जिसका अर्थ है कि हम रिकर्सिविटी मुद्दों को नहीं मारेंगे। हालांकि, यह शर्त पर्याप्त नहीं है जो गारंटी देता है कि deepHashCode() सफल होगा। इसके अलावा, यह भी अधिक होगा। इस मुद्दे को हल करने के लिए एक और अधिक प्रभावी तरीका है।

यदि नोड द्वारा उपयोग की गई हैश विधि केवल हैश मान की गणना करने के लिए सरणी का उपयोग करती है, तो deepHashCode() काम कर सकता है। लेकिन यह कुशल नहीं होगा। यदि हैश विधि अन्य नोड विशेषताओं का उपयोग करती है, तो इन विशेषताओं को भी बराबर होना होगा।

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

+0

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

+0

@ दक्षता IsBliss - बात यह है कि, [दो असमान वस्तुओं * * के पास एक ही हैशकोड भी हो सकता है] (http://download.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode ())। – justkt

+0

यह सच है। मैंने काफी अच्छा नहीं पढ़ा, मुझे लगता है। – efficiencyIsBliss

0

किसी भी चिंता का प्रदर्शन होने पर, वर्तमान उत्तरों में जोड़ने के लिए कुछ बिंदुएं हैं।

सबसे पहले, आपको यह तय करने की आवश्यकता है कि किसी नोड मामले में बच्चे नोड्स के आदेश दें। यदि वे नहीं करते हैं, तो आप एक सरणी के लिए हैशकोड का उपयोग नहीं कर सकते हैं। java.util.Set द्वारा परिभाषित अपने हैशकोड फ़ंक्शन को फ़ैशन करने पर विचार करें। बराबर प्रदर्शन में सुधार करने के लिए आंतरिक रूप से कुछ ऑर्डरिंग का उपयोग करने पर भी विचार करें। उदाहरण के लिए, यदि subtrees की गहराई/ऊंचाई अलग है, तो आप गहराई से सॉर्ट कर सकते हैं।

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

तीसरा, यदि आपके सबट्री गहरे हैं, तो हैशकोड को बराबर() में जांचें और झूठी वापसी करें। हां, हैशकोड का निरीक्षण मानचित्र कार्यान्वयन द्वारा किया जाता है, लेकिन ऐसी जगहें हैं जहां कोड बराबर() का उपयोग करके दो वस्तुओं की तुलना करता है, और वे एक बड़ी कीमत का भुगतान कर सकते हैं।

अंत में, Arrays का उपयोग करने पर विचार करें।aslist() (यदि बच्चा ऑर्डरिंग मायने रखता है) या हैशसेट (यदि ऑर्डरिंग कोई फर्क नहीं पड़ता है और कोई भी दो बच्चा नोड बराबर नहीं है) एक साधारण सरणी के बजाय। फिर कंटेनर इंस्टेंस में कॉल को प्रतिनिधि करने के लिए बराबर और हैशकोड कम हो जाते हैं ... निश्चित रूप से हैशकोड के उचित कैशिंग के साथ।