HshMap 資料結構以及原始碼分析

2021-08-21 01:23:59 字數 3364 閱讀 5972

最近整理資料結構方面的知識點,hashmap是很重要的一部分,今天來聯合原始碼分析他的資料結構以及儲存方式!

接下來將從以下幾個方面來分析(根據jdk1.8)

1. 構造方法

2. 重要的幾個資料解釋

3. put

4. get

// 儲存資料的陣列 table

transient node table;

// 儲存資料的基本型別

static

class

node

implements

map.entry

getter setter

總共有四個構造方法

// initialcapacity:指定map的容量大小

// loadfactor: 指定載入因子, 預設是default_load_factor 0.75

public

hashmap(int initialcapacity, float loadfactor)

public

hashmap(int initialcapacity)

// 預設構造方法

public

hashmap()

// 包含「子map」的建構函式

public

hashmap(map extends k, ? extends v> m)

// 預設的載入因子

static

final

float default_load_factor = 0.75f;

首先來說明下hashmap的資料結構 (圖是從別的地方借用的)

在hashmap 進行儲存資料時,我覺得可以從三點來判斷 :

1 . 如何判定key的唯一性

2. 如何通過key計算hash值,並且可以通過hash值計算得到應該放置的陣列的位置

3. 什麼時候擴容

public v put(k key, v value) 

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;} }

// 對於找到的相同的key的node,進行value覆蓋

v oldvalue = e.value;

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

return oldvalue;}}

// map 被修改的次數+1

++modcount;

// 如果長度達到臨界值,進行擴容

if (++size > threshold)

resize();

afternodeinsertion(evict);

return

null;

}static final int hash(object key)

通過上面的**注釋,應該對hashmap的儲存方式有更進一步的認識。整個過程就是我們拿到node的hash值,來計算應該放置的位置,不管value值是null或者和已經存在的值是否重複,只要找到位置後,放置進去,就ok。

final node resize()  else

if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)

newthr = oldthr << 1; // double threshold

} else

if (oldthr > 0) // initial capacity was placed in threshold

newcap = oldthr;

else

if (newthr == 0)

threshold = newthr;

@suppresswarnings()

node newtab = (node) new node[newcap];

table = newtab;

if (oldtab != null) else

} while ((e = next) != null);

if (lotail != null)

if (hitail != null) }}

}}return newtab;

}

resize方法:無非就是重新申請空間,如果一開始是0,就採用和構造方法一樣的設定,預設初始大小16;如果之前有資料就成倍增加,並計算新的臨界值,重新通過hash值計算在陣列中的位置,把之前的資料拷貝到新申請的陣列上;陣列的擴容是非常耗費效能的,如果我們能提前預算出陣列的大小,我們在初始化時可以直接進行指定;

首先我們來看源**,讀取資料相對儲存資料簡單寫,我們只需要通過key,判斷key的合法性以及通過計算hash 定為元素在陣列的位置即可。

public v get(object key) 

final nodegetnode(int hash, object key) while ((e = e.next) != null);}}

return

null;

}

經過上面的分析,我們知道hashmap主要通過陣列+鍊錶的形式儲存資料,當儲存的資料過多的時候,鍊錶越來越重,之後我們查詢起來時間也越來越長,效率越來越低,

我們可以看到其中(e instanceof treenode)判斷節點是否是treenode,jdk1.8中,hashmap採用陣列+鍊錶+紅黑樹來實現,當鍊表長度超過閾值(8)時,將鍊錶轉換為紅黑樹,這樣大大減少了查詢時間。

static

final

class

treenode

extends

linkedhashmap.linkedhashmapentry

...}

和hashmap相似的hashset其實就是變形的hashmap,我們可參考這篇文章hashset簡單看下 他們的區別。

參考資料:

資料結構原始碼 迷宮

include include include include include define stack init size 1000 define stack more 10 define overflow 2 define ok 1 define error 0 define true 1 de...

java 資料結構 原始碼閱讀

collections工具類裡的 collections.synchronizedlist public static listsynchronizedlist listlist 僅僅是通過判斷是否實現randomaccess介面,而返回不同的synchronizedlist 內部 類,random...

資料結構課後題目原始碼

習題描述如下 假設以陣列q m 存放迴圈佇列中的元素,同時設定乙個標誌tag,以tag 0和tag 1來區別在隊頭指標 front 和隊尾指標 rear 相等時,佇列狀態為 空 還是為 滿 試編寫與此結構相應的插入 enqueue 和刪除 dequeue 演算法。以下是博主自己碼的 不喜勿噴!ifn...