167 lines
4.0 KiB
Go
167 lines
4.0 KiB
Go
package avl
|
|
|
|
// AVL tree adapted from Julienne Walker's presentation at
|
|
// http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_avl.aspx.
|
|
// This port uses similar indentifier names.
|
|
|
|
// The Key interface must be supported by data stored in the AVL tree.
|
|
type Key interface {
|
|
Less(Key) bool
|
|
Eq(Key) bool
|
|
}
|
|
|
|
// Node is a node in an AVL tree.
|
|
type Node struct {
|
|
Data Key // anything comparable with Less and Eq.
|
|
Balance int // balance factor
|
|
Link [2]*Node // children, indexed by "direction", 0 or 1.
|
|
}
|
|
|
|
// A little readability function for returning the opposite of a direction,
|
|
// where a direction is 0 or 1. Go inlines this.
|
|
// Where JW writes !dir, this code has opp(dir).
|
|
func opp(dir int) int {
|
|
return 1 - dir
|
|
}
|
|
|
|
// single rotation
|
|
func single(root *Node, dir int) *Node {
|
|
save := root.Link[opp(dir)]
|
|
root.Link[opp(dir)] = save.Link[dir]
|
|
save.Link[dir] = root
|
|
return save
|
|
}
|
|
|
|
// double rotation
|
|
func double(root *Node, dir int) *Node {
|
|
save := root.Link[opp(dir)].Link[dir]
|
|
|
|
root.Link[opp(dir)].Link[dir] = save.Link[opp(dir)]
|
|
save.Link[opp(dir)] = root.Link[opp(dir)]
|
|
root.Link[opp(dir)] = save
|
|
|
|
save = root.Link[opp(dir)]
|
|
root.Link[opp(dir)] = save.Link[dir]
|
|
save.Link[dir] = root
|
|
return save
|
|
}
|
|
|
|
// adjust valance factors after double rotation
|
|
func adjustBalance(root *Node, dir, bal int) {
|
|
n := root.Link[dir]
|
|
nn := n.Link[opp(dir)]
|
|
switch nn.Balance {
|
|
case 0:
|
|
root.Balance = 0
|
|
n.Balance = 0
|
|
case bal:
|
|
root.Balance = -bal
|
|
n.Balance = 0
|
|
default:
|
|
root.Balance = 0
|
|
n.Balance = bal
|
|
}
|
|
nn.Balance = 0
|
|
}
|
|
|
|
func insertBalance(root *Node, dir int) *Node {
|
|
n := root.Link[dir]
|
|
bal := 2*dir - 1
|
|
if n.Balance == bal {
|
|
root.Balance = 0
|
|
n.Balance = 0
|
|
return single(root, opp(dir))
|
|
}
|
|
adjustBalance(root, dir, bal)
|
|
return double(root, opp(dir))
|
|
}
|
|
|
|
func insertR(root *Node, data Key) (*Node, bool) {
|
|
if root == nil {
|
|
return &Node{Data: data}, false
|
|
}
|
|
dir := 0
|
|
if root.Data.Less(data) {
|
|
dir = 1
|
|
}
|
|
var done bool
|
|
root.Link[dir], done = insertR(root.Link[dir], data)
|
|
if done {
|
|
return root, true
|
|
}
|
|
root.Balance += 2*dir - 1
|
|
switch root.Balance {
|
|
case 0:
|
|
return root, true
|
|
case 1, -1:
|
|
return root, false
|
|
}
|
|
return insertBalance(root, dir), true
|
|
}
|
|
|
|
// Insert a node into the AVL tree.
|
|
// Data is inserted even if other data with the same key already exists.
|
|
func Insert(tree **Node, data Key) {
|
|
*tree, _ = insertR(*tree, data)
|
|
}
|
|
|
|
func removeBalance(root *Node, dir int) (*Node, bool) {
|
|
n := root.Link[opp(dir)]
|
|
bal := 2*dir - 1
|
|
switch n.Balance {
|
|
case -bal:
|
|
root.Balance = 0
|
|
n.Balance = 0
|
|
return single(root, dir), false
|
|
case bal:
|
|
adjustBalance(root, opp(dir), -bal)
|
|
return double(root, dir), false
|
|
}
|
|
root.Balance = -bal
|
|
n.Balance = bal
|
|
return single(root, dir), true
|
|
}
|
|
|
|
func removeR(root *Node, data Key) (*Node, bool) {
|
|
if root == nil {
|
|
return nil, false
|
|
}
|
|
if root.Data.Eq(data) {
|
|
switch {
|
|
case root.Link[0] == nil:
|
|
return root.Link[1], false
|
|
case root.Link[1] == nil:
|
|
return root.Link[0], false
|
|
}
|
|
heir := root.Link[0]
|
|
for heir.Link[1] != nil {
|
|
heir = heir.Link[1]
|
|
}
|
|
root.Data = heir.Data
|
|
data = heir.Data
|
|
}
|
|
dir := 0
|
|
if root.Data.Less(data) {
|
|
dir = 1
|
|
}
|
|
var done bool
|
|
root.Link[dir], done = removeR(root.Link[dir], data)
|
|
if done {
|
|
return root, true
|
|
}
|
|
root.Balance += 1 - 2*dir
|
|
switch root.Balance {
|
|
case 1, -1:
|
|
return root, true
|
|
case 0:
|
|
return root, false
|
|
}
|
|
return removeBalance(root, dir)
|
|
}
|
|
|
|
// Remove a single item from an AVL tree.
|
|
// If key does not exist, function has no effect.
|
|
func Remove(tree **Node, data Key) {
|
|
*tree, _ = removeR(*tree, data)
|
|
}
|