bag, queue
This commit is contained in:
parent
6f9dc7b91b
commit
a35bb36872
4 changed files with 181 additions and 0 deletions
51
fundamentals/bag/bag.go
Normal file
51
fundamentals/bag/bag.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package bag
|
||||
|
||||
// "Generic" item.
|
||||
// When type parameters will land this type became
|
||||
// type Item[T any] T
|
||||
type Item interface{}
|
||||
|
||||
type Bag interface {
|
||||
Add(Item)
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
ForEach(func(Item))
|
||||
}
|
||||
|
||||
// We use linked list as internal data structure
|
||||
// to get O(1) speed for Add operation
|
||||
type node struct {
|
||||
item Item
|
||||
next *node
|
||||
}
|
||||
|
||||
type bag struct {
|
||||
size int
|
||||
head *node
|
||||
}
|
||||
|
||||
func NewBag() Bag {
|
||||
return &bag{}
|
||||
}
|
||||
|
||||
func (b *bag) Add(item Item) {
|
||||
next := b.head
|
||||
b.head = &node{item, next}
|
||||
b.size++
|
||||
}
|
||||
|
||||
func (b *bag) Size() int {
|
||||
return b.size
|
||||
}
|
||||
|
||||
func (b *bag) IsEmpty() bool {
|
||||
return b.size == 0
|
||||
}
|
||||
|
||||
// As for now Go doesn't have iterators.
|
||||
// But we can simulate them with ForEach method
|
||||
func (b *bag) ForEach(f func(Item)) {
|
||||
for current := b.head; current != nil; current = current.next {
|
||||
f(current.item)
|
||||
}
|
||||
}
|
36
fundamentals/bag/bag_test.go
Normal file
36
fundamentals/bag/bag_test.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package bag
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
bag := NewBag()
|
||||
sum := 0
|
||||
|
||||
bag.Add(1)
|
||||
bag.Add(2)
|
||||
bag.Add(3)
|
||||
|
||||
bag.ForEach(func(i Item) { sum += i.(int) })
|
||||
|
||||
if sum != 6 {
|
||||
log.Fatal("wrong items in bag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
bag := NewBag()
|
||||
sum := 0
|
||||
|
||||
if bag.Size() != 0 || !bag.IsEmpty() {
|
||||
log.Fatal("bag should be empty")
|
||||
}
|
||||
|
||||
bag.ForEach(func(i Item) { sum += i.(int) })
|
||||
|
||||
if sum != 0 {
|
||||
log.Fatal("wrong items in bag")
|
||||
}
|
||||
}
|
59
fundamentals/queue/queue.go
Normal file
59
fundamentals/queue/queue.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package queue
|
||||
|
||||
// "Generic" item.
|
||||
// When type parameters will land this type became
|
||||
// type Item[T any] T
|
||||
type Item interface{}
|
||||
|
||||
type Queue interface {
|
||||
Enqueue(Item)
|
||||
Dequeue() Item
|
||||
Size() int
|
||||
IsEmpty() bool
|
||||
}
|
||||
|
||||
// We use linked list as internal data structure
|
||||
// to get O(1) speed for push and pop opeartions
|
||||
type node struct {
|
||||
item Item
|
||||
next *node
|
||||
}
|
||||
|
||||
type queue struct {
|
||||
size int
|
||||
head *node
|
||||
tail *node
|
||||
}
|
||||
|
||||
func NewQueue() Queue {
|
||||
return &queue{}
|
||||
}
|
||||
|
||||
func (q *queue) Enqueue(item Item) {
|
||||
oldTail := q.tail
|
||||
q.tail = &node{item: item, next: nil}
|
||||
if q.IsEmpty() {
|
||||
q.head = q.tail
|
||||
} else {
|
||||
oldTail.next = q.tail
|
||||
}
|
||||
q.size++
|
||||
}
|
||||
|
||||
func (q *queue) Dequeue() Item {
|
||||
first := q.head
|
||||
q.head = q.head.next
|
||||
if q.IsEmpty() {
|
||||
q.tail = nil
|
||||
}
|
||||
q.size--
|
||||
return first.item
|
||||
}
|
||||
|
||||
func (q *queue) Size() int {
|
||||
return q.size
|
||||
}
|
||||
|
||||
func (q *queue) IsEmpty() bool {
|
||||
return q.head == nil
|
||||
}
|
35
fundamentals/queue/queue_test.go
Normal file
35
fundamentals/queue/queue_test.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package queue
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
queue := NewQueue()
|
||||
|
||||
queue.Enqueue(10)
|
||||
queue.Enqueue(20)
|
||||
queue.Enqueue(30)
|
||||
|
||||
first, second := queue.Dequeue().(int), queue.Dequeue().(int)
|
||||
|
||||
if first != 10 && second != 20 {
|
||||
log.Fatal("wrong order")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
queue := NewQueue()
|
||||
|
||||
if queue.Size() != 0 {
|
||||
log.Fatal("empty queue should have size 0")
|
||||
}
|
||||
queue.Enqueue(10)
|
||||
queue.Enqueue(20)
|
||||
queue.Enqueue(30)
|
||||
|
||||
if queue.Size() != 3 {
|
||||
log.Fatal("wrong size")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue