這是我參與8月更文挑戰的第13天,活動詳情查看:8月更文挑戰html
紅黑樹是一棵二叉搜索樹,其在每一個結點上增長了一個存儲位用於表示顏色。經過對根到葉子的每條路徑上的顏色的管理,實現了近似平衡(紅黑樹確保一條路徑不會比另一條路徑高出兩倍),其能夠保證在最壞條件下動態集合操做的時間複雜度爲 .markdown
先簡單介紹下二叉搜索樹:二叉搜索樹可使用一個鏈表來進行表示,其中每一個結點就是一個對象。除了key等一些數據外,其還包括屬性left、right、和p,分別指向左子結點、右子結點和雙親。若是不存在則指向NIL。數據結構
二叉搜索樹知足對於其任意結點X,左子樹的關鍵字最大不能超過X.key而右子樹不能小於X.key,大部分搜索樹操做的最壞時間都和樹高成正比。app
介紹完二叉搜索樹,接下來咱們來介紹下紅黑樹知足的幾個性質:post
根據性質4咱們能夠獲得,從根到葉節點的簡單路徑上,至少有一半的結點爲黑結點。spa
紅黑樹不是完美平衡的二叉查找樹,可是其任意一個結點到每一個葉子結點的路徑都包含相同數量的黑色結點。因此咱們叫紅黑樹的這種平衡爲黑色完美平衡。指針
紅黑樹爲了保持平衡有三種操做:code
左旋:以某個結點做爲支點(旋轉結點),其右子結點變爲旋轉結點的父節點.右子結點的左子結點變成旋轉結點的右子結點,左子結點保持不變。orm
右旋:以某個結點做爲支點(旋轉結點),其左子結點變爲旋轉結點的父節點.左子結點的右子結點變成旋轉結點的左子結點,右子結點保持不變。xml
變色:結點顏色由紅色變成黑色或者由黑色變成紅色
紅黑樹就是經過旋轉和變色實現自平衡的。
從下圖中能夠發現,以11結點爲旋轉結點,其右子結點18變成父結點,而後結點18的左子結點14變成11結點的右子結點。
紅黑樹就是一棵二叉搜索樹,因此其查找結點的方式和普通二叉搜索樹同樣,可是由於紅黑樹平衡性比較好,因此它查找的最壞時間複雜度爲 。
紅黑樹的插入時間複雜度爲 ,紅黑樹的插入和二叉搜索樹的插入相似,不過紅黑樹會判斷相應結點顏色,並給該結點上色。下面上一段僞代碼:
RB-INSERT(T,z) // T爲紅黑樹、z爲要插入的結點
// y設爲nil結點
y = T.nil
// x設爲根節點
x = T.root
while x != T.nil // x不爲空
y = x
if z.key< x.key // 插入的結點比該樹小
x = x.left
else
x = x.right
z.p = y // 設置插入結點的父結點爲 y
if y == T.nil // 該樹爲空
T.root = z
else if z.key < y.key
y.left = z
else
y.right = z
// 將插入的結點的左右子結點設爲nil
z.left = T.nil
z.right = T.nil
z.color = RED
RB-INSERT-FIXUP(T,z) // 調整着色
複製代碼
while z.p.color == RED
if z.p == z.p.p.left // 判斷父結點是不是祖父結點的左結點
y = z.p.p.right // y設爲祖父結點的右節點
if y.color = RED // 判斷y的顏色
z.p.color = BLACK // 將z的父結點的顏色設爲黑色 (狀況1)
y.color = BLACK // 將z的叔父結點的顏色設爲黑色 (狀況1)
z.p.p.color = RED // 將z的祖父結點的顏色設爲紅色 (狀況1)
z = z.p.p // 將z結點設爲其祖父結點 (狀況1)
else if z == z.p.right // 若是z結點是父結點的右子結點
z = z.p // 將z結點設爲z的父結點 (狀況2)
// 對結點進行左旋
LETF-ROTATE(T,z) (狀況2)
z.p.color = BLACK // 將z的父結點顏色設爲黑色 (狀況3)
z.p.p.color = RED // 將z的祖父結點的顏色設爲紅色 (狀況3)
// 對結點進行右旋
RIGHT-ROTATE(T,z.p.p) (狀況3)
else // 與上面的狀況相似
y = z.p.p.left
if y.color = RED
z.p.color = BLACK
y.color = BLACK
z.p.p.color = RED
z = z.p.p
else if z == z.p.left
z = z.p
// 對結點進行左旋
RIGHT-ROTATE(T,z)
z.p.color = BLACK
z.p.p.color = RED
// 對結點進行右旋
LEFT-ROTATE(T,z.p.p)
T.root.color = BLACK
複製代碼
具體左旋和右旋的代碼在這我就不貼出了,若是想了解本身能夠去網上了解一下。
以下圖:具體能夠對照代碼進行了解,開始先是判斷該結點的父結以及叔父結點的顏色,進行判斷插入結點的顏色是否知足,不知足則進行調整,調整完顏色再進行相應的左旋和右旋。
雖然紅黑樹的刪除比插入還要複雜一點,可是爲了節省篇幅就再也不貼代碼了。紅黑樹的刪除操做須要的時間複雜度也是 。
具體步驟就不詳細展開了,以後再寫一篇關於紅黑樹刪除的文章特意進行分析。
第一篇:數據結構-堆
該篇是我記錄的數據結構篇的第二篇,因爲本人技術水平有限,可能寫的沒有那麼準確,若有什麼問題,但願你們可以幫我指出,萬分感謝!