1. 程式人生 > >手寫HashMap,實現put,get以及擴容

手寫HashMap,實現put,get以及擴容

很晚了不多說了,直接貼程式碼,看完就會了解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();
	}
	
}