手寫HashMap,實現put,get以及擴容
阿新 • • 發佈:2019-02-09
很晚了不多說了,直接貼程式碼,看完就會了解HashMap是如何實現陣列+連結串列儲存的,希望能給大家帶來幫助,如果有疑問和糾正,請留言,第一時間回覆
public class MyHashMap<K,V> { public Node<K,V>[] table; private static final int DEFAULT_INITAIL_CAPACITY = 1<<4; //負載因子 private static final float DEFAULT_LOAD_FECTOR = 0.75f; //非null的個數 private static int size; private static int theshold; static class Node<K,V>{ private int hash; private K key; private V value; private Node<K,V> next; public Node(int hash, K key, V value, Node<K, V> next) { super(); this.hash = hash; this.key = key; this.value = value; this.next = next; } public int getHash() { return hash; } public void setHash(int hash) { this.hash = hash; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public Node<K, V> getNext() { return next; } public void setNext(Node<K, V> next) { this.next = next; } @Override public String toString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(key+"("+hash+")"); stringBuffer.append("="); stringBuffer.append(value); stringBuffer.append(","); if(null != next){ stringBuffer.append(next.toString()); } return stringBuffer.toString(); } } /** * 新增元素 * @param key * @param value */ public void put(K key,V value){ //獲取hash int hash = Objects.hashCode(key); //指定陣列長度,初始化陣列 int length = DEFAULT_INITAIL_CAPACITY; if(table == null){ theshold = (int)(DEFAULT_INITAIL_CAPACITY * DEFAULT_LOAD_FECTOR); table = new Node[length]; } //根據hashCode取模算出陣列下標 // int i = hash % length; // &運算代替取模 int i = hash & (length -1);//0000-1111 0-15 //判斷table[i]是否存在 if(null == table[i]){ table[i] = new Node<K, V>(hash,key,value,null); }else{ Node<K,V> node = table[i]; //判斷table[i].key是否等於傳入的key if((node.hash == hash) && (node.key == key ||((key !=null) && node.key.equals(key)))){ node.value = value; }else{ for (int count = 0;; count++) { if(null == node.next){ node.next = new Node<K, V>(hash,key,value,null); break; } //判斷next if((node.next.hash ==hash) && (node.next.key == key || (key != null && node.next.key.equals(key)))){ node.next.value = value; break; } node = node.next; } } } size++; if(size >= theshold){ resize(); } } //擴容方法 private void resize(){ //大小翻倍 int newCapacity = table.length << 1; theshold = (int)(newCapacity * DEFAULT_LOAD_FECTOR); Node<K,V>[] newTable = new Node[newCapacity]; //轉移資料 for (Node<K, V> oldNode : table) { if(null == oldNode){ continue; } for (int count = 0;; count++) { if(oldNode == null){ break; } Node<K,V> next = oldNode.next; //新table的下標 int i = oldNode.hash & (newCapacity -1); oldNode.next = newTable[i]; newTable[i] = oldNode; oldNode = next; } } //替換table table = newTable; } /** * 獲取元素 * @param key * @return */ public V get(K key){ //獲取key的hash int hash = Objects.hashCode(key); //判斷table if(table == null || table.length <= 0){ return null; } //根據hashCode取模算出陣列下標 // int i = hash % length; // &運算代替取模 int i = hash & (table.length -1);//0000-1111 0-15 Node<K,V> node = table[i]; if(node == null){ return null; } //按斷key是否相等 if((node.hash == hash) && ((node.key == key) || (key != null && node.key.equals(key)))){ return node.value; }else{ for (int count = 0;; count++) { if(node.next != null){ if((node.next.hash == hash) && ((node.next.key == key) || (key != null && node.next.key.equals(key)))){ return node.next.value; } node = node.next; } } } } @Override public String toString() { StringBuffer stringBuffer = new StringBuffer("{"); for (Node<K, V> node : table) { if( null == node){ continue; } stringBuffer.append(node.toString()); } stringBuffer.append("}"); return stringBuffer.toString(); } }