手寫HashMap+HashMap原理解說(一)
阿新 • • 發佈:2019-01-31
最近看到一個面試題:手寫HashMap,第一次寫這個東西,覺得無從下手,上網copy了很多程式碼,複雜是複雜,就是有錯,put進去的東西,並不能get出來,無奈之下自己寫,以下是實現了簡單的get()和put()方法,先上傳,下次把擴容等功能補上。
寫之前最好先理解一下原理,可以少走彎路,先新建16個桶即bucket(16是原始碼預設的,可以自定義),給桶分別標上1~16標號,put一個鍵值對之後,用key的hash值對16取餘,結果肯定也是一個1~16範圍內的數值,把這對鍵值對放到取餘後的值對應的那個的桶裡(注意,不可能為每一個hash值都建立一個桶,那樣的話代價太大,這裡只建立了16個桶,所以很有可能一個桶裡放入多個鍵值對;如果偏巧那個桶裡是空的,直接把key、value放進去ok的,如果桶不為空,就要一個一個比對桶裡原有的key是否和現在要放進去的key是同一個(即hash值相同且equals為true),如果是同一個,那麼就用新的value覆蓋替換原來的value就行,如果遍歷完了,沒有一個相同的key,那麼就放到所有key的最後面(據說jdk1.8之後是放在最前面,具體還沒有研究到),這樣有多個鍵值對的桶裡就形成了一個連結串列結構,而多個桶之間是陣列元素的關係,所以說hashmap就是陣列+連結串列結構。
public interface MyMap<K, V> {
V put(K key, V value);
V get(K key);
interface Entry<K, V> {
K getKey();
V getValue();
}
}
public class MyHashMap<K, V> implements MyMap<K, V> { private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; private static final float DEFAULT_LOAD_FACTOR = 0.75f; private float loadFactor = 0; private int initCapacity = 0; private Entry<K, V>[] table = null; public MyHashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; this.initCapacity = DEFAULT_INITIAL_CAPACITY; table = new Entry[this.initCapacity]; } public MyHashMap(int initCapacity, float loadFactor) { this.loadFactor = loadFactor; this.initCapacity = initCapacity; table = new Entry[this.initCapacity]; } private int hash(K key) { int h; return (key == null) ? 0 : Math.abs((h = key.hashCode())) ^ (h >>> 16); } @Override public V put(K key, V value) { int index = hash(key) % initCapacity; if (table[index] != null) { Entry<K, V> e = table[index]; Entry<K, V> e2 = null; while (e != null) { if (hash(e.key) == hash(key) && e.key.equals(key)) { e.value = value; return value; } e2 = e; e = e.next; } e2.next = new Entry<>(key, value, null, index); } else { Entry<K, V> e = new Entry<>(key, value, null, index); table[index] = e; } return value; } @Override public V get(K key) { int index = hash(key) % initCapacity; Entry<K, V> e = table[index]; if (e == null) { return null; } while (e != null) { if (e.key == null && key == null || hash(e.key) == hash(key) && e.key.equals(key)) { return e.value; } e = e.next; } return null; } class Entry<K, V> implements MyMap.Entry<K, V> { K key; V value; Entry<K, V> next; int index;//記錄下標 Entry(K k, V v, Entry<K, V> next, int inx) { this.key = k; this.value = v; this.index = inx; this.next = next; } public K getKey() { return key; } public V getValue() { return value; } public Entry getNext() { return next; } } }
public class Test { public static void main(String[] args) { // Map<String, String> map = new HashMap(); // map.put("name","sophia"); // map.put("age", "18"); // System.out.println(map.get("name")); // System.out.println(map.get("age")); MyMap<String, Object> map = new MyHashMap<>(); map.put("name", "sophia"); map.put("age", 18); map.put("hahaha", "hehehe"); map.put("hehehe", "lalala"); map.put(null, "lalala"); System.out.println(map.get("name")); System.out.println(map.get("age")); System.out.println(map.get("hahaha")); System.out.println(map.get("hehehe")); System.out.println(map.get(null)); } }