From ecc7575e3c281d41456e16b0270c5999d5febc38 Mon Sep 17 00:00:00 2001 From: li_zhaoyun Date: Wed, 19 Apr 2023 16:42:20 +0800 Subject: [PATCH 1/2] Modify trees value generic type to to allow receive map/slice etc as value, all trees test pass Signed-off-by: li_zhaoyun --- .../redblacktreeextended.go | 3 +- trees/avltree/avltree.go | 25 ++--- trees/avltree/avltree_test.go | 96 ++++++++++++++++++- trees/avltree/iterator.go | 2 +- trees/binaryheap/iterator.go | 2 +- trees/btree/btree.go | 17 ++-- trees/btree/btree_test.go | 7 +- trees/btree/iterator.go | 2 +- trees/redblacktree/iterator.go | 2 +- trees/redblacktree/redblacktree.go | 15 +-- 10 files changed, 131 insertions(+), 40 deletions(-) diff --git a/examples/redblacktreeextended/redblacktreeextended.go b/examples/redblacktreeextended/redblacktreeextended.go index 6aa986b0..db53d4fc 100644 --- a/examples/redblacktreeextended/redblacktreeextended.go +++ b/examples/redblacktreeextended/redblacktreeextended.go @@ -6,11 +6,12 @@ package redblacktreeextended import ( "fmt" + rbt "github.com/ugurcsen/gods-generic/trees/redblacktree" ) // RedBlackTreeExtended to demonstrate how to extend a RedBlackTree to include new functions -type RedBlackTreeExtended[K, T comparable] struct { +type RedBlackTreeExtended[K comparable, T any] struct { *rbt.Tree[K, T] } diff --git a/trees/avltree/avltree.go b/trees/avltree/avltree.go index 56fc5e0c..4b44cff5 100644 --- a/trees/avltree/avltree.go +++ b/trees/avltree/avltree.go @@ -11,6 +11,7 @@ package avltree import ( "fmt" + "github.com/ugurcsen/gods-generic/trees" "github.com/ugurcsen/gods-generic/utils" ) @@ -19,14 +20,14 @@ import ( var _ trees.Tree[int] = new(Tree[int, int]) // Tree holds elements of the AVL tree. -type Tree[K, T comparable] struct { +type Tree[K comparable, T any] struct { Root *Node[K, T] // Root node Comparator utils.Comparator[K] // Key comparator size int // Total number of keys in the tree } // Node is a single element within the tree -type Node[K, T comparable] struct { +type Node[K comparable, T any] struct { Key K Value T Parent *Node[K, T] // Parent node @@ -35,17 +36,17 @@ type Node[K, T comparable] struct { } // NewWith instantiates an AVL tree with the custom comparator. -func NewWith[K, T comparable](comparator utils.Comparator[K]) *Tree[K, T] { +func NewWith[K comparable, T any](comparator utils.Comparator[K]) *Tree[K, T] { return &Tree[K, T]{Comparator: comparator} } // NewWithNumberComparator instantiates an AVL tree with the IntComparator, i.e. keys are of type int. -func NewWithNumberComparator[T comparable]() *Tree[int, T] { +func NewWithNumberComparator[T any]() *Tree[int, T] { return &Tree[int, T]{Comparator: utils.NumberComparator[int]} } // NewWithStringComparator instantiates an AVL tree with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator[T comparable]() *Tree[string, T] { +func NewWithStringComparator[T any]() *Tree[string, T] { return &Tree[string, T]{Comparator: utils.StringComparator} } @@ -291,7 +292,7 @@ func (t *Tree[K, T]) remove(key K, qp **Node[K, T]) bool { return false } -func removeMin[K, T comparable](qp **Node[K, T], minKey *K, minVal *T) bool { +func removeMin[K comparable, T any](qp **Node[K, T], minKey *K, minVal *T) bool { q := *qp if q.Children[0] == nil { *minKey = q.Key @@ -309,7 +310,7 @@ func removeMin[K, T comparable](qp **Node[K, T], minKey *K, minVal *T) bool { return false } -func putFix[K, T comparable](c int8, t **Node[K, T]) bool { +func putFix[K comparable, T any](c int8, t **Node[K, T]) bool { s := *t if s.b == 0 { s.b = c @@ -330,7 +331,7 @@ func putFix[K, T comparable](c int8, t **Node[K, T]) bool { return false } -func removeFix[K, T comparable](c int8, t **Node[K, T]) bool { +func removeFix[K comparable, T any](c int8, t **Node[K, T]) bool { s := *t if s.b == 0 { s.b = c @@ -359,14 +360,14 @@ func removeFix[K, T comparable](c int8, t **Node[K, T]) bool { return true } -func singlerot[K, T comparable](c int8, s *Node[K, T]) *Node[K, T] { +func singlerot[K comparable, T any](c int8, s *Node[K, T]) *Node[K, T] { s.b = 0 s = rotate(c, s) s.b = 0 return s } -func doublerot[K, T comparable](c int8, s *Node[K, T]) *Node[K, T] { +func doublerot[K comparable, T any](c int8, s *Node[K, T]) *Node[K, T] { a := (c + 1) / 2 r := s.Children[a] s.Children[a] = rotate(-c, s.Children[a]) @@ -388,7 +389,7 @@ func doublerot[K, T comparable](c int8, s *Node[K, T]) *Node[K, T] { return p } -func rotate[K, T comparable](c int8, s *Node[K, T]) *Node[K, T] { +func rotate[K comparable, T any](c int8, s *Node[K, T]) *Node[K, T] { a := (c + 1) / 2 r := s.Children[a] s.Children[a] = r.Children[a^1] @@ -446,7 +447,7 @@ func (n *Node[K, T]) walk1(a int) *Node[K, T] { return p } -func output[K, T comparable](node *Node[K, T], prefix string, isTail bool, str *string) { +func output[K comparable, T any](node *Node[K, T], prefix string, isTail bool, str *string) { if node.Children[1] != nil { newPrefix := prefix if isTail { diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index 209bb5b9..e0a64d5c 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -6,12 +6,13 @@ package avltree import ( "encoding/json" "fmt" - "github.com/ugurcsen/gods-generic/utils" "strings" "testing" + + "github.com/ugurcsen/gods-generic/utils" ) -func TestAVLTreeGet(t *testing.T) { +func TestAVLTreeGet1(t *testing.T) { tree := NewWithNumberComparator[string]() if actualValue := tree.Size(); actualValue != 0 { @@ -55,6 +56,50 @@ func TestAVLTreeGet(t *testing.T) { } } +func TestAVLTreeGet2(t *testing.T) { + tree := NewWithNumberComparator[[]string]() + + if actualValue := tree.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + + tree.Put(1, []string{"x"}) // 1->x + tree.Put(2, []string{"b"}) // 1->x, 2->b (in order) + tree.Put(1, []string{"a"}) // 1->a, 2->b (in order, replacement) + tree.Put(3, []string{"c"}) // 1->a, 2->b, 3->c (in order) + tree.Put(4, []string{"d"}) // 1->a, 2->b, 3->c, 4->d (in order) + tree.Put(5, []string{"e"}) // 1->a, 2->b, 3->c, 4->d, 5->e (in order) + tree.Put(6, []string{"f"}) // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) + // + // AVLTree + // │ ┌── 6 + // │ ┌── 5 + // └── 4 + // │ ┌── 3 + // └── 2 + // └── 1 + + if actualValue := tree.Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(2).Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + + if actualValue := tree.GetNode(4).Size(); actualValue != 6 { + t.Errorf("Got %v expected %v", actualValue, 6) + } + + if actualValue := tree.GetNode(7).Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } +} + func TestAVLTreePut(t *testing.T) { tree := NewWithNumberComparator[string]() tree.Put(5, "e") @@ -656,9 +701,8 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { } } -func TestAVLTreeSerialization(t *testing.T) { - tree := NewWith[string, string](utils.StringComparator) - tree = NewWithStringComparator[string]() +func TestAVLTreeSerialization1(t *testing.T) { + tree := NewWithStringComparator[string]() tree.Put("c", "3") tree.Put("b", "2") tree.Put("a", "1") @@ -699,6 +743,48 @@ func TestAVLTreeSerialization(t *testing.T) { } } +func TestAVLTreeSerialization2(t *testing.T) { + tree := NewWithStringComparator[[1]string]() + tree.Put("c", [1]string{"3"}) + tree.Put("b", [1]string{"2"}) + tree.Put("a", [1]string{"1"}) + + var err error + assert := func() { + if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := tree.Keys(); actualValue[0] != "a" || actualValue[1] != "b" || actualValue[2] != "c" { + t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") + } + if actualValue := tree.Values(); actualValue[0][0] != "1" || actualValue[1][0] != "2" || actualValue[2][0] != "3" { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := tree.ToJSON() + assert() + + err = tree.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) + if err != nil { + t.Errorf("Got error %v", err) + } + + tree2 := NewWithStringComparator[int]() + err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree2) + if err != nil { + t.Errorf("Got error %v", err) + } +} + func TestAVLTreeString(t *testing.T) { c := NewWithNumberComparator[int]() c.Put(1, 1) diff --git a/trees/avltree/iterator.go b/trees/avltree/iterator.go index 11d3c672..1dd937c8 100644 --- a/trees/avltree/iterator.go +++ b/trees/avltree/iterator.go @@ -10,7 +10,7 @@ import "github.com/ugurcsen/gods-generic/containers" var _ containers.ReverseIteratorWithKey[int, int] = (*Iterator[int, int])(nil) // Iterator holding the iterator's state -type Iterator[K, T comparable] struct { +type Iterator[K comparable, T any] struct { tree *Tree[K, T] node *Node[K, T] position position diff --git a/trees/binaryheap/iterator.go b/trees/binaryheap/iterator.go index 1a7f9b83..8dc8faaa 100644 --- a/trees/binaryheap/iterator.go +++ b/trees/binaryheap/iterator.go @@ -50,7 +50,7 @@ func (iterator *Iterator[T]) Value() T { if end > iterator.heap.Size() { end = iterator.heap.Size() } - tmpHeap := NewWith[T](iterator.heap.Comparator) + tmpHeap := NewWith(iterator.heap.Comparator) for n := start; n < end; n++ { value, _ := iterator.heap.list.Get(n) tmpHeap.Push(value) diff --git a/trees/btree/btree.go b/trees/btree/btree.go index d8fc8486..a6eabef1 100644 --- a/trees/btree/btree.go +++ b/trees/btree/btree.go @@ -19,16 +19,17 @@ package btree import ( "bytes" "fmt" + "strings" + "github.com/ugurcsen/gods-generic/trees" "github.com/ugurcsen/gods-generic/utils" - "strings" ) // Assert Tree implementation var _ trees.Tree[int] = (*Tree[int, int])(nil) // Tree holds elements of the B-tree -type Tree[K, T comparable] struct { +type Tree[K comparable, T any] struct { Root *Node[K, T] // Root node Comparator utils.Comparator[K] // Key comparator size int // Total number of keys in the tree @@ -36,20 +37,20 @@ type Tree[K, T comparable] struct { } // Node is a single element within the tree -type Node[K, T comparable] struct { +type Node[K comparable, T any] struct { Parent *Node[K, T] Entries []*Entry[K, T] // Contained keys in node Children []*Node[K, T] // Children nodes } // Entry represents the key-value pair contained within nodes -type Entry[K, T comparable] struct { +type Entry[K comparable, T any] struct { Key K Value T } // NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator. -func NewWith[K, T comparable](order int, comparator utils.Comparator[K]) *Tree[K, T] { +func NewWith[K comparable, T any](order int, comparator utils.Comparator[K]) *Tree[K, T] { if order < 3 { panic("Invalid order, should be at least 3") } @@ -57,12 +58,12 @@ func NewWith[K, T comparable](order int, comparator utils.Comparator[K]) *Tree[K } // NewWithNumberComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int. -func NewWithNumberComparator[T comparable](order int) *Tree[int, T] { +func NewWithNumberComparator[T any](order int) *Tree[int, T] { return NewWith[int, T](order, utils.NumberComparator[int]) } // NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string. -func NewWithStringComparator[T comparable](order int) *Tree[string, T] { +func NewWithStringComparator[T any](order int) *Tree[string, T] { return NewWith[string, T](order, utils.StringComparator) } @@ -415,7 +416,7 @@ func (tree *Tree[K, T]) splitRoot() { tree.Root = newRoot } -func setParent[K, T comparable](nodes []*Node[K, T], parent *Node[K, T]) { +func setParent[K comparable, T any](nodes []*Node[K, T], parent *Node[K, T]) { for _, node := range nodes { node.Parent = parent } diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go index 63f5d632..f385af73 100644 --- a/trees/btree/btree_test.go +++ b/trees/btree/btree_test.go @@ -7,9 +7,10 @@ package btree import ( "encoding/json" "fmt" - "github.com/ugurcsen/gods-generic/utils" "strings" "testing" + + "github.com/ugurcsen/gods-generic/utils" ) func TestBTreeGet1(t *testing.T) { @@ -1044,13 +1045,13 @@ func TestBTreeSearch(t *testing.T) { } } -func assertValidTree[K, T comparable](t *testing.T, tree *Tree[K, T], expectedSize int) { +func assertValidTree[K comparable, T any](t *testing.T, tree *Tree[K, T], expectedSize int) { if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue { t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue) } } -func assertValidTreeNode[K, T comparable](t *testing.T, node *Node[K, T], expectedEntries int, expectedChildren int, keys []K, hasParent bool) { +func assertValidTreeNode[K comparable, T any](t *testing.T, node *Node[K, T], expectedEntries int, expectedChildren int, keys []K, hasParent bool) { if actualValue, expectedValue := node.Parent != nil, hasParent; actualValue != expectedValue { t.Errorf("Got %v expected %v for hasParent", actualValue, expectedValue) } diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go index 17c715c9..c5d1a168 100644 --- a/trees/btree/iterator.go +++ b/trees/btree/iterator.go @@ -10,7 +10,7 @@ import "github.com/ugurcsen/gods-generic/containers" var _ containers.ReverseIteratorWithKey[int, int] = (*Iterator[int, int])(nil) // Iterator holding the iterator's state -type Iterator[K, T comparable] struct { +type Iterator[K comparable, T any] struct { tree *Tree[K, T] node *Node[K, T] entry *Entry[K, T] diff --git a/trees/redblacktree/iterator.go b/trees/redblacktree/iterator.go index fd6c24cb..c5a315a3 100644 --- a/trees/redblacktree/iterator.go +++ b/trees/redblacktree/iterator.go @@ -10,7 +10,7 @@ import "github.com/ugurcsen/gods-generic/containers" var _ containers.ReverseIteratorWithKey[int, int] = (*Iterator[int, int])(nil) // Iterator holding the iterator's state -type Iterator[K, T comparable] struct { +type Iterator[K comparable, T any] struct { tree *Tree[K, T] node *Node[K, T] position position diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go index 2b22d97f..beb5cc4d 100644 --- a/trees/redblacktree/redblacktree.go +++ b/trees/redblacktree/redblacktree.go @@ -13,6 +13,7 @@ package redblacktree import ( "fmt" + "github.com/ugurcsen/gods-generic/trees" "github.com/ugurcsen/gods-generic/utils" ) @@ -27,14 +28,14 @@ const ( ) // Tree holds elements of the red-black tree -type Tree[K, T comparable] struct { +type Tree[K comparable, T any] struct { Root *Node[K, T] size int Comparator utils.Comparator[K] } // Node is a single element within the tree -type Node[K, T comparable] struct { +type Node[K comparable, T any] struct { Key K Value T color color @@ -44,17 +45,17 @@ type Node[K, T comparable] struct { } // NewWith instantiates a red-black tree with the custom comparator. -func NewWith[K, T comparable](comparator utils.Comparator[K]) *Tree[K, T] { +func NewWith[K comparable, T any](comparator utils.Comparator[K]) *Tree[K, T] { return &Tree[K, T]{Comparator: comparator} } // NewWithNumberComparator instantiates a red-black tree with the IntComparator, i.e. keys are of type int. -func NewWithNumberComparator[T comparable]() *Tree[int, T] { +func NewWithNumberComparator[T any]() *Tree[int, T] { return &Tree[int, T]{Comparator: utils.NumberComparator[int]} } // NewWithStringComparator instantiates a red-black tree with the StringComparator, i.e. keys are of type string. -func NewWithStringComparator[T comparable]() *Tree[string, T] { +func NewWithStringComparator[T any]() *Tree[string, T] { return &Tree[string, T]{Comparator: utils.StringComparator} } @@ -296,7 +297,7 @@ func (node *Node[K, T]) String() string { return fmt.Sprintf("%v", node.Key) } -func output[K, T comparable](node *Node[K, T], prefix string, isTail bool, str *string) { +func output[K comparable, T any](node *Node[K, T], prefix string, isTail bool, str *string) { if node.Right != nil { newPrefix := prefix if isTail { @@ -541,7 +542,7 @@ func (tree *Tree[K, T]) deleteCase6(node *Node[K, T]) { } } -func nodeColor[K, T comparable](node *Node[K, T]) color { +func nodeColor[K comparable, T any](node *Node[K, T]) color { if node == nil { return black } From facb43eb73ab0ee918d60faa9de0b5a9afb692f1 Mon Sep 17 00:00:00 2001 From: li1234yun Date: Tue, 25 Apr 2023 22:16:43 +0800 Subject: [PATCH 2/2] Remove add tree tests --- trees/avltree/avltree_test.go | 90 +---------------------------------- 1 file changed, 2 insertions(+), 88 deletions(-) diff --git a/trees/avltree/avltree_test.go b/trees/avltree/avltree_test.go index e0a64d5c..25cb2c1b 100644 --- a/trees/avltree/avltree_test.go +++ b/trees/avltree/avltree_test.go @@ -12,7 +12,7 @@ import ( "github.com/ugurcsen/gods-generic/utils" ) -func TestAVLTreeGet1(t *testing.T) { +func TestAVLTreeGet(t *testing.T) { tree := NewWithNumberComparator[string]() if actualValue := tree.Size(); actualValue != 0 { @@ -56,50 +56,6 @@ func TestAVLTreeGet1(t *testing.T) { } } -func TestAVLTreeGet2(t *testing.T) { - tree := NewWithNumberComparator[[]string]() - - if actualValue := tree.Size(); actualValue != 0 { - t.Errorf("Got %v expected %v", actualValue, 0) - } - - if actualValue := tree.GetNode(2).Size(); actualValue != 0 { - t.Errorf("Got %v expected %v", actualValue, 0) - } - - tree.Put(1, []string{"x"}) // 1->x - tree.Put(2, []string{"b"}) // 1->x, 2->b (in order) - tree.Put(1, []string{"a"}) // 1->a, 2->b (in order, replacement) - tree.Put(3, []string{"c"}) // 1->a, 2->b, 3->c (in order) - tree.Put(4, []string{"d"}) // 1->a, 2->b, 3->c, 4->d (in order) - tree.Put(5, []string{"e"}) // 1->a, 2->b, 3->c, 4->d, 5->e (in order) - tree.Put(6, []string{"f"}) // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order) - // - // AVLTree - // │ ┌── 6 - // │ ┌── 5 - // └── 4 - // │ ┌── 3 - // └── 2 - // └── 1 - - if actualValue := tree.Size(); actualValue != 6 { - t.Errorf("Got %v expected %v", actualValue, 6) - } - - if actualValue := tree.GetNode(2).Size(); actualValue != 3 { - t.Errorf("Got %v expected %v", actualValue, 3) - } - - if actualValue := tree.GetNode(4).Size(); actualValue != 6 { - t.Errorf("Got %v expected %v", actualValue, 6) - } - - if actualValue := tree.GetNode(7).Size(); actualValue != 0 { - t.Errorf("Got %v expected %v", actualValue, 0) - } -} - func TestAVLTreePut(t *testing.T) { tree := NewWithNumberComparator[string]() tree.Put(5, "e") @@ -701,7 +657,7 @@ func TestAVLTreeIteratorPrevTo(t *testing.T) { } } -func TestAVLTreeSerialization1(t *testing.T) { +func TestAVLTreeSerialization(t *testing.T) { tree := NewWithStringComparator[string]() tree.Put("c", "3") tree.Put("b", "2") @@ -743,48 +699,6 @@ func TestAVLTreeSerialization1(t *testing.T) { } } -func TestAVLTreeSerialization2(t *testing.T) { - tree := NewWithStringComparator[[1]string]() - tree.Put("c", [1]string{"3"}) - tree.Put("b", [1]string{"2"}) - tree.Put("a", [1]string{"1"}) - - var err error - assert := func() { - if actualValue, expectedValue := tree.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) - } - if actualValue := tree.Keys(); actualValue[0] != "a" || actualValue[1] != "b" || actualValue[2] != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") - } - if actualValue := tree.Values(); actualValue[0][0] != "1" || actualValue[1][0] != "2" || actualValue[2][0] != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") - } - if err != nil { - t.Errorf("Got error %v", err) - } - } - - assert() - - bytes, err := tree.ToJSON() - assert() - - err = tree.FromJSON(bytes) - assert() - - bytes, err = json.Marshal([]interface{}{"a", "b", "c", tree}) - if err != nil { - t.Errorf("Got error %v", err) - } - - tree2 := NewWithStringComparator[int]() - err = json.Unmarshal([]byte(`{"a":1,"b":2}`), &tree2) - if err != nil { - t.Errorf("Got error %v", err) - } -} - func TestAVLTreeString(t *testing.T) { c := NewWithNumberComparator[int]() c.Put(1, 1)