Initial commit
This commit is contained in:
42
sortable.go
Normal file
42
sortable.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package stl
|
||||||
|
|
||||||
|
// ImplicitSortable are types that can be compared with
|
||||||
|
// the less operator <, among others.
|
||||||
|
//
|
||||||
|
// As with C++, two keys are considered equal if neither
|
||||||
|
// x < y nor y < x, so these interfaces have nothing to
|
||||||
|
// do with Go's 'comparable' whatsoever.
|
||||||
|
//
|
||||||
|
// This behavior can be overridden by defining another
|
||||||
|
// type and then add a Compare method to the original key.
|
||||||
|
type ImplicitSortable interface {
|
||||||
|
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~string | ~float32 | ~float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorter is a interface used in the construction of
|
||||||
|
// many collection types, to compare two keys with
|
||||||
|
// the '<' operator by default.
|
||||||
|
type Sorter[T any] interface {
|
||||||
|
Compare(x, y T) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Less implements Sorter for ImplicitSortables using the '<' operator.
|
||||||
|
type Less[T ImplicitSortable] struct{}
|
||||||
|
|
||||||
|
func (Less[T]) Compare(x, y T) bool {
|
||||||
|
return x < y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Greater implements Sorter for ImplicitSortables using the '>' operator.
|
||||||
|
type Greater[T ImplicitSortable] struct{}
|
||||||
|
|
||||||
|
func (Greater[T]) Compare(x, y T) bool {
|
||||||
|
return x > y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal determines if the two keys are considered equal,
|
||||||
|
// i.e., neither x < y nor y < x, per C++ traditions.
|
||||||
|
func Equal[C Sorter[T], T any](x, y T) bool {
|
||||||
|
var c C
|
||||||
|
return !c.Compare(x, y) && !c.Compare(y, x)
|
||||||
|
}
|
215
tree.go
Normal file
215
tree.go
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
package stl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Node is a node on the binary search tree.
|
||||||
|
type Node[K comparable, V any, C Sorter[K]] struct {
|
||||||
|
lson, rson *Node[K, V, C]
|
||||||
|
parent *Node[K, V, C]
|
||||||
|
bal uint32 // for treap balancing
|
||||||
|
|
||||||
|
key K
|
||||||
|
Value V // The value on the node.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key is read-only access to the key of the node.
|
||||||
|
func (n *Node[K, V, C]) Key() K {
|
||||||
|
return n.key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tree is a binary search tree. Always take
|
||||||
|
// addresses and don't work with values.
|
||||||
|
//
|
||||||
|
// The zero value is a usable, empty tree.
|
||||||
|
type Tree[K comparable, V any, C Sorter[K]] struct {
|
||||||
|
root *Node[K, V, C]
|
||||||
|
}
|
||||||
|
|
||||||
|
// TreeInc is an alias for a tree compared by the
|
||||||
|
// default Less operator.
|
||||||
|
type TreeInc[K ImplicitSortable, V any] = Tree[K, V, Less[K]]
|
||||||
|
|
||||||
|
// TreeDec is an alias for a tree compared by the
|
||||||
|
// Greater operator.
|
||||||
|
type TreeDec[K ImplicitSortable, V any] = Tree[K, V, Greater[K]]
|
||||||
|
|
||||||
|
// Clear clears the tree, erasing every element on it.
|
||||||
|
func (t *Tree[K, V, C]) Clear() {
|
||||||
|
t.root = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert tries to insert a new node on the tree, locating
|
||||||
|
// the value if the key is already in the tree.
|
||||||
|
//
|
||||||
|
// Returns the new (or found) value on the tree, and true/false
|
||||||
|
// if the key was inserted or found.
|
||||||
|
func (t *Tree[K, V, C]) Insert(key K, value V) (value_on_tree *V, is_added bool) {
|
||||||
|
node, is_added := t.InsertNode(key, value)
|
||||||
|
return &node.Value, is_added
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertNode does the same as Insert, but returns the entire *Node.
|
||||||
|
func (t *Tree[K, V, C]) InsertNode(key K, value V) (node *Node[K, V, C], is_added bool) {
|
||||||
|
t.root = t.realInsertNode(t.root, nil, key, value, &node, &is_added)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// realInsertNode recursivly searches and tries to insert the new node.
|
||||||
|
// If the key is found, it's passed into *result.
|
||||||
|
func (t *Tree[K, V, C]) realInsertNode(cur, parent *Node[K, V, C], key K, value V, result **Node[K, V, C], is_added *bool) (node *Node[K, V, C]) {
|
||||||
|
var c C
|
||||||
|
if cur == nil {
|
||||||
|
*result = &Node[K, V, C]{
|
||||||
|
parent: parent,
|
||||||
|
key: key,
|
||||||
|
Value: value,
|
||||||
|
bal: rand.Uint32(),
|
||||||
|
}
|
||||||
|
*is_added = true
|
||||||
|
return *result
|
||||||
|
} else if c.Compare(key, cur.key) {
|
||||||
|
// key < now.key
|
||||||
|
cur.lson = t.realInsertNode(cur.lson, cur, key, value, result, is_added)
|
||||||
|
return cur
|
||||||
|
} else if c.Compare(cur.key, key) {
|
||||||
|
// key > now.key
|
||||||
|
cur.rson = t.realInsertNode(cur.rson, cur, key, value, result, is_added)
|
||||||
|
return cur
|
||||||
|
} else {
|
||||||
|
// key == now.key
|
||||||
|
*result = cur
|
||||||
|
*is_added = false
|
||||||
|
return cur
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find finds the value related to the key on the tree,
|
||||||
|
// or nil if it is not found.
|
||||||
|
func (t *Tree[K, V, C]) Find(key K) (value_on_tree *V) {
|
||||||
|
node := t.FindNode(key)
|
||||||
|
if node == nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return &node.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindNode finds the node instead, or nil if it is not found.
|
||||||
|
func (t *Tree[K, V, C]) FindNode(key K) (node *Node[K, V, C]) {
|
||||||
|
return t.realFindNode(t.root, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree[K, V, C]) realFindNode(cur *Node[K, V, C], key K) (node *Node[K, V, C]) {
|
||||||
|
var c C
|
||||||
|
if cur == nil {
|
||||||
|
return nil
|
||||||
|
} else if c.Compare(key, cur.key) {
|
||||||
|
// key < cur.key
|
||||||
|
return t.realFindNode(cur.lson, key)
|
||||||
|
} else if c.Compare(cur.key, key) {
|
||||||
|
// key > cur.key
|
||||||
|
return t.realFindNode(cur.rson, key)
|
||||||
|
} else {
|
||||||
|
// key == cur.key
|
||||||
|
return cur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deletes a node, does nothing if node is Nil.
|
||||||
|
//
|
||||||
|
// Use in tandem with FindNode to delete a key.
|
||||||
|
func (t *Tree[K, V, C]) Delete(node *Node[K, V, C]) {
|
||||||
|
if node == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for node.lson != nil && node.rson != nil {
|
||||||
|
if node.lson.bal < node.rson.bal {
|
||||||
|
node.lson.rotate(&t.root)
|
||||||
|
} else {
|
||||||
|
node.rson.rotate(&t.root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if node == t.root {
|
||||||
|
// select new root
|
||||||
|
if node.lson != nil {
|
||||||
|
t.root = node.lson
|
||||||
|
} else {
|
||||||
|
t.root = node.rson
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if node.lson != nil {
|
||||||
|
node.parent.connect(node.lson, node.tell())
|
||||||
|
} else {
|
||||||
|
node.parent.connect(node.rson, node.tell())
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete everything for the GC
|
||||||
|
// Seriously, why use a tree when you have a GC?
|
||||||
|
node.lson = nil
|
||||||
|
node.rson = nil
|
||||||
|
node.parent = nil
|
||||||
|
var k K
|
||||||
|
var v V
|
||||||
|
node.key = k
|
||||||
|
node.Value = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree[K, V, C]) FirstNode() (node *Node[K, V, C]) {
|
||||||
|
node = t.root
|
||||||
|
if node == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for node.lson != nil {
|
||||||
|
node = node.lson
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree[K, V, C]) LastNode() (node *Node[K, V, C]) {
|
||||||
|
node = t.root
|
||||||
|
if node == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for node.rson != nil {
|
||||||
|
node = node.rson
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node[K, V, C]) Next() (next *Node[K, V, C]) {
|
||||||
|
if node.rson != nil {
|
||||||
|
next = node.rson
|
||||||
|
for next.lson != nil {
|
||||||
|
next = next.lson
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
next = node
|
||||||
|
for next.parent != nil && next.tell() == treeRight {
|
||||||
|
next = next.parent
|
||||||
|
}
|
||||||
|
return next.parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Node[K, V, C]) Previous() (prev *Node[K, V, C]) {
|
||||||
|
if node.lson != nil {
|
||||||
|
prev = node.lson
|
||||||
|
for prev.rson != nil {
|
||||||
|
prev = prev.rson
|
||||||
|
}
|
||||||
|
return prev
|
||||||
|
} else {
|
||||||
|
prev = node
|
||||||
|
for prev.parent != nil && prev.tell() == treeLeft {
|
||||||
|
prev = prev.parent
|
||||||
|
}
|
||||||
|
return prev.parent
|
||||||
|
}
|
||||||
|
}
|
74
tree_adjust.go
Normal file
74
tree_adjust.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package stl
|
||||||
|
|
||||||
|
type treeConnectType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
treeLeft treeConnectType = iota
|
||||||
|
treeRight
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t treeConnectType) invert() treeConnectType {
|
||||||
|
return 1 - t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (son *Node[K, V, C]) tell() treeConnectType {
|
||||||
|
if son.parent == nil {
|
||||||
|
return treeLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
if son.parent.lson == son {
|
||||||
|
return treeLeft
|
||||||
|
} else {
|
||||||
|
return treeRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node[K, V, C]) get(t treeConnectType) *Node[K, V, C] {
|
||||||
|
if t == treeLeft {
|
||||||
|
return n.lson
|
||||||
|
} else {
|
||||||
|
return n.rson
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (parent *Node[K, V, C]) connect(son *Node[K, V, C], t treeConnectType) {
|
||||||
|
if son != nil {
|
||||||
|
son.parent = parent
|
||||||
|
}
|
||||||
|
if parent != nil {
|
||||||
|
if t == treeLeft {
|
||||||
|
parent.lson = son
|
||||||
|
} else {
|
||||||
|
parent.rson = son
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate the node up
|
||||||
|
func (node *Node[K, V, C]) rotate(root **Node[K, V, C]) {
|
||||||
|
if node.parent == nil {
|
||||||
|
// is root, sanity check
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t := node.tell()
|
||||||
|
|
||||||
|
f := node.parent
|
||||||
|
b := node.get(t.invert())
|
||||||
|
|
||||||
|
f.parent.connect(node, f.tell())
|
||||||
|
node.connect(f, t.invert())
|
||||||
|
f.connect(b, t)
|
||||||
|
|
||||||
|
if node.parent == nil {
|
||||||
|
// new root
|
||||||
|
*root = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust the new node in the tree Treap style.
|
||||||
|
func (node *Node[K, V, C]) adjust(root **Node[K, V, C]) {
|
||||||
|
for node.parent != nil && node.parent.bal > node.bal {
|
||||||
|
node.rotate(root)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user