ディレクトリ
golangを達成するための詳細なと赤黒木の原則
赤黒木の原則を見る前に、二分探索木を見てください。
バイナリ検索ツリー
バイナリ検索ツリーは、また、バイナリ・ソート木、二分探索木として知られています。
プロパティ
これは、自然について持っています:
1、ルートノードの左の部分木のすべてのノードは、その平均値よりも小さいです。
図2は、すべてのノードの右の部分木の値は、そのルートより大きい値に等しいです。
図3は、左裕子の木は、バイナリ・ソートツリーです。
4、なしノード等価鍵。
今すぐ検索ツリーと呼ばれ、この構造の利点は、もちろん多少の検索であるということである
私たちは15を検索したい場合は、
1、左サブツリーを探し、ルートノード、15 <50から出発。
2,15 <20、左の部分木を見て、
右のサブツリーを見つけるための3、15> 10、ので、私たちは15を発見しました。
挿入の方法は、インサートの適切な位置を見つけるために、あるレベルの大きさを比較し、類似しています。
时间复杂度
最良の場合には、検索およびログの平均数(n)が2に比例し、それは木を探した回数に等しい高さを参照してください。
キーが単一の分岐ツリーとして構成逐次順序付け、バイナリソートツリー変換を挿入されたとき、もちろん悪い場合があり、ツリーとその深さは、ノードの数(および同じシーケンシャルサーチ)に比例する。
例えば、順次挿入さ:100、 200,90,80,70,60,50,40は、
以下のフォームを次のようになります。
この不均衡な状況に対処するために、赤、黒の木があるでしょう。
赤、黒の木
プロパティ
赤黒木は、次のプロパティと一緒に、二分探索木の特性を含む自己均衡二分探索木、次のとおりです。
1、所有节点的颜色不是红色就是黑色。
2、根节点是黑丝。
3、每个叶子节点都是黑色的空节点(nil)。
4、每个红色节点的两个子节点都是黑色。(从每个叶子到根节点的所有路径上不能有两个连续的红色节点)
5、从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。
40及び90:最初の4つは、それの意味を理解することができるので、そのようなノード60のような第五の点でのみ説明は、すべてのリーフノードへのパスは、ブラックノードを含みます。
操作
その赤黒木5時00分このような性質を維持するために、それは非常に少ない操作をサポートし、
变色
: 顾名思义变色,红变黑,黑变红。
左旋转
: 这里借用百度百科两张旋转图,以图中红色节点为中心,中心节点为右孩子替代,而自己成为它的左孩子,同时节点b作为pivot的有孩子(至于为什么是右孩子,b原本就在pivot的右子树上,所以肯定大于pivot)。
右选装
: 同左旋转,中心点顺时钟旋转,成为其原来左孩子的右孩子,原来左孩子的右孩子则成为原中心点的左孩子。
接着看看红黑树的插入,看看它是如何通过这几个op维持红黑树这5个性质的。
红黑树的插入
关于插入的特点 : 由于性质5的约束,每次插入的节点颜色必然为红色。
插入的化存在几种情形,复杂的树可能会涉及到循环的向树上检索做自平衡,这里先从一颗空树开始先简单理解下这些情形。
情形1
:空树
直接插入,直接作为根节点,同时由于性质1的约束,通过变色op变为黑色即可。
情形2
:插入节点父节为黑色,
不违反任何性质,无需做任何修改。
情形3
插入节点的父节点为红色,父节点为父父节点的左孩子,父父节点的右孩子为黑色,插入节点为左孩子(或者父节点为父父节点的右孩子,父父节点的左孩子为黑色,插入节点为右孩子)。
这是一种插入节点和父节点在一个方向上的情况(例如父节点为左孩子,插入节点也为左孩子)和情形5相反
父节点 及 父父节点变色,在进行左/右旋转, 具体做还是右看你插入的节点的父节点是左子树还是右子树,图例为左子树。
此处 : 变色 - > 右旋转
情形4
插入节点父节点为红色,父父节点的左/右孩子为红色
先将父节点和父父节点右孩子变黑,父父节点变红,然后将父节点当做插入节点一样递归向上进行平衡红黑树性质操作。 若父节点为根节点直接变父节点为黑色即可.
此处 : 变色 -> 变色
情形5
插入节点的父节点为红色,父节点为父父节点的左孩子,父父节点的右孩子为黑色,插入节点为右孩子(或者父节点为父父节点的右孩子,父父节点的左孩子为黑色,插入节点为左孩子)。
和情形3类比是一种反向情况,这种情况进行两次旋转,
先左/右旋转,旋转后变成了情形3,接着按情形3变换即可。
ここで:左回転 - >色 - >右回転
golang達成
タイプ定義
赤黒木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)
}
アイテムのインタフェース
バリュータイプインタフェース
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))
}
インサート
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時、はるかに良いの性質を理解するために、オーバーです。そして、そこに二つの操作:变色
と旋转
自己均衡それらを通る線に理解赤黒木です。
唯一の挿入書いたタイミングの理由から、削除するには、それに修正する機会を持っていますが、挿入の原理を理解していない、削除もそれを言及します。