red-black insertion
This commit is contained in:
parent
b9c2332be8
commit
caaf53b30d
|
@ -0,0 +1 @@
|
|||
/.idea
|
|
@ -0,0 +1 @@
|
|||
golang 1.20.7
|
2
LICENSE
2
LICENSE
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue