TreeMap原始碼分析

2021-10-07 10:47:27 字數 3456 閱讀 5339

treemap是基於紅黑樹結構實現的一種map。紅黑樹是一種自平衡二叉查詢樹。

二叉查詢樹

若左子樹不為空,則左子樹上所有節點的值均小於它的根節點的值;

若右子樹不為空,則右子樹上所有節點的值均大於它的根節點的值;

左、右子樹也分別為二叉查詢樹;

沒有鍵值相等的節點。

treemap 利用了紅黑樹左節點小,右節點大的性質,根據 key 進行排序,使每個元素能夠插入到紅黑樹大小適當的位置,維護了 key 的大小關係,適用於 key 需要排序的場景。因為底層使用的是紅黑樹的結構(平衡樹),所以 containskey、get、put、remove 等方法的時間 複雜度都是 log(n)。

一、原始碼中常見屬性

//自帶的比較器,如果外部有傳進來比較器,優先用外部的

private

final comparator<

?super k> comparator;

//紅黑樹的根

private

transient entry

root;

//集合元素數量

private

transient

int size =0;

//版本號修改次數

private

transient

int modcount =0;

//紅黑樹的節點

static

final

class

entry

implements

map.entry

二、新增節點

判斷紅黑樹的根節點是不是空的,是空的則要建立根節點,並且key不能為null。

根據紅黑樹左小右大的特性,找到新增節點的父節點(這邊要判斷有沒有外部比較器),如果已經存在,就是值相等,就直接覆蓋。

找到父節點之後就是插入,相等的情況就在第二步中處理。

對紅黑樹進行著色旋轉,達到平衡。

public v put

(k key, v value)

// 記錄比較結果

int cmp;

entry

parent;

comparator<

?super k> cpr = comparator;

//如果比較器不為空,就是用指定的比較器來維護treemap的元素順序

if(cpr != null)

while

(t != null)

;// t 為空,說明已經到葉子節點了

}else

while

(t != null);}

// 找到新節點的父節點後,建立節點物件

entry

e =newentry

<

>

(key, value, parent)

;// 如果新節點key的值小於父節點key的值,則插在父節點的左側

if(cmp <0)

parent.left = e;

// 如果新節點key的值大於父節點key的值,則插在父節點的右側

else

parent.right = e;

// 插入新的節點後,為了保持紅黑樹平衡,對紅黑樹進行調整

fixafterinsertion

(e);

size++

; modcount++

;return null;

}

三、紅黑樹的刪除原理及treemap的remove實現

相比新增,紅黑樹的刪除顯得更加複雜了。看下紅黑樹的刪除需要哪幾個步奏:

將紅黑樹當成一顆二叉查詢樹,將節點刪除。

通過旋轉和著色,使它恢復平衡,重新變成一顆符合規則的紅黑樹。

刪除節點的關鍵是:

如果刪除的是紅色節點,不會違背紅黑樹的規則。

如果刪除的是黑色節點,那麼這個路徑上就少了乙個黑色節點,則違背了紅黑樹的規則。

來看下紅黑樹刪除節點會有哪幾種情況:

被刪除的節點沒有孩子節點,即葉子節點。可直接刪除。

被刪除的節點只有乙個孩子節點,那麼直接刪除該節點,然後用它的孩子節點頂替它的位置。

被刪除的節點有兩個孩子節點。這種情況二叉樹的刪除有乙個技巧,就是查詢到要刪除的節點x,接著我們找到它左子樹的最大元素m,或者它右子樹的最小元素m,交換x和m的值,然後刪除節點m。

我們得到的結論是紅黑樹的刪除遇到的主要問題就是被刪除路徑上的黑色節點減少,於是需要進行一系列旋轉和著色。

treemap的查詢與hashmap類似。

四、hashmap,linkedhashmap、hashtable和treemap的區別

map主要用於儲存健值對,根據鍵得到值,因此不允許鍵重複(重複會覆蓋),但允許值重複。

1. hashmap

hashmap是乙個最常用的map,它根據鍵的hashcode值儲存資料,根據鍵可以直接獲取它的值,具有很快的訪問速度。遍歷時,取得資料的順序是完全隨機的;

hashmap最多隻允許一條記錄的鍵為null;允許多條記錄的值為null;

hashmap不支援執行緒的同步(非執行緒安全),即任一時刻可以有多個執行緒同時寫hashmap,可能會導致資料的不一致;

同步,可以用collections的synchronizedmap方法hashmap具有同步的能力,或者使用concurrenthashmap。

在map中插入、刪除和定位元素,hashmap是最好的選擇。

abstractmap抽象類,(hashmap繼承abstractmap)覆蓋了equals()和hashcode()方法以確保兩個相等對映返回相同的雜湊碼。如果兩個對映大小相等、包含同樣的鍵且每個鍵在這兩個對映中對應的值都相同,則這兩個對映相等

2. hashtable

hashtable與hashmap類似,它不允許記錄的鍵或者值為空;

支援執行緒的同步(執行緒安全),即任一時刻只有乙個執行緒能寫hashtable,因此導致了hashtable在寫入時會比較慢。

3. linkedhashmap

linkedhashmap是hashmap的乙個子類;

linkedhashmap儲存了記錄的插入順序,在用iterator遍歷linkedhashmap時,先得到的記錄肯定是先插入的;

4. treemap

treemap實現sortmap介面,能夠把它儲存的記錄根據鍵排序,預設是按鍵值的公升序排序,也可以指定排序的比較器。

treemap取出來的是排序後的鍵值對。但如果您要按自然順序或自定義順序遍歷鍵,那麼treemap會更好。

treemap基於紅黑樹實現,是非執行緒安全

TreeMap 原始碼分析

treemap底層是使用紅黑樹實現的儲存鍵值對的map容器,可以通過比較器進行排序。紅黑樹本質上是一棵弱平衡二叉樹,它的節點有紅色和黑色兩種顏色。主要特性有五點。1 每個節點或者是黑色,或者是紅色。2 根節點是黑色。3 每個葉子節點 nil 是黑色。注意 這裡葉子節點,是指為空 nil或null 的...

TreeMap原始碼分析

public v put k key,v value int cmp entryparent split comparator and comparable paths comparator cpr comparator if cpr null while t null else while t n...

TreeMap原始碼分析

基於紅黑樹的實現,根據key的自然順序排序,或者根據構造方法傳入的排序方式。構造方法傳入的比較器 藉此維護鍵的順序 private final comparator super k comparator private transient entry root 根節點 private transie...