github.com/hyperledger-labs/bdls@v2.1.1+incompatible/common/graph/tree.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package graph 8 9 // Iterator defines an iterator that can be used to traverse vertices 10 // of a graph 11 type Iterator interface { 12 // Next returns the next element in the iteration order, 13 // or nil if there is no such an element 14 Next() *TreeVertex 15 } 16 17 // TreeVertex defines a vertex of a tree 18 type TreeVertex struct { 19 Id string // id identifies uniquely the TreeVertex in the Tree 20 Data interface{} // data holds arbitrary data, to be used by the user of the package 21 Descendants []*TreeVertex // descendants are the vertices that this TreeVertex is their parent in the tree 22 Threshold int // threshold symbols the count of sub-trees / leaves to pick when creating tree permutations 23 } 24 25 // NewTreeVertex creates a new vertex with a given unique id and a given arbitrary data 26 func NewTreeVertex(id string, data interface{}, descendants ...*TreeVertex) *TreeVertex { 27 return &TreeVertex{ 28 Id: id, 29 Data: data, 30 Descendants: descendants, 31 } 32 } 33 34 // IsLeaf returns whether the given vertex is a leaf 35 func (v *TreeVertex) IsLeaf() bool { 36 return len(v.Descendants) == 0 37 } 38 39 // AddDescendant creates a new vertex who's parent is the invoker vertex, 40 // with a given id and data. Returns the new vertex 41 func (v *TreeVertex) AddDescendant(u *TreeVertex) *TreeVertex { 42 v.Descendants = append(v.Descendants, u) 43 return u 44 } 45 46 // ToTree creates a Tree who's root vertex is the current vertex 47 func (v *TreeVertex) ToTree() *Tree { 48 return &Tree{ 49 Root: v, 50 } 51 } 52 53 // Find searches for a vertex who's id is the given id. 54 // Returns the first vertex it finds with such an Id, or nil if not found 55 func (v *TreeVertex) Find(id string) *TreeVertex { 56 if v.Id == id { 57 return v 58 } 59 for _, u := range v.Descendants { 60 if r := u.Find(id); r != nil { 61 return r 62 } 63 } 64 return nil 65 } 66 67 // Exists searches for a vertex who's id is the given id, 68 // and returns whether such a vertex was found or not. 69 func (v *TreeVertex) Exists(id string) bool { 70 return v.Find(id) != nil 71 } 72 73 // Clone clones the tree who's root vertex is the current vertex. 74 func (v *TreeVertex) Clone() *TreeVertex { 75 var descendants []*TreeVertex 76 for _, u := range v.Descendants { 77 descendants = append(descendants, u.Clone()) 78 } 79 copy := &TreeVertex{ 80 Id: v.Id, 81 Descendants: descendants, 82 Data: v.Data, 83 } 84 return copy 85 } 86 87 // replace replaces the sub-tree of the vertex who's id is the given id 88 // with a sub-tree who's root vertex is r. 89 func (v *TreeVertex) replace(id string, r *TreeVertex) { 90 if v.Id == id { 91 v.Descendants = r.Descendants 92 return 93 } 94 for _, u := range v.Descendants { 95 u.replace(id, r) 96 } 97 } 98 99 // Tree defines a Tree of vertices of type TreeVertex 100 type Tree struct { 101 Root *TreeVertex 102 } 103 104 // Permute returns Trees that their vertices and edges all exist in the original tree. 105 // The permutations are calculated according to the thresholds of all vertices. 106 // The combinationUpperBound is an upper bound of possible combinations of direct descendants 107 // of a vertex. If the vertex has a threshold and descendants that result a number of combinations 108 // that exceeds the given combinationUpperBound, the descendants are pruned until the number of 109 // combinations is lower than the combinationUpperBound. 110 // This is done in order to cap the memory usage of the computed result. 111 func (t *Tree) Permute(combinationUpperBound int) []*Tree { 112 return newTreePermutation(t.Root, combinationUpperBound).permute() 113 } 114 115 // BFS returns an iterator that iterates the vertices 116 // in a Breadth-First-Search order 117 func (t *Tree) BFS() Iterator { 118 return newBFSIterator(t.Root) 119 } 120 121 type bfsIterator struct { 122 *queue 123 } 124 125 func newBFSIterator(v *TreeVertex) *bfsIterator { 126 return &bfsIterator{ 127 queue: &queue{ 128 arr: []*TreeVertex{v}, 129 }, 130 } 131 } 132 133 // Next returns the next element in the iteration order, 134 // or nil if there is no such an element 135 func (bfs *bfsIterator) Next() *TreeVertex { 136 if len(bfs.arr) == 0 { 137 return nil 138 } 139 v := bfs.dequeue() 140 for _, u := range v.Descendants { 141 bfs.enqueue(u) 142 } 143 return v 144 } 145 146 // a primitive implementation of a queue backed by a slice 147 type queue struct { 148 arr []*TreeVertex 149 } 150 151 func (q *queue) enqueue(v *TreeVertex) { 152 q.arr = append(q.arr, v) 153 } 154 155 func (q *queue) dequeue() *TreeVertex { 156 v := q.arr[0] 157 q.arr = q.arr[1:] 158 return v 159 }