【java】實現自己的hashMap--基礎hashcode與二叉樹

最近逛知乎,看到一篇關於紅黑二叉樹的文章,末尾提了一句java的hashmap用到了紅黑樹,突發奇想自己也寫一個,儘量多地實現map的方法吧


首先,自定義自己的map接口

public interface CoolMap<K,V> {
//清空coolmap
public void clear();
//檢查是否存在該key
public boolean containsKey(K key);
//檢查是否存在該value
public boolean containsValue(V value);
//根據key獲取value
public V get(K key);
//檢查該coolmap是否爲空
public boolean isEmpty();
//插入鍵值對應關係
public V put(K key,V value);
//插入coolMap
public void putAll(CoolMap<K,V> coolMap);
//移除鍵值對應關係
public V remove(K key);
//獲取當前map擁有的結點數
public int size();
//獲取所有值的集合
public Collection<V> values();
//獲取所有鍵的集合
public Set<K> keySet();
}

//當然如果對照map的文檔,發現我少了entrySet方法,後面我再改進吧


接下來,編寫coolmap的實現類,基於hashcode對比key,自然類名就是HashCoolMap

public class HashCoolMap<K, V> implements CoolMap<K, V>

然後在我目前的設計中,每個HashCoolMap可以看作是一個結點,和hashmap實現原理略有不同,那麼既然是結點,就有相關的屬性

	private K key=null;
	private V value=null;
	private CoolMap<K, V> leftChild=null;
	private CoolMap<K, V> rightChild=null;

實現最基本功能,put與get方法

public V put(K key, V value) {
		//對所有key爲null的情況不做討論
		if(key==null)return null;
		//檢測可插入當前結點
		if(this.key==null
				||this.key.hashCode()==key.hashCode()){
			//替換當前結點
			this.key=key;
			this.value=value;
			return this.value;
		}
		//根據對比hacode大小判斷插入左孩子結點還是右孩子結點
		if(searchLeft(key)){
			if(leftChild==null){
				leftChild=new HashCoolMap<K,V>();
			}
			return leftChild.put(key, value);
		}else{
			if(rightChild==null){
				rightChild=new HashCoolMap<K,V>();
			}
			return rightChild.put(key, value);
		}
	}
	
	public V get(K key) {
		//對所有key爲null的情況不做討論
		if(key==null)return null;
		//返回當前結點的值
		if(this.key==null
				||this.key.hashCode()==key.hashCode()){
			return this.value;
		}
		//根據對比hashcode大小判斷查找左邊還是右邊
		if(searchLeft(key)){
			if(leftChild==null){
				return null;
			}
			return leftChild.get(key);
		}else{
			if(rightChild==null){
				return null;
			}
			return rightChild.get(key);
		}
	}

	//私有方法,判斷是否查找左孩子結點
	private boolean searchLeft(K key){
		return this.key.hashCode()>key.hashCode();
	}
編寫main方法測試put與get方法
public static void main(String[] args){
		CoolMap<String,String> coolMap=new HashCoolMap<String,String>();
		System.out.println("null:"+coolMap.get("key1"));
		System.out.println("value1:"+coolMap.put("key1", "value1"));
		System.out.println("value1:"+coolMap.get("key1"));
		System.out.println("value2:"+coolMap.put("key1", "value2"));
		System.out.println("value2:"+coolMap.get("key1"));
		System.out.println("value2:"+coolMap.put("key2", "value2"));
		System.out.println("value3:"+coolMap.put("key3", "value3"));
		System.out.println("value4:"+coolMap.put("key4", "value4"));
		System.out.println("value5:"+coolMap.put("key5", "value5"));
		System.out.println("value6:"+coolMap.put("key6", "value6"));
		System.out.println("value4:"+coolMap.get("key4"));
	}
查看結果

其中對於key爲null時的處理,我直接忽視,不過hashmap中對key爲null的情況下也可以有鍵值對應關係

