最近逛知乎,看到一篇關於紅黑二叉樹的文章,末尾提了一句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方法,暫時未寫,溜了留了