摘要:數(shù)據(jù)結構小白科普是和中常用的一個容器,采用了數(shù)組鏈表的結構來存儲數(shù)據(jù)新增紅黑樹,當鏈表長度大于以后,鏈表會進化成紅黑樹。下面具體分析的實現(xiàn)思路。
Android 數(shù)據(jù)結構 java 小白科普
HashMap是java和Android中常用的一個容器,采用了數(shù)組+鏈表的結構來存儲數(shù)據(jù)(PS:jdk1.8新增紅黑樹,當鏈表長度大于8以后,鏈表會進化成紅黑樹)。下面具體分析HashMap的實現(xiàn)思路。
1 為什么要用鏈表很多人疑惑,實現(xiàn)HashMap直接用數(shù)組不就可以了嗎,通過hash函數(shù)計算出key對應的數(shù)組的下標,value直接存進去。為什么會用鏈表呢?
問題的關鍵就出在hash函數(shù)身上,因為到現(xiàn)在為止還沒有出現(xiàn)一種一個不同的key對應的hash值都不一樣的函數(shù),(包括MD5,SHA等算法),假如a,b兩個key通過hash函數(shù)得到的數(shù)組下標都是1,a已經(jīng)存進數(shù)組下標為1的位置,b該怎么存儲呢?把a對應的value刪了,替換成b對應的value?這種作法顯然是不可取的。所以在HashMap中引入了鏈表,還是a,b兩個key,存儲a的時候,我們先判斷下數(shù)組下標為1的位置是否有數(shù)據(jù),如果沒有直接插入數(shù)組中,這時候a對應的value插入到了數(shù)組中,這時候我們來存儲b,我們發(fā)現(xiàn)下標為1的位置已經(jīng)存了數(shù)據(jù),我們用a.next來指向b,形成一個鏈表。以此類推。
public V put(K key, V value) { //hash()散列函數(shù),主要作用通過一系列計算,得出應存在數(shù)組的下標 return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node2 get方法[] tab; Node p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) //擴容數(shù)據(jù)搬遷 n = (tab = resize()).length; //查看對應下標是否有數(shù)據(jù),沒有數(shù)據(jù)直接插入數(shù)據(jù) if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node e; K k; //key相等 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; //進化成紅黑樹之后 else if (p instanceof TreeNode) e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { //判斷是不是鏈表最后一個節(jié)點 if ((e = p.next) == null) { //發(fā)現(xiàn)是最后一個節(jié)點的話,添加在隊尾 p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } //key相等 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } //重新賦值 if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
public V get(Object key) { Node3 總結e; return (e = getNode(hash(key), key)) == null ? null : e.value; } final Node getNode(int hash, Object key) { Node [] tab; Node first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {//取出數(shù)組中對應下標數(shù)據(jù) //key相同 hash相同 數(shù)組中的對象就是我們要找的 if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNode )first).getTreeNode(hash, key); do { //循環(huán)遍歷 找到key相同的對象 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }
HashMap通過數(shù)組加鏈表的方式,實現(xiàn)了時間復雜度為O(1)的快速插入,查詢等操作,在平時使用中我們還可以通過指定數(shù)組大小來進一步加快它的性能。
文章中只是寫了大概的思路,有不對的還請見諒!
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/72544.html
摘要:任務名稱響應式砸蛋頁面任務背景前輩方方啊最近項目也沒什么事情你看這個砸蛋頁面不是很好看要不你做一個響應式砸蛋頁面吧系統(tǒng)鄭方方接下前輩的任務鄭方方自動解析任務步驟任務響應式砸蛋頁面與入門閱讀秘籍響應式布局制作層搭配搭配控制器完成任務人物背 任務名稱:響應式砸蛋頁面 任務背景 前輩:方方啊,最近項目也沒什么事情,你看這個砸蛋頁面不是很好看,要不你做一個響應式砸蛋頁面吧? 系統(tǒng):鄭方方接下前...
摘要:任務名稱響應式砸蛋頁面任務背景前輩方方啊最近項目也沒什么事情你看這個砸蛋頁面不是很好看要不你做一個響應式砸蛋頁面吧系統(tǒng)鄭方方接下前輩的任務鄭方方自動解析任務步驟任務響應式砸蛋頁面與入門閱讀秘籍響應式布局制作層搭配搭配控制器完成任務人物背 任務名稱:響應式砸蛋頁面 任務背景 前輩:方方啊,最近項目也沒什么事情,你看這個砸蛋頁面不是很好看,要不你做一個響應式砸蛋頁面吧? 系統(tǒng):鄭方方接下前...
摘要:任務名稱響應式砸蛋頁面任務背景前輩方方啊最近項目也沒什么事情你看這個砸蛋頁面不是很好看要不你做一個響應式砸蛋頁面吧系統(tǒng)鄭方方接下前輩的任務鄭方方自動解析任務步驟任務響應式砸蛋頁面與入門閱讀秘籍響應式布局制作層搭配搭配控制器完成任務人物背 任務名稱:響應式砸蛋頁面 任務背景 前輩:方方啊,最近項目也沒什么事情,你看這個砸蛋頁面不是很好看,要不你做一個響應式砸蛋頁面吧? 系統(tǒng):鄭方方接下前...
閱讀 662·2021-11-24 09:39
閱讀 2315·2021-11-22 13:54
閱讀 2197·2021-09-23 11:46
閱讀 3246·2019-08-30 15:55
閱讀 2679·2019-08-30 15:54
閱讀 2403·2019-08-30 14:18
閱讀 1546·2019-08-29 14:15
閱讀 2732·2019-08-29 13:49