實現clear、containsKey、containsValue、isEmpty、putAll、size、values、keySet方法

	public void clear() {
		//清空當前結點
		key=null;
		value=null;
		//去掉內存引用,等待java內存釋放機制自動釋放內存
		leftChild=null;
		rightChild=null;
		//雖然沒什麼卵用,但還是調用一下吧
		System.gc();
	}
	
	public boolean containsKey(K key) {
		//對所有key爲null的情況不做討論
		if(key==null)return false;
		if(this.key.hashCode()==key.hashCode()){
			return true;
		}
		//查找子結點
		if(searchLeft(key)){
			if(leftChild==null){
				return false;
			}
			return leftChild.containsKey(key);
		}else{
			if(rightChild==null){
				return false;
			}
			return rightChild.containsKey(key);
		}
	}

	public boolean containsValue(V value) {
		return //判斷當前結點
				(this.value==null&&value==null)//都爲null
				||(this.value!=null&&this.value.equals(value))//不爲null
				//判斷子結點
				||(this.leftChild!=null&&this.leftChild.containsValue(value))
				||(this.rightChild!=null&&this.rightChild.containsValue(value));
	}
	
	public boolean isEmpty() {
		//因爲對key爲null的情況不做考慮,因此可以將當前key是否爲null作爲判斷依據
		return this.key==null;
	}

	public void putAll(CoolMap<K, V> coolMap) {
		Set<K> keySet=coolMap.keySet();
		//傳入左孩子下的coolMap
		CoolMap<K, V> leftCoolMap=new HashCoolMap<K, V>();
		//傳入右孩子下的coolMap
		CoolMap<K, V> rightCoolMap=new HashCoolMap<K, V>();
		for(Iterator<K> it=keySet.iterator();it.hasNext();){
			K key=it.next();
			//替換當前結點
			if(this.key.hashCode()==key.hashCode()){
				this.value=coolMap.get(key);
				continue;
			}
			//根據hashcode大小分配到左右孩子coolMap
			if(searchLeft(key)){
				leftCoolMap.put(key, coolMap.get(key));
			}else{
				rightCoolMap.put(key, coolMap.get(key));
			}
		}
		//調用子結點的putAll方法
		if(!leftCoolMap.isEmpty()){
			if(this.leftChild==null){
				this.leftChild=new HashCoolMap<>();
			}
			this.leftChild.putAll(leftCoolMap);
		}
		if(!rightCoolMap.isEmpty()){
			if(this.rightChild==null){
				this.rightChild=new HashCoolMap<>();
			}
			this.rightChild.putAll(rightCoolMap);
		}
	}

	public int size() {
		int currentSize=0;
		int leftChildSize=0;
		int rightChildSize=0;
		//當前結點數量
		if(this.key!=null){
			currentSize=1;
		}
		//左孩子結點下數量
		if(this.leftChild!=null){
			leftChildSize=this.leftChild.size();
		}
		//右孩子結點下數量
		if(this.rightChild!=null){
			rightChildSize=this.rightChild.size();
		}
		return currentSize+leftChildSize+rightChildSize;
	}

	public Collection<V> values() {
		Collection<V> collection=new ArrayList<V>();
		//判斷爲空
		if(this.isEmpty()){
			return collection;
		}
		//左中右
		if(this.leftChild!=null){
			collection.addAll(this.leftChild.values());
		}
		collection.add(this.value);
		if(this.rightChild!=null){
			collection.addAll(this.rightChild.values());
		}
		return collection;
	}

	public Set<K> keySet() {
		Set<K> set=new HashSet<K>();
		//添加當前結點的key
		if(this.key!=null){
			set.add(key);
		}
		//添加子結點的key
		if(this.leftChild!=null){
			Set<K> leftSet=this.leftChild.keySet();
			for(Iterator<K> it=leftSet.iterator();it.hasNext();){
				set.add(it.next());
			}
		}
		if(this.rightChild!=null){
			Set<K> rightSet=this.rightChild.keySet();
			for(Iterator<K> it=rightSet.iterator();it.hasNext();){
				set.add(it.next());
			}
		}
		return set;
	}

編寫測試方法

public static void main(String[] args){
		CoolMap<String,String> coolMap=new HashCoolMap<String,String>();
		System.out.println("null:"+coolMap.get("key1"));
		System.out.println("value1:"+coolMap.put("key1", "value1"));
		System.out.println("value1:"+coolMap.get("key1"));
		System.out.println("value2:"+coolMap.put("key1", "value2"));
		System.out.println("value2:"+coolMap.get("key1"));
		System.out.println("value2:"+coolMap.put("key2", "value2"));
		System.out.println("value3:"+coolMap.put("key3", "value3"));
		System.out.println("value4:"+coolMap.put("key4", "value4"));
		System.out.println("value5:"+coolMap.put("key5", "value5"));
		System.out.println("value6:"+coolMap.put("key6", "value6"));
		System.out.println("value4:"+coolMap.get("key4"));
		
		System.out.println("false:"+coolMap.isEmpty());
		System.out.println("false:"+coolMap.containsKey("key7"));
		System.out.println("true:"+coolMap.containsKey("key6"));
		System.out.println("false:"+coolMap.containsValue("value7"));
		System.out.println("true:"+coolMap.containsValue("value5"));
		System.out.println(coolMap.values());
		System.out.println(coolMap.keySet());
		coolMap.clear();
		System.out.println("true:"+coolMap.isEmpty());
		
		CoolMap<String,String> coolMap1=new HashCoolMap<String,String>();
		coolMap1.put("k1", "v1");
		coolMap1.put("k2", "v2");
		coolMap1.put("k3", "v3");
		coolMap1.put("k4", "v4");
		CoolMap<String,String> coolMap2=new HashCoolMap<String,String>();
		coolMap2.put("k5", "v5");
		coolMap2.put("k2", "vv2");
		coolMap2.put("k3", "v3");
		coolMap2.put("k4", "v4");
		coolMap.putAll(coolMap1);
		coolMap.putAll(coolMap2);
		System.out.println(coolMap.keySet());
		System.out.println(coolMap.values());
		System.out.println(coolMap.size());
	}

結果



還有remove方法,暫時未寫,溜了留了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章