在jdk1.7版本的hashmap 底層採用了鍊錶+陣列的方式實現資料的儲存及擴容等,在jdk1.8後hashmap的底層換為紅黑樹+陣列的方式。這邊以鍊錶+陣列的方式模仿原始碼寫乙個自己的簡易hashmap。
其中初始容量設為的10,負載因子設定0.5,上面效果已有了擴容的效果。
因為是基於鍊錶+陣列實現的,所以要定義乙個node鍊錶陣列,有陣列肯定需要定義陣列的大小,這裡預設是10,原始碼預設是16。看過原始碼的肯定知道還要設定乙個負載因子,定義容量達到多少的時候開始進行擴容,比如初始容量10,負載因子為0.5,則儲存容量達到50%時要進行擴容。
put資料時,先判斷儲存容量有沒有達到負載因子定義的擴容大小,如果沒有達到,則拿到key的hashcode值,採用hashcode%陣列大小獲得儲存位置下標,也就是具體存到前面定義的陣列的某個位置,先判斷該位置是否已經存有值,如果沒有直接將node物件付給該位置,如果已經存有值,則要從第乙個node 一直取next 下乙個node,並判斷key是否相等,相等則覆蓋,沒有則在最後乙個node後新增node。
如果上面put時達到了擴容的大小,則新建乙個node鍊錶陣列,大小為上面鍊錶的兩倍,所有資料都要移到新的鍊錶陣列中,陣列的大小發生了變化,那上面計算的hashcode%陣列大小也發生了變化,所以資料放到新的陣列中,需要重新計算其下標位置。
使用者獲取資料,同樣先拿到hashcode%陣列大小,定位在那個鍊錶中,然後再next 判斷key,拿到就將value返還給使用者。
class node
public k getkey()
public v getvalue()
public v setvalue(v value)
}
這裡就實現put,get,size功能
public inte***ce bxcmap
//鍊錶的陣列
node table = null;
//儲存資料個數
int size;
//負載因子
float default_load_factor = 0.5f;
//初始大小
static int default_initial_capacity = 10;
public v put(k key, v value)
//判斷是否需要擴容
if (size > (default_load_factor * default_initial_capacity))
//拿到下標的位置
int index = getindex(key, default_initial_capacity);
nodenode = table[index];
//如果該位置沒有,就新建物件存入
if (node == null) else else
}newnode = newnode.next;}}
table[index] = node;
return null;
}
public int getindex(k k, int length)
private void resize()
}table = newtable;
default_initial_capacity = newtable.length;
}
public v get(k k)
public nodegetnode(nodenode, k k)
node = node.next;
}return null;
}
public int size()
對於HashMap為什麼要使用陣列加鍊表的個人思考
問題的源頭 hashmap資料結構是?陣列加鍊表,1.8增加了紅黑樹,那麼為什麼?陣列的特點查詢快,增刪慢,鍊錶查詢慢,增刪快,陣列加鍊表是折中方案 其實這種描述並不準確,因為在使用hashmap的時候陣列插入並不慢,而鍊錶增刪快的特點也沒有發揮出來,因為每次put都需要遍歷一遍判斷key值是否相等...
手寫反轉鍊錶
實現過程 line 9 11是將原鍊錶的第乙個節點變成了新鍊錶的最後乙個節點,同時將原鍊錶的第二個節點儲存在cur中 line13 16就是從原鍊錶的第二個節點開始遍歷到最後乙個節點,將所有節點翻轉一遍 以翻轉第二個節點為例 temp cur.next是將cur的下乙個節點儲存在temp中,也就是第...
手寫 LinkedList(雙向鍊錶)
用於 linkedlist 繼承 param public inte ce mylist public class mylinkedlist implements mylist 1.00 將 element 作為最後乙個節點進行連線 param element void linklast e ele...