2013-01-31 14 views
5

मैंने कुछ वास्तव में डरावनी वृक्षारोपण व्यवहार का अनुभव किया है और मुझे एक छोटे से टेस्ट केस को कम करने में कुछ परेशानी हुई है, इसलिए मेरे साथ भालू।TreeMap put() चुपचाप अन्य प्रविष्टियों को हटा देता है?

मैं रनटाइम पर प्रदान की गई फ़ाइल से मानचित्र में बड़ी संख्या में कुंजी-मूल्य जोड़ों को पढ़ना चाहता हूं। मैं एक कस्टम कुंजी वर्ग का उपयोग कर रहा हूँ। बाद में, जब मैं प्रविष्टियों को वापस खींचने के लिए जाता हूं, तो मुझे लगता है कि उनमें से एक या अधिक गायब हैं। एक डीबगर और कुछ परीक्षण मामलों का उपयोग करके, मैंने यह निर्धारित किया है कि लापता प्रविष्टि (ies) निश्चित रूप से पढ़ने के चरण के दौरान गायब हो रही हैं, लेकिन मुझे यकीन नहीं है कि इसका क्या कारण है।

असल:

Map<MyKey,Double> map = new TreeMap<MyKey,Double>(); 
map.put(key1,value1); 

// ... put another ~500 entries into the map ... 

assertTrue(map.containsKey(key1)); // passes 
if (!map.containsKey(keyN)) { 
    map.put(keyN, valueN); // this code executes 
} 
assertTrue(map.containsKey(key1)); // FAILS 

... तो अनिवार्य रूप से, नक्शे के लिए एक नया कुंजी जोड़ने एक असंबंधित प्रविष्टि इसे से बाहर गिर कारण बनता है।

  • मैं सिर्फ अकेले कुंजी 1 और keyN जोड़ते हैं, तो कुंजी 1 मानचित्र में रहता है - बीच 500 प्रविष्टियों किसी भी तरह महत्वपूर्ण
  • हैं मैं .. 2 से एक या दो मनमाना कुंजी को दूर (एन -1), key1 को तब भी बूट किया जाता है जब कुंजीएन जोड़ा जाता है
  • यदि मैं 2 से बड़ी चाबियाँ हटा देता हूं .. (एन -1), कुंजी 1 तब जोड़ा जाता है जब keyN जोड़ा जाता है, लेकिन जब (कहें) keyQ जोड़ा जाता है, ~ 300 कुंजी
  • दुर्भाग्यवश मानचित्र का आकार जब keyN kicks out key1 है मानचित्र के आकार के समान ही है जब keyQ key1 kicks out, तो यह probab है ly सीमित आकार के मुद्दे
  • यदि मैं इसके बजाय हैश मैप का उपयोग करता हूं, तो कुंजी 1 मानचित्र में रहता है
  • कस्टम कुंजी वर्ग MyKey तुलनात्मक, बराबर, और हैशकोड के लिए एक ही तर्क का उपयोग करता है।

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

+0

स्टीव कुओ के साथ सहमत हैं। अपनी तुलना में टिप्पणी करें/बराबर/हैशकोड कार्यान्वयन और अपना परीक्षण फिर से चलाएं और देखें कि क्या आपको एक ही समस्या है या नहीं। – digitaljoel

उत्तर

11

ट्री मैप दो प्रविष्टियों के बराबर सोचता है, जब तुलना की जाती है, तो परिणाम 0 होता है। इसलिए यदि key1 और keyN '0 से तुलना करें', तो key1 को keyN द्वारा रखा जाएगा()। यह सच है भले ही!key1.equals(keyN)। तो जब आप सोच सकते हैं कि उन दो कुंजियां बराबर नहीं हैं, और इसलिए किसी को डालने से दूसरे को ओवरराइट नहीं करना चाहिए, TreeMap अलग-अलग सोचेंगे यदि आपके बराबर और तुलनात्मक कार्य एक-दूसरे के साथ असंगत हैं।

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

TreeMap javadocs से:

...मानचित्र क्रमबद्ध नक्शा, बराबर की दृष्टि से इसकी compareTo का उपयोग कर सभी प्रमुख तुलना करता है (या तुलना) विधि, इसलिए दो कुंजी है कि इस विधि से बराबर माना जाता है कर रहे हैं, ...

और Comparable javadocs से (धन्यवाद @Brian):

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

+1

+1 यही कारण है कि 'तुलना करने के लिए' स्थिरता खंड javadocs में है: "यह दृढ़ता से अनुशंसा की जाती है (हालांकि आवश्यक नहीं) कि प्राकृतिक क्रम बराबर के साथ संगत हो। ऐसा इसलिए है क्योंकि स्पष्ट तुलनाकर्ताओं के बिना सॉर्ट किए गए सेट (और सॉर्ट किए गए मानचित्र) व्यवहार करते हैं "अजीब" जब वे तत्वों (या चाबियों) के साथ प्रयोग किया जाता है जिसका प्राकृतिक आदेश बराबर के साथ असंगत है। " (['तुलनात्मक'] (http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html)) – Brian

+0

@ ब्रायन उस उद्धरण के लिए धन्यवाद, मैंने इसे उत्तर में जोड़ा। – sharakan

+0

हां, यह था - जिस चीज को मैं याद कर रहा था वह था कि वास्तविक तुलना() कॉल जो कि कुंजी 1 को लात मारती है, नई कुंजी के साथ जरूरी नहीं है, लेकिन पेड़ के पुनर्वसन के हिस्से के रूप में। धन्यवाद! – krivard

0

क्या आप सुनिश्चित हैं कि keyN किसी भी परिदृश्य में key1 को ओवरराइट नहीं कर रहा है? क्योंकि ऐसा लगता है कि यह आपका प्रेत मामला है।

1

हमें MyKey के लिए कोड दिखाएं। मेरा अनुमान है कि आपके compareTo विधि में कुछ गड़बड़ है। अधिक विशेष रूप से आपके compareToequals के साथ संगत नहीं है।

संबंधित मुद्दे