red-black insertion

This commit is contained in:
Suyono 2023-08-07 20:38:24 +10:00
parent b9c2332be8
commit caaf53b30d
6 changed files with 224 additions and 1 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.idea

1
.tool-versions Normal file
View File

@ -0,0 +1 @@
golang 1.20.7

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) <year> <copyright holders>
Copyright (c) 2023 Suyono
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module gitea.suyono.dev/suyono/redblack
go 1.20

181
redblack.go Normal file
View File

@ -0,0 +1,181 @@
package redblack
type Comparable interface {
Compare(c Comparable) int
}
type Tree struct {
root *Node
num int
}
type Node struct {
key Comparable
color int
parent *Node
left *Node
right *Node
}
func (t *Tree) rightRotate(node *Node) {
var (
left = node.left
)
node.left = node.right
if node.left != nil {
node.left.parent = node
}
left.parent = node.parent
if node.parent == nil {
t.root = left
} else if node == node.parent.left {
node.parent.left = left
} else {
node.parent.right = left
}
left.right = node
node.parent = left
}
func (t *Tree) leftRotate(node *Node) {
var (
right = node.right
)
node.right = right.left
if node.right != nil {
node.right.parent = node
}
right.parent = node.parent
if node.parent == nil {
t.root = right
} else if node == node.parent.left {
node.parent.left = right
} else {
node.parent.right = right
}
right.left = node
node.parent = right
}
func (t *Tree) bst(trav, temp *Node) *Node {
if trav == nil {
return temp
}
if temp.key.Compare(trav.key) < 0 {
trav.left = t.bst(trav.left, temp)
trav.left.parent = trav
} else if temp.key.Compare(trav.key) > 0 {
trav.right = t.bst(trav.right, temp)
trav.right.parent = trav
} else {
panic("duplicate key") // duplicate key not allowed
}
return trav
}
func (t *Tree) fixup(root, pt *Node) {
var (
parentPt *Node
grandParentPt *Node
unclePt *Node
)
for pt != t.root && pt.color != 0 && pt.parent.color == 1 {
parentPt = pt.parent
grandParentPt = pt.parent.parent
//case A: Parent of pt is left child of grand-parent of pt
if parentPt == grandParentPt.left {
unclePt = grandParentPt.right
//case 1: the uncle of pt is also red; only recoloring required
if unclePt != nil && unclePt.color == 1 {
grandParentPt.color = 1
parentPt.color = 0
unclePt.color = 0
pt = grandParentPt
} else {
//case 2: pt is right child of its parent; left-rotation required
if pt == parentPt.right {
t.leftRotate(parentPt)
pt = parentPt
parentPt = pt.parent
}
//case 3: pt is left child of its parent; right-rotation required
t.rightRotate(grandParentPt)
t := parentPt.color
parentPt.color = grandParentPt.color
grandParentPt.color = t
pt = parentPt
}
} else {
//case B: parent of pt is right child of grand parent of pt
unclePt = grandParentPt.left
//case 1: the unclePt is also red; only recoloring required
if unclePt != nil && unclePt.color == 1 {
grandParentPt.color = 1
parentPt.color = 0
unclePt.color = 0
pt = grandParentPt
} else {
//case 2: pt is left child of its parent; right-rotate required
if pt == parentPt.left {
t.rightRotate(parentPt)
pt = parentPt
parentPt = pt.parent
}
//case 3: pt is right child of its parent; left-rotate required
t.leftRotate(grandParentPt)
t := parentPt.color
parentPt.color = grandParentPt.color
grandParentPt.color = t
pt = parentPt
}
}
}
}
func (t *Tree) Insert(key Comparable) {
temp := &Node{
key: key,
color: 1,
}
t.root = t.bst(t.root, temp)
t.fixup(t.root, temp)
t.root.color = 0
t.num++
}
func (t *Tree) Slice() []Comparable {
returnValue := make([]Comparable, t.num)
t.slice(returnValue, 0, t.root)
return returnValue
}
func (t *Tree) slice(s []Comparable, index int, node *Node) int {
if node.left != nil {
index = t.slice(s, index, node.left)
}
s[index] = node.key
index++
if node.right != nil {
index = t.slice(s, index, node.right)
}
return index
}

37
redblack_test.go Normal file
View File

@ -0,0 +1,37 @@
package redblack
import "testing"
type testKey int
func (k testKey) Compare(c Comparable) int {
if ck, ok := c.(testKey); ok {
return int(k - ck)
}
panic("unexpected type")
}
func TestInsert(t *testing.T) {
var (
tree *Tree
out []Comparable
keys = []testKey{7, 6, 5, 4, 3, 2, 1}
)
tree = new(Tree)
for _, k := range keys {
tree.Insert(k)
}
out = tree.Slice()
for i, d := range out {
if ck, ok := d.(testKey); ok {
if ck != keys[len(keys)-1-i] {
t.Fatal("mismatch data")
}
} else {
t.Fatal("invalid data type")
}
}
}