DoubleKeyMap_实现

来源:互联网 发布:敏捷软件开发 pdf 编辑:程序博客网 时间:2024/06/16 08:10

DoubleKeyMap接口类

package cs601.collections;import java.util.List;/** A Map (Dictionary) just like Java's Map<K,V> interface except that * this interface has 2 keys instead of just one. Otherwise it works * the same way. */public interface DoubleKeyMap<K1,K2,V> {    /** Add (key1,key2,value) to dictionary, overwriting previous     *  value if any.  key1, key2, and value must all be non-null.     *  If any is null, throw IllegalArgumentException.     *  @return the previous value associated with <tt>key</tt>, or     * <tt>null</tt> if there was no mapping for <tt>key</tt>.     *     */    V put(K1 key1, K2 key2, V value);    /** Return the value associated with (key1, key2). Return null if     *  no value exists for those keys.  key1, key2 must be non-null.     *  If any is null, throw IllegalArgumentException.  The value     *  should be just the value added by the user via put(), and     *  should not contain any of your internal bookkeeping     *  data/records.     */    V get(K1 key1, K2 key2);    /** Remove a value if present. Return previous value if any.     *  Do nothing if not present.     */    V remove(K1 key1, K2 key2);    /** Return true if there is a value associated with the 2 keys     *  else return false.     *  key1, key2 must be non-null. If either is null, return false.     */    boolean containsKey(K1 key1, K2 key2);    /** Return list of a values in the map/dictionary.  Return an     *  empty list if there are no values.  The values should be just     *  the values added by the user via put(), and should not contain     *  any of your internal bookkeeping data/records.     */    List<V> values();    /** Return how many elements there are in the dictionary. */    int size();    /** Reset the dictionary so there are no elements. */    void clear();}

DoubleKeyHashMap  内部构建了一个hashtable实现

