2011-04-08 17 views
23

मैं लागू करने वाले विभिन्न हैशिंग एल्गोरिदम पर मेट्रिक्स लेने के लिए HashMap के अधिकतम आकार को सीमित करना चाहता हूं। मैंने लोडफेक्टर को HashMap के ओवरलोडेड कन्स्ट्रक्टर में से एक में देखा।जावा में हैश मैप के अधिकतम आकार को सीमित करना

Exception in thread "main" java.lang.IllegalArgumentException: Illegal load factor: 0.0 
     at java.util.HashMap.<init>(HashMap.java:177) 
     at hashtables.CustomHash.<init>(Main.java:20) 
     at hashtables.Main.main(Main.java:70) Java Result: 1 

वहाँ एक और है:

HashMap(int initialCapacity, float loadFactor) 

मैं निर्माता में 0.0f को loadFactor की स्थापना (जिसका अर्थ है कि मैं HashMap कभी आकार में विकसित करने के लिए नहीं करना चाहते हैं), लेकिन javac कॉल यह अमान्य करने की कोशिश की HashMap के आकार को सीमित करने का तरीका तो यह कभी नहीं बढ़ता है?

+8

नक्शा भरने पर क्या होना चाहिए और आप एक और तत्व डालने का प्रयास करते हैं? – biziclop

+0

बस एक एफवाईआई के रूप में, हैश टेबल को अपने कीस्पेस को संपीड़ित करने की आवश्यकता है क्योंकि आप प्रत्येक संभावित कुंजी के लिए मान रखने के लिए मेमोरी स्पेस के 2^31 * 4 बाइट आरक्षित नहीं कर सकते हैं। इसलिए, हैश टेबल आमतौर पर हैश को छोटा कर देते हैं और टक्कर के लिए लिंक्ड सूचियों का उपयोग करते हैं। लोडफैक्टर घुमावदार हैश से अधिक बिट्स का उपयोग शुरू होने से पहले जुड़े हुए अधिकतम आकार को इंगित करता है। इसलिए, 0 लंबाई से जुड़ी सूचियां समझ में नहीं आतीं: आप इसमें कुछ भी स्टोर नहीं कर सकते हैं। – chacham15

उत्तर

30

कभी-कभी सरल बेहतर होता है।

public class InstrumentedHashMap<K, V> implements Map<K, V> { 

    private Map<K, V> map; 

    public InstrumentedHashMap() { 
     map = new HashMap<K, V>(); 
    } 

    public boolean put(K key, V value) { 
     if (map.size() >= MAX && !map.containsKey(key)) { 
      return false; 
     } else { 
      map.put(...); 
      return true; 
     } 
    } 

    ... 
} 
+0

@ इशतर, इसके लिए धन्यवाद। – Mike

+0

यह उत्तर आपके मानचित्र के _maximum_ आकार को सीमित करता है। एक सरल मानचित्र के लिए मार्गस का उत्तर देखें जो _or removing_ प्रविष्टियों को रोकता है। LinkedHashMap वर्ग का उल्लेख करने के लिए –

89

आप एक HashMap के आकार को सीमित करने के लिए इस तरह एक नया वर्ग बना सकते हैं:

public class MaxSizeHashMap<K, V> extends LinkedHashMap<K, V> { 
    private final int maxSize; 

    public MaxSizeHashMap(int maxSize) { 
     this.maxSize = maxSize; 
    } 

    @Override 
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { 
     return size() > maxSize; 
    } 
} 
+11

+1, हटाएं EldestEntry() और यह * इस प्रकार के मानचित्र को बनाए रखने के लिए * कार्यक्षमता में बनाया गया है! देखें: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedHashMap.html#removeEldestEntry(java.util.Map.Entry) –

+0

यह एक अच्छा है! –

+3

पिछला जावा लिंक मृत - http://docs.oracle.com/javase/7/docs/api/java/util/LinkedHashMap.html#removeEldestEntry(java.util.Map.Entry) –

1

HashMap कक्षा में विधि put HashMap में तत्वों को जोड़ने के आरोप में से एक है और

void addEntry(int hash, K key, V value, int bucketIndex) { 
     Entry<K,V> e = table[bucketIndex]; 
     table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 
     if (size++ >= threshold) 
      resize(2 * table.length); 
    } 

