diff --git a/trie/radix.go b/trie/radix.go new file mode 100644 index 0000000..1cffb54 --- /dev/null +++ b/trie/radix.go @@ -0,0 +1,439 @@ +package trie + +import ( + "fmt" + "iter" + "strings" + + . "github.com/moorara/algo/generic" + "github.com/moorara/algo/internal/graphviz" +) + +type radixNode[V any] struct { + label []byte + val V + term bool + children []*radixNode[V] +} + +// search looks for a child node that is a prefix of the given key. +func (n *radixNode[V]) search(key []byte) (int, int) { + for i, e := range n.children { + // Children (edges) are sorted + if key[0] < e.label[0] { + return i, 0 + } + + j := 0 + for j < len(key) && j < len(e.label) && key[j] == e.label[j] { + j++ + } + + if j > 0 { + return i, j + } + } + + return len(n.children), 0 +} + +type radix[V any] struct { + size int + root *radixNode[V] + eqVal EqualFunc[V] +} + +// NewRadix creates a new Radix tree. +// +// A Radix tree is an ordered tree that represents a space-optimized trie (prefix tree). +// It is derived from a regular trie by merging each node, that is the only child of its parent, with its parent. +// +// Like regular tries, +// +// - The root node is always associated with the empty string. +// - Keys are stored on a path from the root node to any arbitrary node (keys are stored on edges). +// - All the descendants of a node have the same common prefix of the string associated with that node. +// +// Unlike regular tries, edges can be labeled with sequences of digits as well as single digits. +func NewRadix[V any](eqVal EqualFunc[V]) Trie[V] { + return &radix[V]{ + size: 0, + root: new(radixNode[V]), + eqVal: eqVal, + } +} + +func (t *radix[V]) verify() bool { + // TODO: + return false +} + +// Size returns the number of key-value pairs in the Radix tree. +func (t *radix[V]) Size() int { + return t.size +} + +// Height returns the height of the Radix tree. +func (t *radix[V]) Height() int { + return t._height(t.root) +} + +func (t *radix[V]) _height(n *radixNode[V]) int { + if n == nil { + return 0 + } + + h := 0 + for _, c := range n.children { + h = max(h, t._height(c)) + } + + return 1 + h +} + +// IsEmpty returns true if the Radix tree is empty. +func (t *radix[V]) IsEmpty() bool { + return t.size == 0 +} + +// Put adds a new key-value pair to the Radix tree. +func (t *radix[V]) Put(key string, val V) { + k := []byte(key) + last := t.root + + for l := 0; l < len(k); { + i, j := last.search(k[l:]) + if j < len(last.children[i].label) { + break + } + + last = last.children[i] + l += len(last.label) + } + + if last.term { + last.val = val // Update value for the existing key + return + } + + // TODO: +} + +// Get returns the value of a given key in the Radix tree. +func (t *radix[V]) Get(key string) (V, bool) { + var zeroV V + + k := []byte(key) + curr := t.root + + for l := 0; l < len(k); { + i, j := curr.search(k[l:]) + if j < len(curr.children[i].label) { + return zeroV, false + } + + curr = curr.children[i] + l += len(curr.label) + } + + if curr.term { + return curr.val, true + } + + return zeroV, false +} + +// Delete removes a key-value pair from the Radix tree. +func (t *radix[V]) Delete(key string) (val V, ok bool) { + // TODO: + var zeroV V + return zeroV, false +} + +// DeleteAll deletes all key-values from the Radix tree, leaving it empty. +func (t *radix[V]) DeleteAll() { + t.size = 0 + t.root = new(radixNode[V]) +} + +// Min returns the minimum key and its value in the Radix tree. +func (t *radix[V]) Min() (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// Max returns the maximum key and its value in the Radix tree. +func (t *radix[V]) Max() (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// Floor returns the largest key in the Radix tree less than or equal to key. +func (t *radix[V]) Floor(key string) (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// Ceiling returns the smallest key in the Radix tree greater than or equal to key. +func (t *radix[V]) Ceiling(key string) (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// DeleteMin removes the smallest key and associated value from the Radix tree. +func (t *radix[V]) DeleteMin() (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// DeleteMax removes the largest key and associated value from the Radix tree. +func (t *radix[V]) DeleteMax() (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// Select returns the k-th smallest key in the Radix tree. +func (t *radix[V]) Select(rank int) (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// Rank returns the number of keys in the Radix tree less than key. +func (t *radix[V]) Rank(key string) int { + // TODO: + return -1 +} + +// Range returns all keys and associated values in the Radix tree between two given keys. +func (t *radix[V]) Range(lo, hi string) []KeyValue[string, V] { + // TODO: + return nil +} + +// RangeSize returns the number of keys in the Radix tree between two given keys. +func (t *radix[V]) RangeSize(lo, hi string) int { + // TODO: + return -1 +} + +// Match returns all the keys and associated values in the radix trie +// that match the given pattern in which * matches any character. +func (t *radix[V]) Match(pattern string) []KeyValue[string, V] { + // TODO: + return nil +} + +// WithPrefix returns all the keys and associated values in the Radix tree having s as a prefix. +func (t *radix[V]) WithPrefix(prefix string) []KeyValue[string, V] { + // TODO: + return nil +} + +// LongestPrefixOf returns the key and associated value in the radix trie +// that is the longest prefix of the given key. +func (t *radix[V]) LongestPrefixOf(prefix string) (string, V, bool) { + // TODO: + var zeroV V + return "", zeroV, false +} + +// String returns a string representation of the radix trie. +func (t *radix[V]) String() string { + i := 0 + pairs := make([]string, t.Size()) + + t._traverse(t.root, "", Ascending, func(k string, n *radixNode[V]) bool { + if n.term { + pairs[i] = fmt.Sprintf("<%v:%v>", k, n.val) + i++ + } + return true + }) + + return fmt.Sprintf("{%s}", strings.Join(pairs, " ")) +} + +// Equals determines whether or not two radix tries have the same key-value pairs. +func (t *radix[V]) Equals(rhs Trie[V]) bool { + t2, ok := rhs.(*radix[V]) + if !ok { + return false + } + + return t._traverse(t.root, "", Ascending, func(k string, n *radixNode[V]) bool { // t ⊂ t2 + if n.term { + val, ok := t2.Get(k) + return ok && t.eqVal(n.val, val) + } + return true + }) && t2._traverse(t2.root, "", Ascending, func(k string, n *radixNode[V]) bool { // t2 ⊂ t + if n.term { + val, ok := t.Get(k) + return ok && t.eqVal(n.val, val) + } + return true + }) +} + +// All returns an iterator sequence containing all the key-value pairs in the radix trie. +func (t *radix[V]) All() iter.Seq2[string, V] { + return func(yield func(string, V) bool) { + t._traverse(t.root, "", Ascending, func(k string, n *radixNode[V]) bool { + return !n.term || yield(k, n.val) + }) + } +} + +// AnyMatch returns true if at least one key-value pair in the radix trie satisfies the provided predicate. +func (t *radix[V]) AnyMatch(p Predicate2[string, V]) bool { + return !t._traverse(t.root, "", VLR, func(key string, n *radixNode[V]) bool { + return !n.term || !p(key, n.val) + }) +} + +// AllMatch returns true if all key-value pairs in the radix trie satisfy the provided predicate. +// If the radix trie is empty, it returns true. +func (t *radix[V]) AllMatch(p Predicate2[string, V]) bool { + return t._traverse(t.root, "", VLR, func(key string, n *radixNode[V]) bool { + return !n.term || p(key, n.val) + }) +} + +// SelectMatch selects a subset of key-values from the radix trie that satisfy the given predicate. +// It returns a new radix trie containing the matching key-values, of the same type as the original radix trie. +func (t *radix[V]) SelectMatch(p Predicate2[string, V]) Collection2[string, V] { + newT := NewRadix[V](t.eqVal).(*radix[V]) + + t._traverse(t.root, "", VLR, func(key string, n *radixNode[V]) bool { + if n.term && p(key, n.val) { + newT.Put(key, n.val) + } + return true + }) + + return newT +} + +// Traverse performs a traversal of the radix trie using the specified traversal order +// and yields the key-value pair of each node to the provided VisitFunc2 function. +// +// If the function returns false, the traversal is halted. +func (t *radix[V]) Traverse(order TraverseOrder, visit VisitFunc2[string, V]) { + t._traverse(t.root, "", order, func(_ string, n *radixNode[V]) bool { + return visit(string(n.label), n.val) + }) +} + +func (t *radix[V]) _traverse(n *radixNode[V], prefix string, order TraverseOrder, visit func(string, *radixNode[V]) bool) bool { + if n == nil { + return true + } + + prefix = prefix + string(n.label) + + switch order { + case VLR, Ascending: + res := visit(prefix, n) + for i := 0; i < len(n.children); i++ { + res = res && t._traverse(n.children[i], prefix, order, visit) + } + return res + + case VRL: + res := visit(prefix, n) + for i := len(n.children) - 1; i >= 0; i-- { + res = res && t._traverse(n.children[i], prefix, order, visit) + } + return res + + case LRV: + res := true + for i := 0; i < len(n.children); i++ { + res = res && t._traverse(n.children[i], prefix, order, visit) + } + return res && visit(prefix, n) + + case RLV, Descending: + res := true + for i := len(n.children) - 1; i >= 0; i-- { + res = res && t._traverse(n.children[i], prefix, order, visit) + } + return res && visit(prefix, n) + + default: + return false + } +} + +// Graphviz generates and returns a string representation of the radix trie in DOT format. +// This format is commonly used for visualizing graphs with Graphviz tools. +func (t *radix[V]) Graphviz() string { + // Create a map of node --> id + var id int + nodeID := map[*radixNode[V]]int{} + t._traverse(t.root, "", VLR, func(_ string, n *radixNode[V]) bool { + id++ + nodeID[n] = id + return true + }) + + graph := graphviz.NewGraph(true, true, false, "Radix Tree", graphviz.RankDirTB, "", "", graphviz.ShapeMrecord) + + t._traverse(t.root, "", VLR, func(_ string, n *radixNode[V]) bool { + name := fmt.Sprintf("%d", nodeID[n]) + + var label string + var style graphviz.Style + var topField graphviz.Field + + switch { + case n == t.root: + label = "•" + topField = graphviz.NewSimpleField("", label) + case !n.term: + label = string(n.label) + topField = graphviz.NewSimpleField("", label) + default: + label = string(n.label) + style = graphviz.StyleBold + topField = graphviz.NewComplexField( + graphviz.NewRecord( + graphviz.NewSimpleField("", label), + graphviz.NewSimpleField("", fmt.Sprintf("%v", n.val)), + ), + ) + } + + bottomRec := graphviz.NewRecord() + for _, e := range n.children { + edgeName := string(e.label) + from := fmt.Sprintf("%s:%s", name, edgeName) + to := fmt.Sprintf("%d", nodeID[e]) + + bottomRec.AddField(graphviz.NewSimpleField(edgeName, "")) + graph.AddEdge(graphviz.NewEdge(from, to, graphviz.EdgeTypeDirected, "", "", "", "", "", "")) + } + + rec := graphviz.NewRecord( + graphviz.NewComplexField( + graphviz.NewRecord( + topField, + graphviz.NewComplexField(bottomRec), + ), + ), + ) + + graph.AddNode(graphviz.NewNode(name, "", rec.Label(), "", style, "", "", "")) + + return true + }) + + return graph.DotCode() +} diff --git a/trie/radix_test.go b/trie/radix_test.go new file mode 100644 index 0000000..f3d79b0 --- /dev/null +++ b/trie/radix_test.go @@ -0,0 +1,78 @@ +package trie + +import ( + "testing" + + . "github.com/moorara/algo/generic" +) + +func getRadixTests() []trieTest[int] { + tests := getTrieTests() + + tests[0].trie = "Radix Trie" + tests[0].expectedHeight = 3 + tests[0].equals = nil + tests[0].expectedEquals = false + tests[0].expectedVLRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedVRLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedLVRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedRVLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedLRVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedRLVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedAscendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedDescendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[0].expectedGraphviz = `` + + tests[1].trie = "Radix Trie" + tests[1].expectedHeight = 5 + tests[1].equals = NewRadix[int](nil) + tests[1].expectedEquals = false + tests[1].expectedVLRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedVRLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedLVRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedRVLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedLRVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedRLVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedAscendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedDescendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[1].expectedGraphviz = `` + + tests[2].trie = "Radix Trie" + tests[2].expectedHeight = 7 + tests[2].equals = NewRadix[int](nil) + tests[2].expectedEquals = false + tests[2].expectedVLRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedVRLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedLVRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedRVLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedLRVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedRLVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedAscendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedDescendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[2].expectedGraphviz = `` + + tests[3].trie = "Radix Trie" + tests[3].expectedHeight = 8 + tests[3].equals = NewRadix[int](nil) + tests[3].expectedEquals = true + tests[3].expectedVLRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedVRLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 7}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedLVRTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedRVLTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedLRVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedRLVTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedAscendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedDescendingTraverse = []KeyValue[string, int]{{Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}, {Key: "", Val: 0}} + tests[3].expectedGraphviz = `` + + return tests +} + +func TestRadixTrie(t *testing.T) { + tests := getRadixTests() + + for _, tc := range tests { + bin := NewRadix[int](tc.eqVal) + runTrieTest(t, bin, tc) + } +}