《資料結構與演算法》之紅黑樹

2021-09-02 22:13:31 字數 3748 閱讀 3886

二叉查詢樹對於某個節點而言,其左子樹的節點關鍵值都小於該節點關鍵值,右子樹的所有節點關鍵值都大於該節點關鍵值。二叉查詢樹作為一種資料結構,其查詢、插入和刪除操作的時間複雜度都為 o(logn) ,底數為 2。但是我們說這個時間複雜度是在平衡的二叉查詢樹上體現的,也就是如果插入的資料是隨機的,則效率很高,但是如果插入的資料是有序的,這種情況下查詢的時間複雜度為 o(n),而不是 o(logn) 。當然這是在最不平衡的條件下,實際上,二叉查詢樹的效率應該在 o(n) 和 o(logn) 之間,這取決於樹的不平衡程度。

那麼為了能夠以較快的時間 o(logn) 來搜尋一棵樹,我們需要保證樹總是平衡的(或者大部分是平衡的),也就是說每個節點的左子樹節點個數和右子樹節點個數盡量相等。紅黑樹就是這樣的一棵平衡樹,對乙個要插入的資料項(刪除也是),插入例程要檢查會不會破壞樹的特徵,如果破壞了,程式就會進行糾正,根據需要改變樹的結構,從而保持樹的平衡。紅黑樹是一種自平衡二叉查詢樹,是在電腦科學中用到的一種資料結構,典型的用途是實現關聯陣列。

1、紅黑樹的特徵

①、節點都有顏色;

②、在插入和刪除的過程中,要遵循保持這些顏色的不同排列規則。

第①點很好理解,在紅黑樹中,每個節點的顏色或者是黑色或者是紅色的。當然也可以是任意別的兩種顏色,這裡的顏色用於標記,我們可以在節點類node中增加乙個boolean型變數,以此來表示顏色的資訊。

第②點,在插入或者刪除乙個節點時,必須要遵守的規則稱為紅黑規則:

(1)每個節點不是紅色就是黑色的;

(2)根節點總是黑色的;

(3)如果節點是紅色的,則它的子節點必須是黑色的(反之不一定),也就是從每個葉子到根的所有路徑上不能有兩個連續的紅色節點;

(4)從根節點到葉節點或空子節點的每條路徑,必須包含相同數目的黑色節點(即相同的黑色高度)。

從根節點到葉節點的路徑上的黑色節點的數目稱為黑色高度,規則 4 另一種表示就是從根到葉節點路徑上的黑色高度必須相同。

注意:新插入的節點顏色總是紅色的,這是因為插入乙個紅色節點比插入乙個黑色節點違背紅黑規則的可能性更小,原因是插入黑色節點總會改變黑色高度(違背規則4),但是插入紅色節點只有一半的機會會違背規則3(因為父節點是黑色的沒事,父節點是紅色的就違背規則3)。另外違背規則3比違背規則4要更容易修正。

2、紅黑樹的自我修正

(1)節點顏色轉換

新插入的節點顏色都為紅色,直接插入會違反規則3,改為黑色卻發現違反規則4。這時候我們將其父節點顏色改為黑色,父節點的兄弟節點顏色也改為黑色。通常祖父節點顏色會由黑色變為紅色。注意:當節點為根節點時,始終為黑色。這項操作最重要的性質在於它是區域性變換,不會影響整棵樹的黑色平衡性。

(2)左旋轉

首先要說明的是節點本身是不會旋轉的,旋轉改變的是節點之間的關係,選擇乙個節點作為旋轉的頂端,如果做一次左旋,這個頂端節點會向下和向左移動到它左子節點的位置,它的右子節點會上移到它原來的位置。左旋的頂端節點必須要有右子節點。

(3)右旋轉

首先要說明的是節點本身是不會旋轉的,旋轉改變的是節點之間的關係,選擇乙個節點作為旋轉的頂端,如果做一次右旋,這個頂端節點會向下和向右移動到它右子節點的位置,它的左子節點會上移到它原來的位置。右旋的頂端節點必須要有左子節點。

3、紅黑樹的實現

3.1 紅黑樹的節點

public class rbnode> 