package cs601.collections;import java.util.*;public class DoubleKeyHashMap<K1, K2, V> implements DoubleKeyMap<K1, K2, V> {    private float loadFactor;    private int threshold;    private LinkedList<Entry<K1, K2, V>>[] table;    private int count;    private static final int MAX_TABLE_SIZE = Integer.MAX_VALUE - 8;    public static class Entry<K1, K2, V> {        final int hash;        final K1 key1;        final K2 key2;        V value;        protected Entry(int hash, K1 key1, K2 key2, V value) {            this.hash = hash;            this.key1 = key1;            this.key2 = key2;            this.value = value;        }        public K1 getKey1() {            return key1;        }        public K2 getKey2() {            return key2;        }        public V getValue() {            return value;        }        public V setValue(V value) {            if (value == null) {                throw new IllegalArgumentException("Entry setValue must be non-nil");            }            V oldValue = this.value;            this.value = value;            return oldValue;        }    }    public DoubleKeyHashMap() {        this(11);    }    public DoubleKeyHashMap(int initialCapacity) {        this(initialCapacity, 0.75f);    }    public DoubleKeyHashMap(int initialCapacity, float loadFactor) {        if (initialCapacity < 0) {            throw new IllegalArgumentException("initialCapacity must be non-0");        }        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {            throw new IllegalArgumentException("Illegal Load: " + loadFactor);        }        if (initialCapacity == 0) {            initialCapacity = 1;        }        this.loadFactor = loadFactor;        table = (LinkedList<Entry<K1, K2, V>>[]) new LinkedList[initialCapacity];        this.threshold = (int) (loadFactor * initialCapacity);    }    Map<K1, Map<K2, V>> data = new HashMap<K1, Map<K2, V>>();    List<V> values;    private void checkKeys(K1 key1, K2 key2) {        if (key1 == null) {            throw new IllegalArgumentException("key1 must be non-nil");        }        if (key2 == null) {            throw new IllegalArgumentException("key2 must be non-nil");        }    }    @Override    public V put(K1 key1, K2 key2, V value) {        checkKeys(key1, key2);        LinkedList<Entry<K1, K2, V>>[] tab = table;        int hash = Math.abs(key1.hashCode() * 37 + key2.hashCode());        int index = (hash & 0x7FFFFFFF) % tab.length;        LinkedList<Entry<K1, K2, V>> entrys = tab[index];        if (entrys != null) {            int entrySize = entrys.size();            for (int i = 0; i < entrySize; i++) {                Entry<K1, K2, V> entry = entrys.get(i);                if (key1.equals(entry.key1) && key2.equals(entry.key2) && hash == entry.hash) {                    V oldValue = entry.setValue(value);                    return oldValue;                }            }        }        if (count >= threshold) {            rehash();            tab = table;            hash = Math.abs(key1.hashCode() * 37 + key2.hashCode());            index = (hash & 0x7FFFFFFF) % tab.length;        }        if (entrys == null) {            entrys = new LinkedList<Entry<K1, K2, V>>();        }        entrys.addFirst(new Entry<K1, K2, V>(hash, key1, key2, value));        tab[index] = entrys;        count++;        return null;    }    private void rehash() {        int oldCapacity = table.length;        LinkedList<Entry<K1, K2, V>>[] oldTable = table;        int newCapacity = (oldCapacity << 1) + 1;        if (newCapacity - MAX_TABLE_SIZE > 0) {            if (oldCapacity == MAX_TABLE_SIZE) {                return;            }            newCapacity = MAX_TABLE_SIZE;        }        LinkedList<Entry<K1, K2, V>>[] newTable = (LinkedList<Entry<K1, K2, V>>[]) new LinkedList[newCapacity];        threshold = (int) Math.min(newCapacity * loadFactor, MAX_TABLE_SIZE + 1);        table = newTable;        for (int i = oldCapacity; i-- > 0; ) {            LinkedList<Entry<K1, K2, V>> oldEntrys = oldTable[i];            if (oldEntrys == null) {                continue;            }            for (int j = 0; j < oldEntrys.size(); j++) {                Entry<K1, K2, V> entry = oldEntrys.get(j);                int index = (entry.hash & 0x7FFFFFFF) % newCapacity;                LinkedList<Entry<K1, K2, V>> indexEntrys = newTable[index];                if (indexEntrys == null) {                    indexEntrys = new LinkedList<Entry<K1, K2, V>>();                }                indexEntrys.addFirst(entry);                newTable[index] = indexEntrys;            }        }    }    @Override    public V get(K1 key1, K2 key2) {        checkKeys(key1, key2);        LinkedList<Entry<K1, K2, V>>[] tab = table;        int hash = Math.abs(key1.hashCode() * 37 + key2.hashCode());        int index = (hash & 0x7FFFFFFF) % tab.length;        LinkedList<Entry<K1, K2, V>> entrys = tab[index];        if (entrys == null) {            return null;        }        for (int i = 0; i < entrys.size(); i++) {            Entry<K1, K2, V> entry = entrys.get(i);            if (key1.equals(entry.key1) && key2.equals(entry.key2) && hash == entry.hash) {                return entry.value;            }        }        return null;    }    @Override    public V remove(K1 key1, K2 key2) {        if (key1 == null || key2 == null) {            return null;        }        LinkedList<Entry<K1, K2, V>>[] tab = table;        int hash = Math.abs(key1.hashCode() * 37 + key2.hashCode());        int index = (hash & 0x7FFFFFFF) % tab.length;        LinkedList<Entry<K1, K2, V>> entrys = tab[index];        if (entrys == null) {            return null;        }        for (int i = 0; i < entrys.size(); i++) {            Entry<K1, K2, V> entry = entrys.get(i);            if (key1.equals(entry.key1) && key2.equals(entry.key2) && hash == entry.hash) {                entrys.remove(entry);                if (entrys.isEmpty()) {                    tab[index] = null;                }                return entry.value;            }        }        return null;    }    @Override    public boolean containsKey(K1 key1, K2 key2) {        if (key1 == null || key2 == null) {            return false;        }        LinkedList<Entry<K1, K2, V>>[] tab = table;        int hash = Math.abs(key1.hashCode() * 37 + key2.hashCode());        int index = (hash & 0x7FFFFFFF) % tab.length;        LinkedList<Entry<K1, K2, V>> entrys = tab[index];        if (entrys == null) {            return false;        }        for (int i = 0; i < entrys.size(); i++) {            Entry<K1, K2, V> entry = entrys.get(i);            if (key1.equals(entry.key1) && key2.equals(entry.key2) && hash == entry.hash) {                return true;            }        }        return false;    }    @Override    public List<V> values() {        if (values == null) {            values = new ArrayList<V>();        }        values.clear();        LinkedList<Entry<K1, K2, V>>[] tab = table;        for (int i = 0; i < tab.length; i++) {            LinkedList<Entry<K1, K2, V>> entrys = tab[i];            if (entrys == null) {                continue;            }            for (Entry<K1, K2, V> entry : entrys) {                values.add(entry.value);            }        }        return values;    }    @Override    public int size() {        return values().size();    }    @Override    public void clear() {        LinkedList<Entry<K1, K2, V>>[] tab = table;        for (int i = tab.length; i-- >= 0; ) {            tab[i] = null;        }    }}

0 0
原创粉丝点击