आप इस विधि में देख सकते हैं है HashMap जहां अगर सीमा मधुमक्खी है आकार दिया जाता है: यह एक तरीका है addEntry नाम पर है जो कोड के रूप में इस फोन करके यह करता है n पार हो गया, इसलिए मैं आकार बदलने के क्रम में put और addEntry के लिए अपनी खुद की विधियों को श्रेणी हैश मैप को विस्तारित करने और अपने स्वयं के तरीकों को लिखने का प्रयास करूंगा। कुछ की तरह:

package java.util; 

public class MyHashMap<K, V> extends HashMap { 


    private V myPutForNullKey(V value) { 
     for (Entry<K, V> e = table[0]; e != null; e = e.next) { 
      if (e.key == null) { 
       V oldValue = e.value; 
       e.value = value; 
       e.recordAccess(this); 
       return oldValue; 
      } 
     } 
     modCount++; 
     myAddEntry(0, null, value, 0); 
     return null; 
    } 

    public V myPut(K key, V value) { 
     if (key == null) 
      return myPutForNullKey(value); 
     if (size < table.length) { 
      int hash = hash(key.hashCode()); 
      int i = indexFor(hash, table.length); 
      for (Entry<K, V> e = table[i]; e != null; e = e.next) { 
       Object k; 
       if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
        V oldValue = e.value; 
        e.value = value; 
        e.recordAccess(this); 
        return oldValue; 
       } 
      } 

      modCount++; 
      myAddEntry(hash, key, value, i); 
     } 
     return null; 
    } 

    void myAddEntry(int hash, K key, V value, int bucketIndex) { 
     Entry<K, V> e = table[bucketIndex]; 
     table[bucketIndex] = new Entry<K, V>(hash, key, value, e); 
     size++; 
    } 
} 

आप put और addEntry के बाद से अपने स्वयं के तरीकों लिखने के लिए की आवश्यकता होगी अधिभावी नहीं किया जा सकता और आप भी, क्योंकि यह put अंदर कहा जाता है putForNullKey के लिए भी ऐसा ही करने की आवश्यकता होगी। put में एक सत्यापन सत्यापित करने के लिए आवश्यक है कि तालिका पूर्ण होने पर हम ऑब्जेक्ट डालने की कोशिश नहीं कर रहे हैं।

6

सरल समाधान आमतौर पर सबसे अच्छा है, इसलिए unmodifiable या Immutable हैशपैप का उपयोग करें।

यदि आप तत्वों की मात्रा नहीं बदल सकते हैं, तो आकार तय किया जाएगा - समस्या हल हो गई है।

+0

मुझे वास्तव में यह बहुत बेहतर पसंद है। – Mike

+0

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

2
public class Cache { 
    private LinkedHashMap<String, String> Cache = null; 
    private final int cacheSize; 
    private ReadWriteLock readWriteLock=null; 
    public Cache(LinkedHashMap<String, String> psCacheMap, int size) { 
     this.Cache = psCacheMap; 
     cacheSize = size; 
     readWriteLock=new ReentrantReadWriteLock(); 
    } 

    public void put(String sql, String pstmt) throws SQLException{ 
     if(Cache.size() >= cacheSize && cacheSize > 0){ 
      String oldStmt=null; 
      String oldSql = Cache.keySet().iterator().next(); 
      oldStmt = remove(oldSql); 
      oldStmt.inCache(false); 
      oldStmt.close(); 

     } 
     Cache.put(sql, pstmt); 
    } 

    public String get(String sql){ 
     Lock readLock=readWriteLock.readLock(); 
     try{ 
      readLock.lock(); 
      return Cache.get(sql); 
     }finally{ 
      readLock.unlock(); 
     } 
    } 

    public boolean containsKey(String sql){ 
     Lock readLock=readWriteLock.readLock(); 
     try{ 
      readLock.lock(); 
      return Cache.containsKey(sql); 
     }finally{ 
      readLock.unlock(); 
     } 
    } 

    public String remove(String key){ 
     Lock writeLock=readWriteLock.writeLock(); 
     try{ 
      writeLock.lock(); 
      return Cache.remove(key); 
     }finally{ 
      writeLock.unlock(); 
     } 
    } 

    public LinkedHashMap<String, String> getCache() { 
     return Cache; 
    } 

    public void setCache(
      LinkedHashMap<String, String> Cache) { 
     this.Cache = Cache; 
    } 


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