public t getkey()

public string tostring()

}

3.2 紅黑樹左旋的實現

/************* 對紅黑樹節點x進行左旋操作 ******************/

/* * 左旋示意圖:對節點x進行左旋

* 左旋做了三件事:

* 1. 將y的左子節點賦給x的右子節點,並將x賦給y左子節點的父節點(y左子節點非空時)

* 2.將x的父節點p(非空時)賦給y的父節點,同時更新p的子節點為y(左或右)

* 3. 將y的左子節點設為x,將x的父節點設為y

*/private void leftrotate(rbnodex) else

// 3. 將y的左子節點設為x,將x的父節點設為y

y.left = x;

x.parent = y;

}

3.3 紅黑樹右旋的實現

/************* 對紅黑樹節點y進行右旋操作 ******************/

/* * 左旋示意圖:對節點y進行右旋

* 右旋做了三件事:

* 1. 將x的右子節點賦給y的左子節點,並將y賦給x右子節點的父節點(x右子節點非空時)

* 2. 將y的父節點p(非空時)賦給x的父節點,同時更新p的子節點為x(左或右)

* 3. 將x的右子節點設為y,將y的父節點設為x

*/private void rightrotate(rbnodey) else

// 3. 將y的左子節點設為x,將x的父節點設為y

x.right = y;

y.parent = x;

}

3.4 插入新的節點

/*********************** 向紅黑樹中插入新的節點 **********************/

public void insert(t key)

// 將節點插入到紅黑樹中,這個過程與二叉搜尋樹是一樣的

private void insert(rbnodenode)

node.parent = current; // 找到了位置,將當前current作為node的父節點

// 2. 接下來判斷node是插在左子節點還是右子節點

if (current != null) else

// 3. 將它重新修整為一顆紅黑樹

insertfixup(node);

}

在插入過程中,只要謹慎的使用左旋轉、右旋轉和顏色轉換這三種簡單的操作,就能夠保證插入操作後紅黑樹和2-3樹的一一對應關係。在沿著插入點到根節點的路徑向上移動時在所經過的每個節點中順序完成以下操作,就可以完成插入操作了。

private void insertfixup(rbnodenode) 

// case2: 叔叔節點是黑色,且當前節點是右子節點

if (node == parent.right)

// case3: 叔叔節點是黑色,且當前節點是左子節點

setblack(parent);

setred(gparent);

rightrotate(gparent);

} else

// case2: 叔叔節點是黑色的,且當前節點是左子節點

if (node == parent.left)

// case3: 叔叔節點是黑色的,且當前節點是右子節點

setblack(parent);

setred(gparent);

leftrotate(gparent);

}} // 將根節點設定為黑色

setblack(this.root);

}

參考:

資料結構與演算法 十三 之紅黑樹

節點的刪除 紅黑樹是一種特殊的二叉搜尋樹 紅黑樹的性質 節點是紅色或黑色。根節點是黑色。每個葉子節點都是黑色的空節點 nil節點 從每個葉子到根的所有路徑上不能有兩個連續的紅色節點。從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。1 紅黑樹放棄了追求完全平衡,追求大致平衡,在與平衡二叉樹的...

資料結構之紅黑樹

定義 紅黑樹是一顆二叉查詢樹,樹中結點顏色或為紅色或為黑色,且滿足如下條件 根結點和所有外結點的顏色為黑色 根結點到任意乙個外結點的路徑上沒有連續的兩個紅色結點,若乙個結點是紅色,則其兩個兒子結點都是黑色 根結點到任意外結點的路徑上都有相同數目的黑色結點。1 插入操作 插入操作可以概括為以下幾個步驟...

資料結構查詢演算法之紅黑樹

紅黑樹對於結點的顏色設定不是任意的,需滿足以下性質的二叉查詢樹才是紅黑樹 紅黑樹中每個結點都有各自的黑高度,整棵樹也有自己的黑高度,即為根結點的黑高度,例如圖 1 中的紅黑樹的黑高度為 3。對於一棵具有 n 個結點的紅黑樹,樹的高度至多為 2lg n 1 所以紅黑樹的時間複雜度為o logn 紅黑樹...