紅黑樹原理詳解及golang實現

紅黑樹原理詳解及golang實現


在看紅黑樹原理以前,先看下二叉查找樹。golang

二叉查找樹

二叉查找樹,又稱二叉排序樹,二叉搜索樹。less

性質

它具有如下性質:ui

一、左子樹上的全部節點均小於它的根節點值。
二、右子樹上的全部節點的值均大於它根節點的值。
三、左右子樹也分別爲二叉排序樹。
四、沒有鍵值相等的節點。3d

Alt text

既然叫搜索樹,那這種結構的好處固然也就是搜索咯,
假如咱們要查找15code

一、從root節點開始,15<50,找左子樹。
二、15<20,找左子樹,
三、15>10,找右子樹,這樣便找到15了。blog

插入也是相似方法,一層一層比較大小,找到合適的位置插入。
在這裏插入圖片描述排序

時間複雜度
看見它查找的次數等同於樹的高度,在最好的狀況下,其平均查找次數和log 2 (n)成正比。
固然也有壞狀況,當前後插入的關鍵字有序時,構成的二叉排序樹蛻變爲單支樹,樹的深度和其節點數成正比(和順序查找相同).
例如依序插入 : 100、200、90、80、70、60、50、40
就會成爲以下圖形態:
Alt text遞歸

爲了解決這種不平衡的情形,就有了紅黑樹。接口

紅黑樹

性質

紅黑樹是一種自平衡的二叉搜索樹,它包含了二叉搜索樹的特性,同時具有如下性質:

一、全部節點的顏色不是紅色就是黑色。
二、根節點是黑色。
三、每一個葉子節點都是黑色的空節點(nil)。
四、每一個紅色節點的兩個子節點都是黑色。(從每一個葉子到根節點的全部路徑上不能有兩個連續的紅色節點)
五、從任一節點到其葉子節點的全部路徑上都包含相同數目的黑節點。

Alt text

前四都能理解其意思吧,因此只解釋下第五點,好比60這個節點,到其全部葉子節點的路徑都只包含1個黑色節點:40和90。

Alt text

operation

紅黑樹爲了維持它的這5點性質,因而它支持了這麼幾個操做 ,

變色 : 顧名思義變色,紅變黑,黑變紅。
左旋轉 : 這裏借用百度百科兩張旋轉圖,以圖中紅色節點爲中心,中心節點爲右孩子替代,而本身成爲它的左孩子,同時節點b做爲pivot的有孩子(至於爲何是右孩子,b本來就在pivot的右子樹上,因此確定大於pivot)。
Alt text

右選裝 : 同左旋轉,中心點順時鐘旋轉,成爲其原來左孩子的右孩子,原來左孩子的右孩子則成爲原中心點的左孩子。
Alt text

接着看看紅黑樹的插入,看看它是如何經過這幾個op維持紅黑樹這5個性質的。

紅黑樹的插入

關於插入的特色 : 因爲性質5的約束,每次插入的節點顏色必然爲紅色。

插入的化存在幾種情形,複雜的樹可能會涉及到循環的向樹上檢索作自平衡,這裏先從一顆空樹開始先簡單理解下這些情形。

情形1:空樹

直接插入,直接做爲根節點,同時因爲性質1的約束,經過變色op變爲黑色便可。

Alt text

情形2:插入節點父節爲黑色,

不違反任何性質,無需作任何修改。

Alt text

情形3 插入節點的父節點爲紅色,父節點爲父父節點的左孩子,父父節點的右孩子爲黑色,插入節點爲左孩子(或者父節點爲父父節點的右孩子,父父節點的左孩子爲黑色,插入節點爲右孩子)。

這是一種插入節點和父節點在一個方向上的狀況(例如父節點爲左孩子,插入節點也爲左孩子)和情形5相反

父節點 及 父父節點變色,再進行左/右旋轉, 具體左仍是右看你插入的節點的父節點是左子樹仍是右子樹,圖例爲左子樹。

此處 : 變色 - > 右旋轉

Alt text

情形4 插入節點父節點爲紅色,父父節點的左/右孩子爲紅色

先將父節點和父父節點右孩子變黑,父父節點變紅,而後將父節點當作新插入的紅色節點同樣遞歸向上進行平衡紅黑樹性質操做。 若父節點爲根節點直接變父節點爲黑色便可.

此處 : 變色 -> 變色

Alt text

情形5 插入節點的父節點爲紅色,父節點爲父父節點的左孩子,父父節點的右孩子爲黑色,插入節點爲右孩子(或者父節點爲父父節點的右孩子,父父節點的左孩子爲黑色,插入節點爲左孩子)。

和情形3類比是一種反向狀況,這種狀況進行兩次旋轉,
先左/右旋轉,旋轉後變成了情形3,接着按情形3變換便可。

此處 :左旋轉 -> 變色 -> 右旋轉
Alt text

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)

}

Alt text

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)

}

Alt text

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))
}

Alt text

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() 仔細瞧瞧這就是咱們 講情形那棵樹 哈 。

Alt text

完整代碼

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點性質,就好多了。 而後就是兩個操做 : 變色旋轉 理解紅黑樹是經過他們進行自平衡的就好了。 因爲時間緣由只寫了插入了 ,沒作刪除,有機會再補上吧,不過理解了插入原理,刪除也不在話下了吧。

相關文章
相關標籤/搜索