1. 程式人生 > >原始碼——手寫一個簡單的HashMap

原始碼——手寫一個簡單的HashMap

定義:用於儲存Key-Value鍵值對集合,

儲存結構:線性連結串列(陣列+連結串列)。陣列:固定長度,索引效率高,增刪效率低-----連結串列:長度不固定,索引效率低,增刪效率高

雜湊值特點:同一物件呼叫多次hashcode()方法,必須返回相同的數值。(冪等)

                    如果兩個物件根據equals()方法比較是相等的,那麼兩個物件呼叫hashcode()方法返回的結果必須相等;

                                if(a==b)   a.hashcode()==b.hashcode()

                    如果兩個物件的equals()方法比較是不相等的,那麼兩個物件呼叫hashcode()方法返回的結果不一定不相等

hash演算法實現:取模,求與,線性探測,其他 

public interface Map<K,V> {

	//向hashMap中插入值
	public V put(K k,V v); 
	
	//根據key獲取hashMap中的值
	public V get(K k);
	
	//獲得集合中元素的個數
	public int size();
	
	//獲取集合中,鍵值對的物件
	interface Entry<K,V>{
		K getKey();
		
		V getValue();
		
		V setValue(V v);
		
	}
}
package HashMap;


public class HashMap<K, V> implements Map<K, V> {
	//資料儲存的結構==>陣列+連結串列
	Node<K,V>[] array=null;
	
	//陣列/雜湊桶的長度 
	private static int defaultLength=16;
	
	//載入因子/擴容因子
	private static double factor=0.75D;
	
	//集合中的元素個數
	private int size;

	//測試列印函式
	public void print() {
		System.out.println("===============================");
		if(array!=null) {
			Node<K, V> node=null;			
			for (int i = 0; i < array.length; i++) {
				node=array[i];
				System.out.print("下標["+i+"]");
				//遍歷連結串列
				while(node!=null) {
					System.out.print("["+node.getKey()+":"+node.getValue()+"]");
					if(node.next!=null) {
						node=node.next;
					}else {
						//到尾部元素
						node=null;
					}
				}
				System.out.println();
			}
			
		}
	}
	
	//put元素方法
	@Override
	public V put(K k, V v) {
		
		//1.懶載入機制,使用的時候進行分配
		if(array==null) {
			array=new Node[defaultLength];
		}
		
		//2.通過hash演算法,計算出具體插入的位置
		int index=position(k,defaultLength);
		
		
		//擴容。判斷是否需要擴容
		//擴容的準則,元素的個數   大於  桶的尺寸*載入因子
		if(size > defaultLength*factor) {
			resize();
		}
		
		//3.放入要插入的元素
		Node<K, V> node=array[index];
		if(node==null) {
			array[index]=new Node<K,V>(k,v,null);
			size++;
		}else {
			if(k.equals(node.getKey()) || k==node.getKey()) {
				return node.setValue(v);
			}else {
				array[index]=new Node<K,V>(k,v,node);
				size++;
			}
		}
			
		return null;
	}

	//擴容,並且重新排列元素
	private void resize() {
		//翻倍擴容
		//1.建立新的array臨時變數,相當於defaultlength*2
		Node<K, V>[] temp=new Node[defaultLength << 1];
		
		//2.重新計算雜湊值,插入到新的array中去。 code=key % defaultLength ==> code=key % defaultLength*2
		Node<K, V> node=null;
		for (int i = 0; i < array.length; i++) {
			node=array[i];
			while(node!=null) {
				//重新雜湊
				int index=position(node.getKey(),temp.length);
				//插入頭部
				Node<K, V> next = node.next;
				//3
				node.next=temp[index];
				//1
				temp[index]=node;
				//2
				node=next;
				
			}
		}
		
		//3.替換掉老array
		array=temp;
		defaultLength=temp.length;
		temp=null;
		
		
	}

	private int position(K k,int length) {
		int code=k.hashCode();
		
		//取模演算法
		return code % (length-1);
		
		//求與演算法
		//return code & (defaultLength-1);
	}

	@Override
	public V get(K k) {
		if(array!=null) {
			int index=position(k,defaultLength);
			Node<K, V> node=array[index];	
			//遍歷連結串列
			while(node!=null) {
					//如果key值相同返回value
					if(node.getKey()==k) 					
						return node.getValue();
					else
						//如果key值不同則調到下一個元素
						node=node.next;
					}
				}
			
		
		return null;
	}

	@Override
	public int size() {
		 
		return size;
	}

	static class Node<K,V> implements Entry<K,V>{
		K key;
		V value;
		Node<K,V> next;
		
		
		public Node(K key, V value, Node<K, V> next) {
			super();
			this.key = key;
			this.value = value;
			this.next = next;
		}

		@Override
		public K getKey() {
			return this.key;
		}

		@Override
		public V getValue() {
			return this.value;
		}

		@Override
		public V setValue(V v) {
			V oldValue=this.value;
			this.value=v;
			return oldValue;
		}
		
	}
}
public class Test {
	public static void main(String[] args) {
		HashMap<String, String> map=new HashMap<String, String>();
		map.put("001號", "001");
		map.put("002號", "002");
		map.put("003號", "003");
		map.put("004號", "004");
		map.put("005號", "005");
		map.put("006號", "006");
		map.put("007號", "007");
		map.put("008號", "008");
		map.put("009號", "009");
		map.put("010號", "010");
		map.put("011號", "011");
		map.print();
		
		System.out.println("========>"+map.get("009號"));
	}
}