摘要:數(shù)據(jù)結(jié)構(gòu)小白科普是和中常用的一個(gè)容器,采用了數(shù)組鏈表的結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)新增紅黑樹(shù),當(dāng)鏈表長(zhǎng)度大于以后,鏈表會(huì)進(jìn)化成紅黑樹(shù)。下面具體分析的實(shí)現(xiàn)思路。
Android 數(shù)據(jù)結(jié)構(gòu) java 小白科普
HashMap是java和Android中常用的一個(gè)容器,采用了數(shù)組+鏈表的結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)(PS:jdk1.8新增紅黑樹(shù),當(dāng)鏈表長(zhǎng)度大于8以后,鏈表會(huì)進(jìn)化成紅黑樹(shù))。下面具體分析HashMap的實(shí)現(xiàn)思路。
1 為什么要用鏈表很多人疑惑,實(shí)現(xiàn)HashMap直接用數(shù)組不就可以了嗎,通過(guò)hash函數(shù)計(jì)算出key對(duì)應(yīng)的數(shù)組的下標(biāo),value直接存進(jìn)去。為什么會(huì)用鏈表呢?
問(wèn)題的關(guān)鍵就出在hash函數(shù)身上,因?yàn)榈浆F(xiàn)在為止還沒(méi)有出現(xiàn)一種一個(gè)不同的key對(duì)應(yīng)的hash值都不一樣的函數(shù),(包括MD5,SHA等算法),假如a,b兩個(gè)key通過(guò)hash函數(shù)得到的數(shù)組下標(biāo)都是1,a已經(jīng)存進(jìn)數(shù)組下標(biāo)為1的位置,b該怎么存儲(chǔ)呢?把a(bǔ)對(duì)應(yīng)的value刪了,替換成b對(duì)應(yīng)的value?這種作法顯然是不可取的。所以在HashMap中引入了鏈表,還是a,b兩個(gè)key,存儲(chǔ)a的時(shí)候,我們先判斷下數(shù)組下標(biāo)為1的位置是否有數(shù)據(jù),如果沒(méi)有直接插入數(shù)組中,這時(shí)候a對(duì)應(yīng)的value插入到了數(shù)組中,這時(shí)候我們來(lái)存儲(chǔ)b,我們發(fā)現(xiàn)下標(biāo)為1的位置已經(jīng)存了數(shù)據(jù),我們用a.next來(lái)指向b,形成一個(gè)鏈表。以此類(lèi)推。
public V put(K key, V value) { //hash()散列函數(shù),主要作用通過(guò)一系列計(jì)算,得出應(yīng)存在數(shù)組的下標(biāo) 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) //擴(kuò)容數(shù)據(jù)搬遷 n = (tab = resize()).length; //查看對(duì)應(yīng)下標(biāo)是否有數(shù)據(jù),沒(méi)有數(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; //進(jìn)化成紅黑樹(shù)之后 else if (p instanceof TreeNode) e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { //判斷是不是鏈表最后一個(gè)節(jié)點(diǎn) if ((e = p.next) == null) { //發(fā)現(xiàn)是最后一個(gè)節(jié)點(diǎn)的話(huà),添加在隊(duì)尾 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 總結(jié)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ù)組中對(duì)應(yīng)下標(biāo)數(shù)據(jù) //key相同 hash相同 數(shù)組中的對(duì)象就是我們要找的 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相同的對(duì)象 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }
HashMap通過(guò)數(shù)組加鏈表的方式,實(shí)現(xiàn)了時(shí)間復(fù)雜度為O(1)的快速插入,查詢(xún)等操作,在平時(shí)使用中我們還可以通過(guò)指定數(shù)組大小來(lái)進(jìn)一步加快它的性能。
文章中只是寫(xiě)了大概的思路,有不對(duì)的還請(qǐng)見(jiàn)諒!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/72544.html
摘要:任務(wù)名稱(chēng)響應(yīng)式砸蛋頁(yè)面任務(wù)背景前輩方方啊最近項(xiàng)目也沒(méi)什么事情你看這個(gè)砸蛋頁(yè)面不是很好看要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧系統(tǒng)鄭方方接下前輩的任務(wù)鄭方方自動(dòng)解析任務(wù)步驟任務(wù)響應(yīng)式砸蛋頁(yè)面與入門(mén)閱讀秘籍響應(yīng)式布局制作層搭配搭配控制器完成任務(wù)人物背 任務(wù)名稱(chēng):響應(yīng)式砸蛋頁(yè)面 任務(wù)背景 前輩:方方啊,最近項(xiàng)目也沒(méi)什么事情,你看這個(gè)砸蛋頁(yè)面不是很好看,要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧? 系統(tǒng):鄭方方接下前...
摘要:任務(wù)名稱(chēng)響應(yīng)式砸蛋頁(yè)面任務(wù)背景前輩方方啊最近項(xiàng)目也沒(méi)什么事情你看這個(gè)砸蛋頁(yè)面不是很好看要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧系統(tǒng)鄭方方接下前輩的任務(wù)鄭方方自動(dòng)解析任務(wù)步驟任務(wù)響應(yīng)式砸蛋頁(yè)面與入門(mén)閱讀秘籍響應(yīng)式布局制作層搭配搭配控制器完成任務(wù)人物背 任務(wù)名稱(chēng):響應(yīng)式砸蛋頁(yè)面 任務(wù)背景 前輩:方方啊,最近項(xiàng)目也沒(méi)什么事情,你看這個(gè)砸蛋頁(yè)面不是很好看,要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧? 系統(tǒng):鄭方方接下前...
摘要:任務(wù)名稱(chēng)響應(yīng)式砸蛋頁(yè)面任務(wù)背景前輩方方啊最近項(xiàng)目也沒(méi)什么事情你看這個(gè)砸蛋頁(yè)面不是很好看要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧系統(tǒng)鄭方方接下前輩的任務(wù)鄭方方自動(dòng)解析任務(wù)步驟任務(wù)響應(yīng)式砸蛋頁(yè)面與入門(mén)閱讀秘籍響應(yīng)式布局制作層搭配搭配控制器完成任務(wù)人物背 任務(wù)名稱(chēng):響應(yīng)式砸蛋頁(yè)面 任務(wù)背景 前輩:方方啊,最近項(xiàng)目也沒(méi)什么事情,你看這個(gè)砸蛋頁(yè)面不是很好看,要不你做一個(gè)響應(yīng)式砸蛋頁(yè)面吧? 系統(tǒng):鄭方方接下前...
閱讀 676·2021-11-24 09:39
閱讀 2343·2021-11-22 13:54
閱讀 2211·2021-09-23 11:46
閱讀 3257·2019-08-30 15:55
閱讀 2692·2019-08-30 15:54
閱讀 2419·2019-08-30 14:18
閱讀 1557·2019-08-29 14:15
閱讀 2745·2019-08-29 13:49