紅黑樹原理詳解及golang實現
目錄
- 紅黑樹原理詳解及golang實現
- 二叉查詢樹
- 性質
- 紅黑樹
- 性質
- operation
- 紅黑樹的插入
- golang實現
- 型別定義
- leftRotate
- RightRotate
- Item Interface
- insert
- 完整程式碼
- 小結
- 二叉查詢樹
紅黑樹原理詳解及golang實現
在看紅黑樹原理之前,先看下二叉查詢樹。
二叉查詢樹
二叉查詢樹,又稱二叉排序樹,二叉搜尋樹。
性質
它具備一下性質:
1、左子樹上的所有節點均小於它的根節點值。
2、右子樹上的所有節點的值均大於等於它根節點的值。
3、左佑子樹也分別二叉排序樹。
4、沒有鍵值相等的節點。
既然叫搜尋樹,那這種結構的好處當然也就是搜尋咯,
假如我們要查詢15
1、從root節點開始,15<50,找左子樹。
2、15<20,找左子樹,
3、15>10,找右子樹,這樣便找到15了。
插入也是類似方法,一層一層比較大小,找到合適的位置插入。
時間複雜度
看見它查詢的次數等同於樹的高度,在最好的情況下,其平均查詢次數和log 2 (n)成正比。
例如依序插入 : 100、200、90、80、70、60、50、40
就會成為如下圖形態:
為了解決這種不平衡的情形,就有了紅黑樹。
紅黑樹
性質
紅黑樹是一種自平衡的二叉搜尋樹,它包含了二叉搜尋樹的特性,同時具備以下性質:
1、所有節點的顏色不是紅色就是黑色。
2、根節點是黑絲。
3、每個葉子節點都是黑色的空節點(nil)。
4、每個紅色節點的兩個子節點都是黑色。(從每個葉子到根節點的所有路徑上不能有兩個連續的紅色節點)
5、從任一節點到其葉子節點的所有路徑上都包含相同數目的黑節點。
前四都能理解其意思吧,所以只解釋下第五點,比如60這個節點,到其所有葉子節點的路徑都只包含1個黑色節點:40和90。
operation
紅黑樹為了維持它的這5點性質,於是它支援了這麼幾個操作 ,
變色
: 顧名思義變色,紅變黑,黑變紅。
左旋轉
: 這裡借用百度百科兩張旋轉圖,以圖中紅色節點為中心,中心節點為右孩子替代,而自己成為它的左孩子,同時節點b作為pivot的有孩子(至於為什麼是右孩子,b原本就在pivot的右子樹上,所以肯定大於pivot)。
右選裝
: 同左旋轉,中心點順時鐘旋轉,成為其原來左孩子的右孩子,原來左孩子的右孩子則成為原中心點的左孩子。
接著看看紅黑樹的插入,看看它是如何通過這幾個op維持紅黑樹這5個性質的。
紅黑樹的插入
關於插入的特點 : 由於性質5的約束,每次插入的節點顏色必然為紅色。
插入的化存在幾種情形,複雜的樹可能會涉及到迴圈的向樹上檢索做自平衡,這裡先從一顆空樹開始先簡單理解下這些情形。
情形1
:空樹
直接插入,直接作為根節點,同時由於性質1的約束,通過變色op變為黑色即可。
情形2
:插入節點父節為黑色,
不違反任何性質,無需做任何修改。
情形3
插入節點的父節點為紅色,父節點為父父節點的左孩子,父父節點的右孩子為黑色,插入節點為左孩子(或者父節點為父父節點的右孩子,父父節點的左孩子為黑色,插入節點為右孩子)。
這是一種插入節點和父節點在一個方向上的情況(例如父節點為左孩子,插入節點也為左孩子)和情形5相反
父節點 及 父父節點變色,在進行左/右旋轉, 具體做還是右看你插入的節點的父節點是左子樹還是右子樹,圖例為左子樹。
此處 : 變色 - > 右旋轉
情形4
插入節點父節點為紅色,父父節點的左/右孩子為紅色
先將父節點和父父節點右孩子變黑,父父節點變紅,然後將父節點當做插入節點一樣遞歸向上進行平衡紅黑樹性質操作。 若父節點為根節點直接變父節點為黑色即可.
此處 : 變色 -> 變色
情形5
插入節點的父節點為紅色,父節點為父父節點的左孩子,父父節點的右孩子為黑色,插入節點為右孩子(或者父節點為父父節點的右孩子,父父節點的左孩子為黑色,插入節點為左孩子)。
和情形3類比是一種反向情況,這種情況進行兩次旋轉,
先左/右旋轉,旋轉後變成了情形3,接著按情形3變換即可。
此處 :左旋轉 -> 變色 -> 右旋轉
golang實現
型別定義
需要注意的是 紅黑樹的NIL節點需要單獨定義出來,不能直接用nil哦。
const (
RED = true
BLACK = false
)
type Node struct {
Parent *Node
Left *Node
Right *Node
color bool
Item
}
type Rbtree struct {
NIL *Node
root *Node
count uint64
}
func New() *Rbtree{
node := Node{nil, nil, nil, BLACK, nil}
return &Rbtree{
NIL : &node,
root : &node,
count : 0,
}
}
leftRotate
// Left Rotate
func (rbt *Rbtree) LeftRotate(no *Node) {
// Since we are doing the left rotation, the right child should *NOT* nil.
if no.Right == nil {
return
}
// | |
// X Y
// / \ left rotate / \
// α Y -------------> X γ
// / \ / \
// β γ α β
rchild := no.Right
no.Right = rchild.Left
if rchild.Left != nil {
rchild.Left.Parent = no
}
rchild.Parent = no.Parent
if no.Parent == nil {
rbt.root = rchild
} else if no == no.Parent.Left {
no.Parent.Left = rchild
} else {
no.Parent.Right = rchild
}
rchild.Left = no
no.Parent = rchild
}
func LeftRotateTest(){
var i10 Int = 10
var i12 Int = 12
rbtree := New()
x := &Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, BLACK, i10}
rbtree.root = x
y := &Node{rbtree.root.Right, rbtree.NIL, rbtree.NIL, RED, i12}
rbtree.root.Right = y
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
rbtree.LeftRotate(rbtree.root)
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
}
RightRotate
// Right Rotate
func (rbt *Rbtree) RightRotate(no *Node) {
if no.Left == nil {
return
}
// | |
// X Y
// / \ right rotate / \
// Y γ -------------> α X
// / \ / \
// α β β γ
lchild := no.Left
no.Left = lchild.Right
if lchild.Right != nil {
lchild.Right.Parent = no
}
lchild.Parent = no.Parent
if no.Parent == nil {
rbt.root = lchild
} else if no == no.Parent.Left {
no.Parent.Left = lchild
} else {
no.Parent.Right = lchild
}
lchild.Right = no
no.Parent = lchild
}
func RightRotateTest(){
var i10 Int = 10
var i12 Int = 12
rbtree := New()
x := &Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, BLACK, i10}
rbtree.root = x
y := &Node{rbtree.root.Right, rbtree.NIL, rbtree.NIL, RED, i12}
rbtree.root.Right = y
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
rbtree.RightRotate(rbtree.root)
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
}
Item Interface
值型別介面
type Item interface {
Less(than Item) bool
}
type Int int
func (x Int) Less(than Item) bool {
log.Println(x, " ", than.(Int))
return x < than.(Int)
}
type Uint32 uint32
func (x Uint32) Less(than Item) bool {
log.Println(x, " ", than.(Uint32))
return x < than.(Uint32)
}
type String string
func (x String) Less(than Item) bool {
log.Println(x, " ", than.(String))
return x < than.(String)
}
func ItemTest(){
var itype1 Int = 10
var itype2 Int = 12
log.Println(itype1.Less(itype2))
var strtype1 String = "sola"
var strtype2 String = "ailumiyana"
log.Println(strtype1.Less(strtype2))
}
insert
func (rbt *Rbtree) Insert(no *Node) {
x := rbt.root
var y *Node = rbt.NIL
for x != rbt.NIL {
y = x
if less(no.Item, x.Item) {
x = x.Left
} else if less(x.Item, no.Item) {
x = x.Right
} else {
log.Println("that node already exist")
}
}
no.Parent = y
if y == rbt.NIL {
rbt.root = no
} else if less(no.Item, y.Item) {
y.Left = no
} else {
y.Right = no
}
rbt.count++
rbt.insertFixup(no)
}
func (rbt *Rbtree) insertFixup(no *Node) {
for no.Parent.color == RED {
if no.Parent == no.Parent.Parent.Left {
y := no.Parent.Parent.Right
if y.color == RED {
//
// 情形 4
log.Println("TRACE Do Case 4 :", no.Item)
no.Parent.color = BLACK
y.color = BLACK
no.Parent.Parent.color = RED
no = no.Parent.Parent //迴圈向上自平衡.
} else {
if no == no.Parent.Right {
//
// 情形 5 : 反向情形
// 直接左旋轉 , 然後進行情形3(變色->右旋)
log.Println("TRACE Do Case 5 :", no.Item)
if no == no.Parent.Right {
no = no.Parent
rbt.LeftRotate(no)
}
}
log.Println("TRACE Do Case 6 :", no.Item)
no.Parent.color = BLACK
no.Parent.Parent.color = RED
rbt.RightRotate(no.Parent.Parent)
}
} else { //為父父節點右孩子情形,和左孩子一樣,改下轉向而已.
y := no.Parent.Parent.Left
if y.color == RED {
no.Parent.color = BLACK
y.color = BLACK
no.Parent.Parent.color = RED
no = no.Parent.Parent
} else {
if no == no.Parent.Left {
no = no.Parent
rbt.RightRotate(no)
}
no.Parent.color = BLACK
no.Parent.Parent.color = RED
rbt.LeftRotate(no.Parent.Parent)
}
}
}
rbt.root.color = BLACK
}
func InsertTest(){
rbtree := New()
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(10)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(9)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(8)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(6)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(7)})
log.Println("rbtree counts : ", rbtree.count)
log.Println("------ ", rbtree.root.Item)
log.Println("----", rbtree.root.Left.Item, "---", rbtree.root.Right.Item)
log.Println("--", rbtree.root.Left.Left.Item, "-", rbtree.root.Left.Right.Item)
}
InsertTest() 仔細瞧瞧這就是我們 講情形那棵樹 哈 。
完整程式碼
package main
import(
"log"
)
const (
RED = true
BLACK = false
)
//-----------------------------------
//Item interface
//
type Item interface {
Less(than Item) bool
}
type Int int
func (x Int) Less(than Item) bool {
log.Println(x, " ", than.(Int))
return x < than.(Int)
}
type Uint32 uint32
func (x Uint32) Less(than Item) bool {
log.Println(x, " ", than.(Uint32))
return x < than.(Uint32)
}
type String string
func (x String) Less(than Item) bool {
log.Println(x, " ", than.(String))
return x < than.(String)
}
//-----------------------------------
type Node struct {
Parent *Node
Left *Node
Right *Node
color bool
Item
}
type Rbtree struct {
NIL *Node
root *Node
count uint64
}
func New() *Rbtree{
node := &Node{nil, nil, nil, BLACK, nil}
return &Rbtree{
NIL : node,
root : node,
count : 0,
}
}
func less(x, y Item) bool {
return x.Less(y)
}
// Left Rotate
func (rbt *Rbtree) LeftRotate(no *Node) {
// Since we are doing the left rotation, the right child should *NOT* nil.
if no.Right == rbt.NIL {
return
}
// | |
// X Y
// / \ left rotate / \
// α Y -------------> X γ
// / \ / \
// β γ α β
rchild := no.Right
no.Right = rchild.Left
if rchild.Left != rbt.NIL {
rchild.Left.Parent = no
}
rchild.Parent = no.Parent
if no.Parent == rbt.NIL {
rbt.root = rchild
} else if no == no.Parent.Left {
no.Parent.Left = rchild
} else {
no.Parent.Right = rchild
}
rchild.Left = no
no.Parent = rchild
}
// Right Rotate
func (rbt *Rbtree) RightRotate(no *Node) {
if no.Left == rbt.NIL {
return
}
// | |
// X Y
// / \ right rotate / \
// Y γ -------------> α X
// / \ / \
// α β β γ
lchild := no.Left
no.Left = lchild.Right
if lchild.Right != rbt.NIL {
lchild.Right.Parent = no
}
lchild.Parent = no.Parent
if no.Parent == rbt.NIL {
rbt.root = lchild
} else if no == no.Parent.Left {
no.Parent.Left = lchild
} else {
no.Parent.Right = lchild
}
lchild.Right = no
no.Parent = lchild
}
func (rbt *Rbtree) Insert(no *Node) {
x := rbt.root
var y *Node = rbt.NIL
for x != rbt.NIL {
y = x
if less(no.Item, x.Item) {
x = x.Left
} else if less(x.Item, no.Item) {
x = x.Right
} else {
log.Println("that node already exist")
}
}
no.Parent = y
if y == rbt.NIL {
rbt.root = no
} else if less(no.Item, y.Item) {
y.Left = no
} else {
y.Right = no
}
rbt.count++
rbt.insertFixup(no)
}
func (rbt *Rbtree) insertFixup(no *Node) {
for no.Parent.color == RED {
if no.Parent == no.Parent.Parent.Left {
y := no.Parent.Parent.Right
if y.color == RED {
//
// 情形 4
log.Println("TRACE Do Case 4 :", no.Item)
no.Parent.color = BLACK
y.color = BLACK
no.Parent.Parent.color = RED
no = no.Parent.Parent //迴圈向上自平衡.
} else {
if no == no.Parent.Right {
//
// 情形 5 : 反向情形
// 直接左旋轉 , 然後進行情形3(變色->右旋)
log.Println("TRACE Do Case 5 :", no.Item)
if no == no.Parent.Right {
no = no.Parent
rbt.LeftRotate(no)
}
}
log.Println("TRACE Do Case 6 :", no.Item)
no.Parent.color = BLACK
no.Parent.Parent.color = RED
rbt.RightRotate(no.Parent.Parent)
}
} else { //為父父節點右孩子情形,和左孩子一樣,改下轉向而已.
y := no.Parent.Parent.Left
if y.color == RED {
no.Parent.color = BLACK
y.color = BLACK
no.Parent.Parent.color = RED
no = no.Parent.Parent
} else {
if no == no.Parent.Left {
no = no.Parent
rbt.RightRotate(no)
}
no.Parent.color = BLACK
no.Parent.Parent.color = RED
rbt.LeftRotate(no.Parent.Parent)
}
}
}
rbt.root.color = BLACK
}
func LeftRotateTest(){
var i10 Int = 10
var i12 Int = 12
rbtree := New()
x := &Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, BLACK, i10}
rbtree.root = x
y := &Node{rbtree.root.Right, rbtree.NIL, rbtree.NIL, RED, i12}
rbtree.root.Right = y
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
rbtree.LeftRotate(rbtree.root)
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
}
func RightRotateTest(){
var i10 Int = 10
var i12 Int = 12
rbtree := New()
x := &Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, BLACK, i10}
rbtree.root = x
y := &Node{rbtree.root.Right, rbtree.NIL, rbtree.NIL, RED, i12}
rbtree.root.Left = y
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
rbtree.RightRotate(rbtree.root)
log.Println("root : ", rbtree.root)
log.Println("left : ", rbtree.root.Left)
log.Println("right : ", rbtree.root.Right)
}
func ItemTest(){
var itype1 Int = 10
var itype2 Int = 12
log.Println(itype1.Less(itype2))
var strtype1 String = "sola"
var strtype2 String = "ailumiyana"
log.Println(strtype1.Less(strtype2))
}
func InsertTest(){
rbtree := New()
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(10)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(9)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(8)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(6)})
rbtree.Insert(&Node{rbtree.NIL, rbtree.NIL, rbtree.NIL, RED, Int(7)})
log.Println("rbtree counts : ", rbtree.count)
log.Println("------ ", rbtree.root.Item)
log.Println("----", rbtree.root.Left.Item, "---", rbtree.root.Right.Item)
log.Println("--", rbtree.root.Left.Left.Item, "-", rbtree.root.Left.Right.Item)
}
func main() {
log.Println(" ---- main ------ ")
LeftRotateTest()
RightRotateTest()
ItemTest()
InsertTest()
}
小結
好了本文 對紅黑樹的講解到此結束,剛開始看紅黑樹的時候這些性質確實特別繞,但是理解了這5點性質,就好多了。 然後就是兩個操作 : 變色
和旋轉
理解紅黑樹是通過他們進行自平衡的就行了。
由於時間原因只寫了插入了 ,沒做刪除,有機會再補上吧,不過理解了插入原理,刪除也不在話下了