從HashMap看紅黑樹

2021-10-08 22:43:05 字數 3218 閱讀 2572

樹上的節點要麼是紅色,要麼是黑色

根節點是黑色

每個葉子節點都是黑色的(所有的葉子節點都是null節點)

紅色節點的子節點都是黑色的

任意乙個節點到其子孫葉子節點的黑色節點的數量是相等的。

下面是乙個紅黑樹的圖示:

從任意節點(不含該節點)到達乙個葉節點的任意一條簡單路徑上的黑色節點個數稱為該節點的黑高(block-height),計為bh(x)。根節點的黑高為樹的黑高。紅黑樹的樹高h(x)與黑高bh(x)的關係是bh(x) >= h(x)/2 

引理:一顆有n個內部節點的紅黑樹的高度至多為2lg(n+1)。(tip:這裡的lg和下面的lg都是以2為底數的)。

紅黑樹的插入刪除操作通過旋轉和變色可以將時間複雜度控制在o(lgn)。

插入乙個紅色節點後,有時只通過變色操作就可以保持紅黑樹的平衡。下面對這種情況進行說明:

當插入的節點x的父節點xp是紅色並且x的叔叔節點xppr也是紅色的時候,需要將xp和xppr節點變為黑色,將xp的父節點xpp變為紅色即可。如圖:(xpp並不一定是根節點)

下面看一下hashmap中的**:

static treenodebalanceinsertion(treenoderoot,

treenodex)

// 若xp為黑色或者xpp為空,則不需要調整,直接返回根節點

else if (!xp.red || (xpp = xp.parent) == null)

return root;

// 若不滿足上面情況說明:xp為紅色而且xpp不為空

// 若xp為xpp的做孩子節點時,說明x插在了xpp的左子樹上

// 也就是說x有右叔叔節點

if (xp == (xppl = xpp.left))

// 若右叔叔節點為黑色(為空也是為黑色)

else

// 此時x已經是插入到xp的左邊了

// 若xp節點不為空

if (xp != null) }}

}// 否則x有左舒舒節點時

else

// 當左叔叔節點為黑色時(為空也是為黑色)

else

// 此時x已經是插入到xp的右節點了

if (xp != null) }}}}}

**中26行到33行是處理上面說的這種情況。通過上下文可知當程式走到26行時說明插入節點x的父節點和叔叔節點都為紅色。然後執行下面的操作:

// 若右叔叔節點不為空 而且 為紅色

if ((xppr = xpp.right) != null && xppr.red)

可以看到將xppr,xp變為黑色,xpp變為紅色。然後將xpp作為x回到迴圈開始位置繼續做樹的平衡操作。 

上圖只列舉了x插入左子樹的情況,其實x插入右子樹是一樣的,這裡不再贅述。

當插入節點x的父節點xp為紅色並且x的叔叔節點xppr(或xppl)為黑色時(叔叔節點為空也是黑色節點),只通過變色是無法滿足平衡條件的。這時就需要旋轉了。旋轉分為左旋和右旋。不管是左旋還是右旋都是有公式的,只要記住公式就可以了。

當節點x與父節點xp與祖父節xpp點在同一條線上時,將xp變為黑色、xpp變為紅色然後在以xp為圓心向傾斜的那一方旋轉,比如:

下面結合**看看hashmap中是如何操作的(節選自上面**的一部分34行-59行):

// 若右叔叔節點為黑色(為空也是為黑色)

else

// 此時x已經是插入到xp的左邊了

// 若xp節點不為空

if (xp != null) }}

下面看一下左旋rotateleft()方法的**:

// 左旋方法

//對p進行左旋操作時,必須滿足p不能為而且p的右子節點不能為空,然後進行如下操作:

//1、定義pp = p.parent; r = p.right; rl = r.left;

//2、將r的左子樹作為p的右子樹,若rl不為空則將p作為rl的父節點

//3、將pp作為r的父節點。當pp不為空時且p為pp的左子節點,

// 則將r變為pp的左子節點,否則將r變為pp的右子節點。若pp為空則將r變為根節點

//4、將p作為r的左子樹

//5、將r作為p的父節點

static treenoderotateleft(treenoderoot,

treenodep)

return root;

}

在看右旋rotateright()方法的**:

// 右旋方法

//對p進行右旋操作時,必須滿足p不能為而且p的左子節點不能為空,然後進行如下操作:

//1、定義pp = p.parent; l = p.left; lr = l.right;

//2、將l的右子樹作為p的左子樹,若lr不為空則將p作為lr的父節點

//3、將pp作為l的父節點。當pp不為空時且p為pp的左子節點,

// 則將l變為pp的左子節點,否則將l變為pp的右子節點。若pp為空則將l變為根節點

//4、將p作為l的右子樹

//5、將l作為p的父節點

static treenoderotateright(treenoderoot,

treenodep)

return root;

}

紅黑樹的插入是比較簡單的情況比較少,一般來說預設新插入的節點為紅色。因為從第5條定義可知紅黑樹的每條簡單路徑的黑高是相等的,若插入的節點預設是黑色的話那麼必定會引起新插入的節點的分支的黑色節點比其他的分支的黑色節點多,從而必定會進行紅黑樹的自平衡(變色和旋轉)操作。而若預設插入的節點是紅色的話,只有當父節點為紅色時才會進行自平衡操作,為了減少演算法要處理的情況,預設插入的節點為紅色。

HashMap總結(不包括紅黑樹)

hashmap是用來存放key value的容器,底層是使用陣列 鍊錶 紅黑樹 實現的 節點少時 預設是untreeify threshold 6值 用鍊錶,多時 預設是 treeify threshold 8 用紅黑樹,樹化容量為min treeify capacity,預設是64。成員變數 構造...

紅黑樹 一看就會

red black tree是自平衡 非絕對平衡 的二叉查詢樹 先嘗試recolor,置色紅黑 再嘗試rotation 旋轉 插入新節點,標紅,如果為根節點,則標黑 如果不是根節點,且其parent是紅,uncle是紅 插入新節點,標紅,如果為根節點,則標黑 如果不是根節點,且其parent是紅,u...

教你了解紅黑樹(HashMap 1 8)

若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值 若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值 任意節點的左 右子樹也分別為二叉查詢樹。沒有鍵值相等的節點 no duplicate nodes 每個結點要麼是紅的要麼是黑的。根結點是黑的。每個葉結點 葉結點即指...