├── README.md ├── binary-search-tree ├── binarysearchtree.go └── binarysearchtree_test.go ├── dictionary ├── dictionary.go └── dictionary_test.go ├── graph ├── graph.go ├── graph_test.go └── queue-node.go ├── hashtable ├── hashtable.go └── hashtable_test.go ├── linkedlist ├── linkedlist.go └── linkedlist_test.go ├── queue ├── queue.go └── queue_test.go ├── set ├── .DS_Store ├── set.go └── set_test.go └── stack ├── stack.go └── stack_test.go /README.md: -------------------------------------------------------------------------------- 1 | # Go Data Structures 2 | 3 | Data structures covered, in alphabetical order: 4 | 5 | ## [Binary Search Tree](https://flaviocopes.com/golang-data-structure-binary-search-tree) 6 | 7 | [![](https://flaviocopes.com/img/golang-data-structures/binary-search-tree.png)](https://flaviocopes.com/golang-data-structure-binary-search-tree) 8 | 9 | ## [Dictionary](https://flaviocopes.com/golang-data-structure-dictionary) 10 | 11 | [![](https://flaviocopes.com/img/golang-data-structures/dictionary.png)](https://flaviocopes.com/golang-data-structure-dictionary) 12 | 13 | ## [Graph](https://flaviocopes.com/golang-data-structure-graph) 14 | 15 | [![](https://flaviocopes.com/img/golang-data-structures/graph.png)](https://flaviocopes.com/golang-data-structure-graph) 16 | 17 | ## [Hash Table](https://flaviocopes.com/golang-data-structure-hashtable) 18 | 19 | [![](https://flaviocopes.com/img/golang-data-structures/hashtable.png)](https://flaviocopes.com/golang-data-structure-hashtable) 20 | 21 | ## [Linked List](https://flaviocopes.com/golang-data-structure-linked-list) 22 | 23 | [![](https://flaviocopes.com/img/golang-data-structures/linked-list.png)](https://flaviocopes.com/golang-data-structure-linked-list) 24 | 25 | ## [Queue](https://flaviocopes.com/golang-data-structure-queue) 26 | 27 | [![](https://flaviocopes.com/img/golang-data-structures/queue.png)](https://flaviocopes.com/golang-data-structure-queue) 28 | 29 | ## [Set](https://flaviocopes.com/golang-data-structure-set) 30 | 31 | [![](https://flaviocopes.com/img/golang-data-structures/set.png)](https://flaviocopes.com/golang-data-structure-set) 32 | 33 | ## [Stack](https://flaviocopes.com/golang-data-structure-stack) 34 | 35 | [![](https://flaviocopes.com/img/golang-data-structures/stack.png)](https://flaviocopes.com/golang-data-structure-stack) 36 | -------------------------------------------------------------------------------- /binary-search-tree/binarysearchtree.go: -------------------------------------------------------------------------------- 1 | // Package binarysearchtree creates a ItemBinarySearchTree data structure for the Item type 2 | package binarysearchtree 3 | 4 | import ( 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/cheekybits/genny/generic" 9 | ) 10 | 11 | // Item the type of the binary search tree 12 | type Item generic.Type 13 | 14 | // Node a single node that composes the tree 15 | type Node struct { 16 | key int 17 | value Item 18 | left *Node //left 19 | right *Node //right 20 | } 21 | 22 | // ItemBinarySearchTree the binary search tree of Items 23 | type ItemBinarySearchTree struct { 24 | root *Node 25 | lock sync.RWMutex 26 | } 27 | 28 | // Insert inserts the Item t in the tree 29 | func (bst *ItemBinarySearchTree) Insert(key int, value Item) { 30 | bst.lock.Lock() 31 | defer bst.lock.Unlock() 32 | n := &Node{key, value, nil, nil} 33 | if bst.root == nil { 34 | bst.root = n 35 | } else { 36 | insertNode(bst.root, n) 37 | } 38 | } 39 | 40 | // internal function to find the correct place for a node in a tree 41 | func insertNode(node, newNode *Node) { 42 | if newNode.key < node.key { 43 | if node.left == nil { 44 | node.left = newNode 45 | } else { 46 | insertNode(node.left, newNode) 47 | } 48 | } else { 49 | if node.right == nil { 50 | node.right = newNode 51 | } else { 52 | insertNode(node.right, newNode) 53 | } 54 | } 55 | } 56 | 57 | // InOrderTraverse visits all nodes with in-order traversing 58 | func (bst *ItemBinarySearchTree) InOrderTraverse(f func(Item)) { 59 | bst.lock.RLock() 60 | defer bst.lock.RUnlock() 61 | inOrderTraverse(bst.root, f) 62 | } 63 | 64 | // internal recursive function to traverse in order 65 | func inOrderTraverse(n *Node, f func(Item)) { 66 | if n != nil { 67 | inOrderTraverse(n.left, f) 68 | f(n.value) 69 | inOrderTraverse(n.right, f) 70 | } 71 | } 72 | 73 | // PreOrderTraverse visits all nodes with pre-order traversing 74 | func (bst *ItemBinarySearchTree) PreOrderTraverse(f func(Item)) { 75 | bst.lock.Lock() 76 | defer bst.lock.Unlock() 77 | preOrderTraverse(bst.root, f) 78 | } 79 | 80 | // internal recursive function to traverse pre order 81 | func preOrderTraverse(n *Node, f func(Item)) { 82 | if n != nil { 83 | f(n.value) 84 | preOrderTraverse(n.left, f) 85 | preOrderTraverse(n.right, f) 86 | } 87 | } 88 | 89 | // PostOrderTraverse visits all nodes with post-order traversing 90 | func (bst *ItemBinarySearchTree) PostOrderTraverse(f func(Item)) { 91 | bst.lock.Lock() 92 | defer bst.lock.Unlock() 93 | postOrderTraverse(bst.root, f) 94 | } 95 | 96 | // internal recursive function to traverse post order 97 | func postOrderTraverse(n *Node, f func(Item)) { 98 | if n != nil { 99 | postOrderTraverse(n.left, f) 100 | postOrderTraverse(n.right, f) 101 | f(n.value) 102 | } 103 | } 104 | 105 | // Min returns the Item with min value stored in the tree 106 | func (bst *ItemBinarySearchTree) Min() *Item { 107 | bst.lock.RLock() 108 | defer bst.lock.RUnlock() 109 | n := bst.root 110 | if n == nil { 111 | return nil 112 | } 113 | for { 114 | if n.left == nil { 115 | return &n.value 116 | } 117 | n = n.left 118 | } 119 | } 120 | 121 | // Max returns the Item with max value stored in the tree 122 | func (bst *ItemBinarySearchTree) Max() *Item { 123 | bst.lock.RLock() 124 | defer bst.lock.RUnlock() 125 | n := bst.root 126 | if n == nil { 127 | return nil 128 | } 129 | for { 130 | if n.right == nil { 131 | return &n.value 132 | } 133 | n = n.right 134 | } 135 | } 136 | 137 | // Search returns true if the Item t exists in the tree 138 | func (bst *ItemBinarySearchTree) Search(key int) bool { 139 | bst.lock.RLock() 140 | defer bst.lock.RUnlock() 141 | return search(bst.root, key) 142 | } 143 | 144 | // internal recursive function to search an item in the tree 145 | func search(n *Node, key int) bool { 146 | if n == nil { 147 | return false 148 | } 149 | if key < n.key { 150 | return search(n.left, key) 151 | } 152 | if key > n.key { 153 | return search(n.right, key) 154 | } 155 | return true 156 | } 157 | 158 | // Remove removes the Item with key `key` from the tree 159 | func (bst *ItemBinarySearchTree) Remove(key int) { 160 | bst.lock.Lock() 161 | defer bst.lock.Unlock() 162 | remove(bst.root, key) 163 | } 164 | 165 | // internal recursive function to remove an item 166 | func remove(node *Node, key int) *Node { 167 | if node == nil { 168 | return nil 169 | } 170 | if key < node.key { 171 | node.left = remove(node.left, key) 172 | return node 173 | } 174 | if key > node.key { 175 | node.right = remove(node.right, key) 176 | return node 177 | } 178 | // key == node.key 179 | if node.left == nil && node.right == nil { 180 | node = nil 181 | return nil 182 | } 183 | if node.left == nil { 184 | node = node.right 185 | return node 186 | } 187 | if node.right == nil { 188 | node = node.left 189 | return node 190 | } 191 | leftmostrightside := node.right 192 | for { 193 | //find smallest value on the right side 194 | if leftmostrightside != nil && leftmostrightside.left != nil { 195 | leftmostrightside = leftmostrightside.left 196 | } else { 197 | break 198 | } 199 | } 200 | node.key, node.value = leftmostrightside.key, leftmostrightside.value 201 | node.right = remove(node.right, node.key) 202 | return node 203 | } 204 | 205 | // String prints a visual representation of the tree 206 | func (bst *ItemBinarySearchTree) String() { 207 | bst.lock.Lock() 208 | defer bst.lock.Unlock() 209 | fmt.Println("------------------------------------------------") 210 | stringify(bst.root, 0) 211 | fmt.Println("------------------------------------------------") 212 | } 213 | 214 | // internal recursive function to print a tree 215 | func stringify(n *Node, level int) { 216 | if n != nil { 217 | format := "" 218 | for i := 0; i < level; i++ { 219 | format += " " 220 | } 221 | format += "---[ " 222 | level++ 223 | stringify(n.left, level) 224 | fmt.Printf(format+"%d\n", n.key) 225 | stringify(n.right, level) 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /binary-search-tree/binarysearchtree_test.go: -------------------------------------------------------------------------------- 1 | package binarysearchtree 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var bst ItemBinarySearchTree 9 | 10 | func fillTree(bst *ItemBinarySearchTree) { 11 | bst.Insert(8, "8") 12 | bst.Insert(4, "4") 13 | bst.Insert(10, "10") 14 | bst.Insert(2, "2") 15 | bst.Insert(6, "6") 16 | bst.Insert(1, "1") 17 | bst.Insert(3, "3") 18 | bst.Insert(5, "5") 19 | bst.Insert(7, "7") 20 | bst.Insert(9, "9") 21 | } 22 | 23 | func TestInsert(t *testing.T) { 24 | fillTree(&bst) 25 | bst.String() 26 | 27 | bst.Insert(11, "11") 28 | bst.String() 29 | } 30 | 31 | // isSameSlice returns true if the 2 slices are identical 32 | func isSameSlice(a, b []string) bool { 33 | if a == nil && b == nil { 34 | return true 35 | } 36 | if a == nil || b == nil { 37 | return false 38 | } 39 | if len(a) != len(b) { 40 | return false 41 | } 42 | for i := range a { 43 | if a[i] != b[i] { 44 | return false 45 | } 46 | } 47 | return true 48 | } 49 | 50 | func TestInOrderTraverse(t *testing.T) { 51 | var result []string 52 | bst.InOrderTraverse(func(i Item) { 53 | result = append(result, fmt.Sprintf("%s", i)) 54 | }) 55 | if !isSameSlice(result, []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"}) { 56 | t.Errorf("Traversal order incorrect, got %v", result) 57 | } 58 | } 59 | 60 | func TestPreOrderTraverse(t *testing.T) { 61 | var result []string 62 | bst.PreOrderTraverse(func(i Item) { 63 | result = append(result, fmt.Sprintf("%s", i)) 64 | }) 65 | if !isSameSlice(result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"}) { 66 | t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"8", "4", "2", "1", "3", "6", "5", "7", "10", "9", "11"}) 67 | } 68 | } 69 | 70 | func TestPostOrderTraverse(t *testing.T) { 71 | var result []string 72 | bst.PostOrderTraverse(func(i Item) { 73 | result = append(result, fmt.Sprintf("%s", i)) 74 | }) 75 | if !isSameSlice(result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"}) { 76 | t.Errorf("Traversal order incorrect, got %v instead of %v", result, []string{"1", "3", "2", "5", "7", "6", "4", "9", "11", "10", "8"}) 77 | } 78 | } 79 | 80 | func TestMin(t *testing.T) { 81 | if fmt.Sprintf("%s", *bst.Min()) != "1" { 82 | t.Errorf("min should be 1") 83 | } 84 | } 85 | 86 | func TestMax(t *testing.T) { 87 | if fmt.Sprintf("%s", *bst.Max()) != "11" { 88 | t.Errorf("max should be 11") 89 | } 90 | } 91 | 92 | func TestSearch(t *testing.T) { 93 | if !bst.Search(1) || !bst.Search(8) || !bst.Search(11) { 94 | t.Errorf("search not working") 95 | } 96 | } 97 | 98 | func TestRemove(t *testing.T) { 99 | bst.Remove(1) 100 | if fmt.Sprintf("%s", *bst.Min()) != "2" { 101 | t.Errorf("min should be 2") 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /dictionary/dictionary.go: -------------------------------------------------------------------------------- 1 | // Package dictionary creates a ValueDictionary data structure for the Item type 2 | package dictionary 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/cheekybits/genny/generic" 8 | ) 9 | 10 | // Key the key of the dictionary 11 | type Key generic.Type 12 | 13 | // Value the content of the dictionary 14 | type Value generic.Type 15 | 16 | // ValueDictionary the set of Items 17 | type ValueDictionary struct { 18 | items map[Key]Value 19 | lock sync.RWMutex 20 | } 21 | 22 | // Set adds a new item to the dictionary 23 | func (d *ValueDictionary) Set(k Key, v Value) { 24 | d.lock.Lock() 25 | defer d.lock.Unlock() 26 | if d.items == nil { 27 | d.items = make(map[Key]Value) 28 | } 29 | d.items[k] = v 30 | } 31 | 32 | // Delete removes a value from the dictionary, given its key 33 | func (d *ValueDictionary) Delete(k Key) bool { 34 | d.lock.Lock() 35 | defer d.lock.Unlock() 36 | _, ok := d.items[k] 37 | if ok { 38 | delete(d.items, k) 39 | } 40 | return ok 41 | } 42 | 43 | // Has returns true if the key exists in the dictionary 44 | func (d *ValueDictionary) Has(k Key) bool { 45 | d.lock.RLock() 46 | defer d.lock.RUnlock() 47 | _, ok := d.items[k] 48 | return ok 49 | } 50 | 51 | // Get returns the value associated with the key 52 | func (d *ValueDictionary) Get(k Key) Value { 53 | d.lock.RLock() 54 | defer d.lock.RUnlock() 55 | return d.items[k] 56 | } 57 | 58 | // Clear removes all the items from the dictionary 59 | func (d *ValueDictionary) Clear() { 60 | d.lock.Lock() 61 | defer d.lock.Unlock() 62 | d.items = make(map[Key]Value) 63 | } 64 | 65 | // Size returns the amount of elements in the dictionary 66 | func (d *ValueDictionary) Size() int { 67 | d.lock.RLock() 68 | defer d.lock.RUnlock() 69 | return len(d.items) 70 | } 71 | 72 | // Keys returns a slice of all the keys present 73 | func (d *ValueDictionary) Keys() []Key { 74 | d.lock.RLock() 75 | defer d.lock.RUnlock() 76 | keys := []Key{} 77 | for i := range d.items { 78 | keys = append(keys, i) 79 | } 80 | return keys 81 | } 82 | 83 | // Values returns a slice of all the values present 84 | func (d *ValueDictionary) Values() []Value { 85 | d.lock.RLock() 86 | defer d.lock.RUnlock() 87 | values := []Value{} 88 | for i := range d.items { 89 | values = append(values, d.items[i]) 90 | } 91 | return values 92 | } 93 | -------------------------------------------------------------------------------- /dictionary/dictionary_test.go: -------------------------------------------------------------------------------- 1 | package dictionary 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func populateDictionary(count int, start int) *ValueDictionary { 9 | dict := ValueDictionary{} 10 | for i := start; i < (start + count); i++ { 11 | dict.Set(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i)) 12 | } 13 | return &dict 14 | } 15 | 16 | func TestSet(t *testing.T) { 17 | dict := populateDictionary(3, 0) 18 | if size := dict.Size(); size != 3 { 19 | t.Errorf("wrong count, expected 3 and got %d", size) 20 | } 21 | dict.Set("key1", "value1") //should not add a new one, just change the existing one 22 | if size := dict.Size(); size != 3 { 23 | t.Errorf("wrong count, expected 3 and got %d", size) 24 | } 25 | dict.Set("key4", "value4") //should add it 26 | if size := dict.Size(); size != 4 { 27 | t.Errorf("wrong count, expected 4 and got %d", size) 28 | } 29 | } 30 | 31 | func TestDelete(t *testing.T) { 32 | dict := populateDictionary(3, 0) 33 | dict.Delete("key2") 34 | if size := dict.Size(); size != 2 { 35 | t.Errorf("wrong count, expected 2 and got %d", size) 36 | } 37 | } 38 | 39 | func TestClear(t *testing.T) { 40 | dict := populateDictionary(3, 0) 41 | dict.Clear() 42 | if size := dict.Size(); size != 0 { 43 | t.Errorf("wrong count, expected 0 and got %d", size) 44 | } 45 | } 46 | 47 | func TestHas(t *testing.T) { 48 | dict := populateDictionary(3, 0) 49 | has := dict.Has("key2") 50 | if !has { 51 | t.Errorf("expected key2 to be there") 52 | } 53 | dict.Delete("key2") 54 | has = dict.Has("key2") 55 | if has { 56 | t.Errorf("expected key2 to be removed") 57 | } 58 | dict.Delete("key1") 59 | has = dict.Has("key1") 60 | if has { 61 | t.Errorf("expected key1 to be removed") 62 | } 63 | } 64 | 65 | func TestKeys(t *testing.T) { 66 | dict := populateDictionary(3, 0) 67 | items := dict.Keys() 68 | if len(items) != 3 { 69 | t.Errorf("wrong count, expected 3 and got %d", len(items)) 70 | } 71 | dict = populateDictionary(520, 0) 72 | items = dict.Keys() 73 | if len(items) != 520 { 74 | t.Errorf("wrong count, expected 520 and got %d", len(items)) 75 | } 76 | } 77 | 78 | func TestValues(t *testing.T) { 79 | dict := populateDictionary(3, 0) 80 | items := dict.Values() 81 | if len(items) != 3 { 82 | t.Errorf("wrong count, expected 3 and got %d", len(items)) 83 | } 84 | dict = populateDictionary(520, 0) 85 | items = dict.Values() 86 | if len(items) != 520 { 87 | t.Errorf("wrong count, expected 520 and got %d", len(items)) 88 | } 89 | } 90 | 91 | func TestSize(t *testing.T) { 92 | dict := populateDictionary(3, 0) 93 | items := dict.Values() 94 | if len(items) != dict.Size() { 95 | t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) 96 | } 97 | dict = populateDictionary(0, 0) 98 | items = dict.Values() 99 | if len(items) != dict.Size() { 100 | t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) 101 | } 102 | dict = populateDictionary(10000, 0) 103 | items = dict.Values() 104 | if len(items) != dict.Size() { 105 | t.Errorf("wrong count, expected %d and got %d", dict.Size(), len(items)) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /graph/graph.go: -------------------------------------------------------------------------------- 1 | // Package graph creates a ItemGraph data structure for the Item type 2 | package graph 3 | 4 | import ( 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/cheekybits/genny/generic" 9 | ) 10 | 11 | // Item the type of the binary search tree 12 | type Item generic.Type 13 | 14 | // Node a single node that composes the tree 15 | type Node struct { 16 | value Item 17 | } 18 | 19 | func (n *Node) String() string { 20 | return fmt.Sprintf("%v", n.value) 21 | } 22 | 23 | // ItemGraph the Items graph 24 | type ItemGraph struct { 25 | nodes []*Node 26 | edges map[Node][]*Node 27 | lock sync.RWMutex 28 | } 29 | 30 | // AddNode adds a node to the graph 31 | func (g *ItemGraph) AddNode(n *Node) { 32 | g.lock.Lock() 33 | g.nodes = append(g.nodes, n) 34 | g.lock.Unlock() 35 | } 36 | 37 | // AddEdge adds an edge to the graph 38 | func (g *ItemGraph) AddEdge(n1, n2 *Node) { 39 | g.lock.Lock() 40 | if g.edges == nil { 41 | g.edges = make(map[Node][]*Node) 42 | } 43 | g.edges[*n1] = append(g.edges[*n1], n2) 44 | g.edges[*n2] = append(g.edges[*n2], n1) 45 | g.lock.Unlock() 46 | } 47 | 48 | // AddEdge adds an edge to the graph 49 | func (g *ItemGraph) String() { 50 | g.lock.RLock() 51 | s := "" 52 | for i := 0; i < len(g.nodes); i++ { 53 | s += g.nodes[i].String() + " -> " 54 | near := g.edges[*g.nodes[i]] 55 | for j := 0; j < len(near); j++ { 56 | s += near[j].String() + " " 57 | } 58 | s += "\n" 59 | } 60 | fmt.Println(s) 61 | g.lock.RUnlock() 62 | } 63 | 64 | // Traverse implements the BFS traversing algorithm 65 | func (g *ItemGraph) Traverse(f func(*Node)) { 66 | g.lock.RLock() 67 | q := NodeQueue{} 68 | q.New() 69 | n := g.nodes[0] 70 | q.Enqueue(*n) 71 | visited := make(map[*Node]bool) 72 | for { 73 | if q.IsEmpty() { 74 | break 75 | } 76 | node := q.Dequeue() 77 | visited[node] = true 78 | near := g.edges[*node] 79 | 80 | for i := 0; i < len(near); i++ { 81 | j := near[i] 82 | if !visited[j] { 83 | q.Enqueue(*j) 84 | visited[j] = true 85 | } 86 | } 87 | if f != nil { 88 | f(node) 89 | } 90 | } 91 | g.lock.RUnlock() 92 | } 93 | -------------------------------------------------------------------------------- /graph/graph_test.go: -------------------------------------------------------------------------------- 1 | package graph 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var g ItemGraph 9 | 10 | func fillGraph() { 11 | nA := Node{"A"} 12 | nB := Node{"B"} 13 | nC := Node{"C"} 14 | nD := Node{"D"} 15 | nE := Node{"E"} 16 | nF := Node{"F"} 17 | g.AddNode(&nA) 18 | g.AddNode(&nB) 19 | g.AddNode(&nC) 20 | g.AddNode(&nD) 21 | g.AddNode(&nE) 22 | g.AddNode(&nF) 23 | 24 | g.AddEdge(&nA, &nB) 25 | g.AddEdge(&nA, &nC) 26 | g.AddEdge(&nB, &nE) 27 | g.AddEdge(&nC, &nE) 28 | g.AddEdge(&nE, &nF) 29 | g.AddEdge(&nD, &nA) 30 | } 31 | 32 | func TestAdd(t *testing.T) { 33 | fillGraph() 34 | g.String() 35 | } 36 | 37 | func TestTraverse(t *testing.T) { 38 | g.Traverse(func(n *Node) { 39 | fmt.Printf("%v\n", n) 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /graph/queue-node.go: -------------------------------------------------------------------------------- 1 | // This file was automatically generated by genny. 2 | // Any changes will be lost if this file is regenerated. 3 | // see https://github.com/cheekybits/genny 4 | 5 | // Package queue creates a NodeQueue data structure for the Node type 6 | package graph 7 | 8 | import "sync" 9 | 10 | // NodeQueue the queue of Nodes 11 | type NodeQueue struct { 12 | items []Node 13 | lock sync.RWMutex 14 | } 15 | 16 | // New creates a new NodeQueue 17 | func (s *NodeQueue) New() *NodeQueue { 18 | s.lock.Lock() 19 | s.items = []Node{} 20 | s.lock.Unlock() 21 | return s 22 | } 23 | 24 | // Enqueue adds an Node to the end of the queue 25 | func (s *NodeQueue) Enqueue(t Node) { 26 | s.lock.Lock() 27 | s.items = append(s.items, t) 28 | s.lock.Unlock() 29 | } 30 | 31 | // Dequeue removes an Node from the start of the queue 32 | func (s *NodeQueue) Dequeue() *Node { 33 | s.lock.Lock() 34 | item := s.items[0] 35 | s.items = s.items[1:len(s.items)] 36 | s.lock.Unlock() 37 | return &item 38 | } 39 | 40 | // Front returns the item next in the queue, without removing it 41 | func (s *NodeQueue) Front() *Node { 42 | s.lock.RLock() 43 | item := s.items[0] 44 | s.lock.RUnlock() 45 | return &item 46 | } 47 | 48 | // IsEmpty returns true if the queue is empty 49 | func (s *NodeQueue) IsEmpty() bool { 50 | s.lock.RLock() 51 | defer s.lock.RUnlock() 52 | return len(s.items) == 0 53 | } 54 | 55 | // Size returns the number of Nodes in the queue 56 | func (s *NodeQueue) Size() int { 57 | s.lock.RLock() 58 | defer s.lock.RUnlock() 59 | return len(s.items) 60 | } 61 | -------------------------------------------------------------------------------- /hashtable/hashtable.go: -------------------------------------------------------------------------------- 1 | // Package hashtable creates a ValueHashtable data structure for the Item type 2 | package hashtable 3 | 4 | import ( 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/cheekybits/genny/generic" 9 | ) 10 | 11 | // Key the key of the dictionary 12 | type Key generic.Type 13 | 14 | // Value the content of the dictionary 15 | type Value generic.Type 16 | 17 | // ValueHashtable the set of Items 18 | type ValueHashtable struct { 19 | items map[int]Value 20 | lock sync.RWMutex 21 | } 22 | 23 | // the hash() private function uses the famous Horner's method 24 | // to generate a hash of a string with O(n) complexity 25 | func hash(k Key) int { 26 | key := fmt.Sprintf("%s", k) 27 | h := 0 28 | for i := 0; i < len(key); i++ { 29 | h = 31*h + int(key[i]) 30 | } 31 | return h 32 | } 33 | 34 | // Put item with value v and key k into the hashtable 35 | func (ht *ValueHashtable) Put(k Key, v Value) { 36 | ht.lock.Lock() 37 | defer ht.lock.Unlock() 38 | i := hash(k) 39 | if ht.items == nil { 40 | ht.items = make(map[int]Value) 41 | } 42 | ht.items[i] = v 43 | } 44 | 45 | // Remove item with key k from hashtable 46 | func (ht *ValueHashtable) Remove(k Key) { 47 | ht.lock.Lock() 48 | defer ht.lock.Unlock() 49 | i := hash(k) 50 | delete(ht.items, i) 51 | } 52 | 53 | // Get item with key k from the hashtable 54 | func (ht *ValueHashtable) Get(k Key) Value { 55 | ht.lock.RLock() 56 | defer ht.lock.RUnlock() 57 | i := hash(k) 58 | return ht.items[i] 59 | } 60 | 61 | // Size returns the number of the hashtable elements 62 | func (ht *ValueHashtable) Size() int { 63 | ht.lock.RLock() 64 | defer ht.lock.RUnlock() 65 | return len(ht.items) 66 | } 67 | -------------------------------------------------------------------------------- /hashtable/hashtable_test.go: -------------------------------------------------------------------------------- 1 | package hashtable 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func populateHashtable(count int, start int) *ValueHashtable { 9 | dict := ValueHashtable{} 10 | for i := start; i < (start + count); i++ { 11 | dict.Put(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i)) 12 | } 13 | return &dict 14 | } 15 | 16 | func TestPut(t *testing.T) { 17 | dict := populateHashtable(3, 0) 18 | if size := dict.Size(); size != 3 { 19 | t.Errorf("wrong count, expected 3 and got %d", size) 20 | } 21 | dict.Put("key1", "value1") //should not add a new one, just change the existing one 22 | if size := dict.Size(); size != 3 { 23 | t.Errorf("wrong count, expected 3 and got %d", size) 24 | } 25 | dict.Put("key4", "value4") //should add it 26 | if size := dict.Size(); size != 4 { 27 | t.Errorf("wrong count, expected 4 and got %d", size) 28 | } 29 | } 30 | 31 | func TestRemove(t *testing.T) { 32 | dict := populateHashtable(3, 0) 33 | dict.Remove("key2") 34 | if size := dict.Size(); size != 2 { 35 | t.Errorf("wrong count, expected 2 and got %d", size) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /linkedlist/linkedlist.go: -------------------------------------------------------------------------------- 1 | // Package linkedlist creates a ItemLinkedList data structure for the Item type 2 | package linkedlist 3 | 4 | import ( 5 | "fmt" 6 | "sync" 7 | 8 | "github.com/cheekybits/genny/generic" 9 | ) 10 | 11 | // Item the type of the linked list 12 | type Item generic.Type 13 | 14 | // Node a single node that composes the list 15 | type Node struct { 16 | content Item 17 | next *Node 18 | } 19 | 20 | // ItemLinkedList the linked list of Items 21 | type ItemBinarySearchTree struct { 22 | head *Node 23 | size int 24 | lock sync.RWMutex 25 | } 26 | 27 | // Append adds an Item to the end of the linked list 28 | func (ll *ItemLinkedList) Append(t Item) { 29 | ll.lock.Lock() 30 | node := Node{t, nil} 31 | if ll.head == nil { 32 | ll.head = &node 33 | } else { 34 | last := ll.head 35 | for { 36 | if last.next == nil { 37 | break 38 | } 39 | last = last.next 40 | } 41 | last.next = &node 42 | } 43 | ll.size++ 44 | ll.lock.Unlock() 45 | } 46 | 47 | // Insert adds an Item at position i 48 | func (ll *ItemLinkedList) Insert(i int, t Item) error { 49 | ll.lock.Lock() 50 | defer ll.lock.Unlock() 51 | if i < 0 || i > ll.size { 52 | return fmt.Errorf("Index out of bounds") 53 | } 54 | addNode := Node{t, nil} 55 | if i == 0 { 56 | addNode.next = ll.head 57 | ll.head = &addNode 58 | return nil 59 | } 60 | node := ll.head 61 | j := 0 62 | for j < i-2 { 63 | j++ 64 | node = node.next 65 | } 66 | addNode.next = node.next 67 | node.next = &addNode 68 | ll.size++ 69 | return nil 70 | } 71 | 72 | // RemoveAt removes a node at position i 73 | func (ll *ItemLinkedList) RemoveAt(i int) (*Item, error) { 74 | ll.lock.Lock() 75 | defer ll.lock.Unlock() 76 | if i < 0 || i > ll.size { 77 | return nil, fmt.Errorf("Index out of bounds") 78 | } 79 | node := ll.head 80 | j := 0 81 | for j < i-1 { 82 | j++ 83 | node = node.next 84 | } 85 | remove := node.next 86 | node.next = remove.next 87 | ll.size-- 88 | return &remove.content, nil 89 | } 90 | 91 | // IndexOf returns the position of the Item t 92 | func (ll *ItemLinkedList) IndexOf(t Item) int { 93 | ll.lock.RLock() 94 | defer ll.lock.RUnlock() 95 | node := ll.head 96 | j := 0 97 | for { 98 | if node.content == t { 99 | return j 100 | } 101 | if node.next == nil { 102 | return -1 103 | } 104 | node = node.next 105 | j++ 106 | } 107 | } 108 | 109 | // IsEmpty returns true if the list is empty 110 | func (ll *ItemLinkedList) IsEmpty() bool { 111 | ll.lock.RLock() 112 | defer ll.lock.RUnlock() 113 | if ll.head == nil { 114 | return true 115 | } 116 | return false 117 | } 118 | 119 | // Size returns the linked list size 120 | func (ll *ItemLinkedList) Size() int { 121 | ll.lock.RLock() 122 | defer ll.lock.RUnlock() 123 | size := 1 124 | last := ll.head 125 | for { 126 | if last == nil || last.next == nil { 127 | break 128 | } 129 | last = last.next 130 | size++ 131 | } 132 | return size 133 | } 134 | 135 | // Insert adds an Item at position i 136 | func (ll *ItemLinkedList) String() { 137 | ll.lock.RLock() 138 | defer ll.lock.RUnlock() 139 | node := ll.head 140 | j := 0 141 | for { 142 | if node == nil { 143 | break 144 | } 145 | j++ 146 | fmt.Print(node.content) 147 | fmt.Print(" ") 148 | node = node.next 149 | } 150 | fmt.Println() 151 | } 152 | 153 | // Head returns a pointer to the first node of the list 154 | func (ll *ItemLinkedList) Head() *Node { 155 | ll.lock.RLock() 156 | defer ll.lock.RUnlock() 157 | return ll.head 158 | } 159 | -------------------------------------------------------------------------------- /linkedlist/linkedlist_test.go: -------------------------------------------------------------------------------- 1 | package linkedlist 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | var ll ItemLinkedList 9 | 10 | func TestAppend(t *testing.T) { 11 | ll.String() 12 | if !ll.IsEmpty() { 13 | t.Errorf("list should be empty") 14 | } 15 | 16 | ll.Append("first") 17 | if ll.IsEmpty() { 18 | t.Errorf("list should not be empty") 19 | } 20 | 21 | if size := ll.Size(); size != 1 { 22 | t.Errorf("wrong count, expected 1 and got %d", size) 23 | } 24 | 25 | ll.Append("second") 26 | ll.Append("third") 27 | 28 | if size := ll.Size(); size != 3 { 29 | t.Errorf("wrong count, expected 3 and got %d", size) 30 | } 31 | 32 | ll.String() 33 | } 34 | 35 | func TestRemoveAt(t *testing.T) { 36 | _, err := ll.RemoveAt(1) 37 | if err != nil { 38 | t.Errorf("unexpected error %s", err) 39 | } 40 | 41 | if size := ll.Size(); size != 2 { 42 | t.Errorf("wrong count, expected 2 and got %d", size) 43 | } 44 | 45 | ll.String() 46 | } 47 | 48 | func TestInsert(t *testing.T) { 49 | //test inserting in the middle 50 | err := ll.Insert(2, "second2") 51 | if err != nil { 52 | t.Errorf("unexpected error %s", err) 53 | } 54 | if size := ll.Size(); size != 3 { 55 | t.Errorf("wrong count, expected 3 and got %d", size) 56 | } 57 | 58 | //test inserting at head position 59 | err = ll.Insert(0, "zero") 60 | if err != nil { 61 | t.Errorf("unexpected error %s", err) 62 | } 63 | 64 | ll.String() 65 | } 66 | 67 | func TestIndexOf(t *testing.T) { 68 | if i := ll.IndexOf("zero"); i != 0 { 69 | t.Errorf("expected position 0 but got %d", i) 70 | } 71 | if i := ll.IndexOf("first"); i != 1 { 72 | t.Errorf("expected position 1 but got %d", i) 73 | } 74 | if i := ll.IndexOf("second2"); i != 2 { 75 | t.Errorf("expected position 2 but got %d", i) 76 | } 77 | if i := ll.IndexOf("third"); i != 3 { 78 | t.Errorf("expected position 3 but got %d", i) 79 | } 80 | } 81 | 82 | func TestHead(t *testing.T) { 83 | h := ll.Head() 84 | if "zero" != fmt.Sprint(h.content) { 85 | t.Errorf("Expected `zero` but got %s", fmt.Sprint(h.content)) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /queue/queue.go: -------------------------------------------------------------------------------- 1 | // Package queue creates a ItemQueue data structure for the Item type 2 | package queue 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/cheekybits/genny/generic" 8 | ) 9 | 10 | // Item the type of the queue 11 | type Item generic.Type 12 | 13 | // ItemQueue the queue of Items 14 | type ItemQueue struct { 15 | items []Item 16 | lock sync.RWMutex 17 | } 18 | 19 | // New creates a new ItemQueue 20 | func (s *ItemQueue) New() *ItemQueue { 21 | s.lock.Lock() 22 | s.items = []Item{} 23 | s.lock.Unlock() 24 | return s 25 | } 26 | 27 | // Enqueue adds an Item to the end of the queue 28 | func (s *ItemQueue) Enqueue(t Item) { 29 | s.lock.Lock() 30 | s.items = append(s.items, t) 31 | s.lock.Unlock() 32 | } 33 | 34 | // Dequeue removes an Item from the start of the queue 35 | func (s *ItemQueue) Dequeue() *Item { 36 | s.lock.Lock() 37 | item := s.items[0] 38 | s.items = s.items[1:len(s.items)] 39 | s.lock.Unlock() 40 | return &item 41 | } 42 | 43 | // Front returns the item next in the queue, without removing it 44 | func (s *ItemQueue) Front() *Item { 45 | s.lock.RLock() 46 | item := s.items[0] 47 | s.lock.RUnlock() 48 | return &item 49 | } 50 | 51 | // IsEmpty returns true if the queue is empty 52 | func (s *ItemQueue) IsEmpty() bool { 53 | s.lock.RLock() 54 | defer s.lock.RUnlock() 55 | return len(s.items) == 0 56 | } 57 | 58 | // Size returns the number of Items in the queue 59 | func (s *ItemQueue) Size() int { 60 | s.lock.RLock() 61 | defer s.lock.RUnlock() 62 | return len(s.items) 63 | } 64 | -------------------------------------------------------------------------------- /queue/queue_test.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var s ItemQueue 8 | 9 | func initQueue() *ItemQueue { 10 | if s.items == nil { 11 | s = ItemQueue{} 12 | s.New() 13 | } 14 | return &s 15 | } 16 | 17 | func TestEnqueue(t *testing.T) { 18 | s := initQueue() 19 | s.Enqueue(1) 20 | s.Enqueue(2) 21 | s.Enqueue(3) 22 | 23 | if size := s.Size(); size != 3 { 24 | t.Errorf("wrong count, expected 3 and got %d", size) 25 | } 26 | } 27 | 28 | func TestDequeue(t *testing.T) { 29 | s.Dequeue() 30 | if size := len(s.items); size != 2 { 31 | t.Errorf("wrong count, expected 2 and got %d", size) 32 | } 33 | 34 | s.Dequeue() 35 | s.Dequeue() 36 | if size := len(s.items); size != 0 { 37 | t.Errorf("wrong count, expected 0 and got %d", size) 38 | } 39 | 40 | if !s.IsEmpty() { 41 | t.Errorf("IsEmpty should return true") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /set/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flaviocopes/datastructures/531bd789b40b28c67c21fa8359bb109cddaf4c57/set/.DS_Store -------------------------------------------------------------------------------- /set/set.go: -------------------------------------------------------------------------------- 1 | // Package stack creates a ItemStack data structure for the Item type 2 | package stack 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/cheekybits/genny/generic" 8 | ) 9 | 10 | // Item the type of the stack 11 | type Item generic.Type 12 | 13 | // ItemStack the stack of Items 14 | type ItemStack struct { 15 | items []Item 16 | lock sync.RWMutex 17 | } 18 | 19 | // New creates a new ItemStack 20 | func (s *ItemStack) New() *ItemStack { 21 | s.items = []Item{} 22 | return s 23 | } 24 | 25 | // Push adds an Item to the top of the stack 26 | func (s *ItemStack) Push(t Item) { 27 | s.lock.Lock() 28 | s.items = append(s.items, t) 29 | s.lock.Unlock() 30 | } 31 | 32 | // Pop removes an Item from the top of the stack 33 | func (s *ItemStack) Pop() *Item { 34 | s.lock.Lock() 35 | item := s.items[len(s.items)-1] 36 | s.items = s.items[0 : len(s.items)-1] 37 | s.lock.Unlock() 38 | return &item 39 | } 40 | -------------------------------------------------------------------------------- /set/set_test.go: -------------------------------------------------------------------------------- 1 | package set 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func populateSet(count int, start int) *ItemSet { 9 | set := ItemSet{} 10 | for i := start; i < (start + count); i++ { 11 | set.Add(fmt.Sprintf("item%d", i)) 12 | } 13 | return &set 14 | } 15 | 16 | func TestAdd(t *testing.T) { 17 | set := populateSet(3, 0) 18 | if size := set.Size(); size != 3 { 19 | t.Errorf("wrong count, expected 3 and got %d", size) 20 | } 21 | set.Add("item1") //should not add it, already there 22 | if size := set.Size(); size != 3 { 23 | t.Errorf("wrong count, expected 3 and got %d", size) 24 | } 25 | set.Add("item4") //should not add it, already there 26 | if size := set.Size(); size != 4 { 27 | t.Errorf("wrong count, expected 4 and got %d", size) 28 | } 29 | } 30 | 31 | func TestClear(t *testing.T) { 32 | set := populateSet(3, 0) 33 | set.Clear() 34 | if size := set.Size(); size != 0 { 35 | t.Errorf("wrong count, expected 0 and got %d", size) 36 | } 37 | } 38 | 39 | func TestDelete(t *testing.T) { 40 | set := populateSet(3, 0) 41 | set.Delete("item2") 42 | if size := set.Size(); size != 2 { 43 | t.Errorf("wrong count, expected 2 and got %d", size) 44 | } 45 | } 46 | 47 | func TestHas(t *testing.T) { 48 | set := populateSet(3, 0) 49 | has := set.Has("item2") 50 | if !has { 51 | t.Errorf("expected item2 to be there") 52 | } 53 | set.Delete("item2") 54 | has = set.Has("item2") 55 | if has { 56 | t.Errorf("expected item2 to be removed") 57 | } 58 | set.Delete("item1") 59 | has = set.Has("item1") 60 | if has { 61 | t.Errorf("expected item1 to be removed") 62 | } 63 | } 64 | 65 | func TestItems(t *testing.T) { 66 | set := populateSet(3, 0) 67 | items := set.Items() 68 | if len(items) != 3 { 69 | t.Errorf("wrong count, expected 3 and got %d", len(items)) 70 | } 71 | set = populateSet(520, 0) 72 | items = set.Items() 73 | if len(items) != 520 { 74 | t.Errorf("wrong count, expected 520 and got %d", len(items)) 75 | } 76 | } 77 | 78 | func TestSize(t *testing.T) { 79 | set := populateSet(3, 0) 80 | items := set.Items() 81 | if len(items) != set.Size() { 82 | t.Errorf("wrong count, expected %d and got %d", set.Size(), len(items)) 83 | } 84 | set = populateSet(0, 0) 85 | items = set.Items() 86 | if len(items) != set.Size() { 87 | t.Errorf("wrong count, expected %d and got %d", set.Size(), len(items)) 88 | } 89 | set = populateSet(10000, 0) 90 | items = set.Items() 91 | if len(items) != set.Size() { 92 | t.Errorf("wrong count, expected %d and got %d", set.Size(), len(items)) 93 | } 94 | } 95 | 96 | func TestUnion(t *testing.T) { 97 | set1 := populateSet(3, 0) 98 | set2 := populateSet(2, 3) 99 | 100 | set3 := set1.Union(set2) 101 | 102 | if len(set3.Items()) != 5 { 103 | t.Errorf("wrong count, expected 5 and got %d", set3.Size()) 104 | } 105 | //don't edit original sets 106 | if len(set1.Items()) != 3 { 107 | t.Errorf("wrong count, expected 3 and got %d", set1.Size()) 108 | } 109 | if len(set2.Items()) != 2 { 110 | t.Errorf("wrong count, expected 2 and got %d", set2.Size()) 111 | } 112 | } 113 | 114 | func TestIntersection(t *testing.T) { 115 | set1 := populateSet(3, 0) 116 | set2 := populateSet(2, 0) 117 | 118 | set3 := set1.Intersection(set2) 119 | 120 | if len(set3.Items()) != 2 { 121 | t.Errorf("wrong count, expected 2 and got %d", set3.Size()) 122 | } 123 | //don't edit original sets 124 | if len(set1.Items()) != 3 { 125 | t.Errorf("wrong count, expected 3 and got %d", set1.Size()) 126 | } 127 | if len(set2.Items()) != 2 { 128 | t.Errorf("wrong count, expected 2 and got %d", set2.Size()) 129 | } 130 | } 131 | 132 | func TestDifference(t *testing.T) { 133 | set1 := populateSet(3, 0) 134 | set2 := populateSet(2, 0) 135 | 136 | set3 := set1.Difference(set2) 137 | 138 | if len(set3.Items()) != 1 { 139 | t.Errorf("wrong count, expected 2 and got %d", set3.Size()) 140 | } 141 | //don't edit original sets 142 | if len(set1.Items()) != 3 { 143 | t.Errorf("wrong count, expected 3 and got %d", set1.Size()) 144 | } 145 | if len(set2.Items()) != 2 { 146 | t.Errorf("wrong count, expected 2 and got %d", set2.Size()) 147 | } 148 | } 149 | 150 | func TestSubset(t *testing.T) { 151 | set1 := populateSet(3, 0) 152 | set2 := populateSet(2, 0) 153 | 154 | if set1.Subset(set2) { 155 | t.Errorf("expected false and got true") 156 | } 157 | 158 | //don't edit original sets 159 | if len(set1.Items()) != 3 { 160 | t.Errorf("wrong count, expected 3 and got %d", set1.Size()) 161 | } 162 | if len(set2.Items()) != 2 { 163 | t.Errorf("wrong count, expected 2 and got %d", set2.Size()) 164 | } 165 | 166 | //try real subsets 167 | set1 = populateSet(2, 0) 168 | if !set1.Subset(set2) { 169 | t.Errorf("expected true and got false") 170 | } 171 | 172 | set1 = populateSet(1, 0) 173 | if !set1.Subset(set2) { 174 | t.Errorf("expected true and got false") 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /stack/stack.go: -------------------------------------------------------------------------------- 1 | // Package stack creates a ItemStack data structure for the Item type 2 | package stack 3 | 4 | import ( 5 | "sync" 6 | 7 | "github.com/cheekybits/genny/generic" 8 | ) 9 | 10 | // Item the type of the stack 11 | type Item generic.Type 12 | 13 | // ItemStack the stack of Items 14 | type ItemStack struct { 15 | items []Item 16 | lock sync.RWMutex 17 | } 18 | 19 | // New creates a new ItemStack 20 | func (s *ItemStack) New() *ItemStack { 21 | s.items = []Item{} 22 | return s 23 | } 24 | 25 | // Push adds an Item to the top of the stack 26 | func (s *ItemStack) Push(t Item) { 27 | s.lock.Lock() 28 | s.items = append(s.items, t) 29 | s.lock.Unlock() 30 | } 31 | 32 | // Pop removes an Item from the top of the stack 33 | func (s *ItemStack) Pop() *Item { 34 | s.lock.Lock() 35 | item := s.items[len(s.items)-1] 36 | s.items = s.items[0 : len(s.items)-1] 37 | s.lock.Unlock() 38 | return &item 39 | } 40 | -------------------------------------------------------------------------------- /stack/stack_test.go: -------------------------------------------------------------------------------- 1 | package stack 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | var s ItemStack 8 | 9 | func initStack() *ItemStack { 10 | if s.items == nil { 11 | s = ItemStack{} 12 | s.New() 13 | } 14 | return &s 15 | } 16 | 17 | func TestPush(t *testing.T) { 18 | s := initStack() 19 | s.Push(1) 20 | s.Push(2) 21 | s.Push(3) 22 | if size := len(s.items); size != 3 { 23 | t.Errorf("wrong count, expected 3 and got %d", size) 24 | } 25 | } 26 | 27 | func TestPop(t *testing.T) { 28 | s.Pop() 29 | if size := len(s.items); size != 2 { 30 | t.Errorf("wrong count, expected 2 and got %d", size) 31 | } 32 | 33 | s.Pop() 34 | s.Pop() 35 | if size := len(s.items); size != 0 { 36 | t.Errorf("wrong count, expected 0 and got %d", size) 37 | } 38 | } 39 | --------------------------------------------------------------------------------