From 222ea6c374b56edba40b7bf88f75c3fd05a7e48d Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:15:29 +0330 Subject: [PATCH 1/7] Add queue interface --- queues/queues.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 queues/queues.go diff --git a/queues/queues.go b/queues/queues.go new file mode 100644 index 0000000..959a0a5 --- /dev/null +++ b/queues/queues.go @@ -0,0 +1,26 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package queues provides an abstract Queue interface. +// +// In computer science, a queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. By convention, the end of the sequence at which elements are added is called the back, tail, or rear of the queue, and the end at which elements are removed is called the head or front of the queue, analogously to the words used when people line up to wait for goods or services. +// The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without remove it. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package queues + +import "github.com/emirpasic/gods/containers" + +// Queue interface that all queues implement +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} +} From 386e3be5861f1464770530755b8969be9331e8ee Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:15:58 +0330 Subject: [PATCH 2/7] Add arrayqueue --- queues/arrayqueue/arrayqueue.go | 87 +++++++++ queues/arrayqueue/arrayqueue_test.go | 278 +++++++++++++++++++++++++++ queues/arrayqueue/iterator.go | 84 ++++++++ queues/arrayqueue/serialization.go | 22 +++ 4 files changed, 471 insertions(+) create mode 100644 queues/arrayqueue/arrayqueue.go create mode 100644 queues/arrayqueue/arrayqueue_test.go create mode 100644 queues/arrayqueue/iterator.go create mode 100644 queues/arrayqueue/serialization.go diff --git a/queues/arrayqueue/arrayqueue.go b/queues/arrayqueue/arrayqueue.go new file mode 100644 index 0000000..11bc995 --- /dev/null +++ b/queues/arrayqueue/arrayqueue.go @@ -0,0 +1,87 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package arrayqueue implements a queue backed by a array-list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package arrayqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/queues" +) + +func assertQueueImplementation() { + var _ queues.Queue = (*Queue)(nil) +} + +// Queue holds elements in an array-list +type Queue struct { + list *arraylist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: arraylist.New()} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + queue.list.Remove(0) + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "ArrayQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/arrayqueue/arrayqueue_test.go b/queues/arrayqueue/arrayqueue_test.go new file mode 100644 index 0000000..d86a3f0 --- /dev/null +++ b/queues/arrayqueue/arrayqueue_test.go @@ -0,0 +1,278 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import ( + "fmt" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIterator(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + // Iterator + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := queue.ToJSON() + assert() + + err = queue.FromJSON(json) + assert() +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkLinkedListQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkEnqueue(b, stack, size) +} + +func BenchmarkLinkedListQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/arrayqueue/iterator.go b/queues/arrayqueue/iterator.go new file mode 100644 index 0000000..5e41319 --- /dev/null +++ b/queues/arrayqueue/iterator.go @@ -0,0 +1,84 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// Next moves the iterator to the next element and returns true if there was a next element in the container. +// If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) // in order (FIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return iterator.index +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.queue.Size() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} diff --git a/queues/arrayqueue/serialization.go b/queues/arrayqueue/serialization.go new file mode 100644 index 0000000..45d554f --- /dev/null +++ b/queues/arrayqueue/serialization.go @@ -0,0 +1,22 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Queue)(nil) + var _ containers.JSONDeserializer = (*Queue)(nil) +} + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} From 327ef4525be9ba4157c58595a4d7b566b9c26531 Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:16:11 +0330 Subject: [PATCH 3/7] Add linkedlistqueue --- queues/linkedlistqueue/iterator.go | 60 ++++ queues/linkedlistqueue/linkedlistqueue.go | 87 ++++++ .../linkedlistqueue/linkedlistqueue_test.go | 278 ++++++++++++++++++ queues/linkedlistqueue/serialization.go | 22 ++ 4 files changed, 447 insertions(+) create mode 100644 queues/linkedlistqueue/iterator.go create mode 100644 queues/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/linkedlistqueue/linkedlistqueue_test.go create mode 100644 queues/linkedlistqueue/serialization.go diff --git a/queues/linkedlistqueue/iterator.go b/queues/linkedlistqueue/iterator.go new file mode 100644 index 0000000..82afb08 --- /dev/null +++ b/queues/linkedlistqueue/iterator.go @@ -0,0 +1,60 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +func assertIteratorImplementation() { + var _ containers.IteratorWithIndex = (*Iterator)(nil) +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// Next moves the iterator to the next element and returns true if there was a next element in the container. +// If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) // in order (FIFO) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return iterator.index +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} diff --git a/queues/linkedlistqueue/linkedlistqueue.go b/queues/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 0000000..d777a59 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue.go @@ -0,0 +1,87 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package linkedlistqueue implements a queue backed by a singly-linked list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package linkedlistqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/singlylinkedlist" + "github.com/emirpasic/gods/queues" +) + +func assertQueueImplementation() { + var _ queues.Queue = (*Queue)(nil) +} + +// Queue holds elements in a singly-linked-list +type Queue struct { + list *singlylinkedlist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: &singlylinkedlist.List{}} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + queue.list.Remove(0) + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "LinkedListQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/linkedlistqueue/linkedlistqueue_test.go b/queues/linkedlistqueue/linkedlistqueue_test.go new file mode 100644 index 0000000..fd640ce --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue_test.go @@ -0,0 +1,278 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import ( + "fmt" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIterator(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + // Iterator + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + json, err := queue.ToJSON() + assert() + + err = queue.FromJSON(json) + assert() +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkLinkedListQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + stack := New() + b.StartTimer() + benchmarkEnqueue(b, stack, size) +} + +func BenchmarkLinkedListQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkLinkedListQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/linkedlistqueue/serialization.go b/queues/linkedlistqueue/serialization.go new file mode 100644 index 0000000..ccd1038 --- /dev/null +++ b/queues/linkedlistqueue/serialization.go @@ -0,0 +1,22 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Queue)(nil) + var _ containers.JSONDeserializer = (*Queue)(nil) +} + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} From b2f992450dd0503d6ab42feb3556cc6fc17367c5 Mon Sep 17 00:00:00 2001 From: AryanAhadinia Date: Wed, 13 Jan 2021 23:17:01 +0330 Subject: [PATCH 4/7] Add queue to README --- README.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/README.md b/README.md index 7346b99..dd11033 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Implementation of various data structures and algorithms in Go. - [ArrayList](#arraylist) - [SinglyLinkedList](#singlylinkedlist) - [DoublyLinkedList](#doublylinkedlist) + - [Queues](#queues) + - [LinkedListQueue](#linkedlistqueue) + - [ArrayQueue](#arrayqueue) - [Sets](#sets) - [HashSet](#hashset) - [TreeSet](#treeset) @@ -68,6 +71,9 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [ArrayList](#arraylist) | yes | yes* | yes | index | | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | +| [Queues](#queues) | +| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | +| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | | [Sets](#sets) | | | [HashSet](#hashset) | no | no | no | index | | | [TreeSet](#treeset) | yes | yes* | yes | index | @@ -400,6 +406,80 @@ func main() { } ``` +### Queues + +A queue that represents a first-in-first-out (FIFO) data structure. The usual enqueue and dequeue operations are provided, as well as a method to peek at the first item in the queue. + +Implements [Container](#containers) interface. + +```go +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} +} +``` + +#### LinkedListQueue + +A [queue](#queues) based on a [linked list](#singlylinkedlist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import ll1 "github.com/emirpasic/gods/stacks/linkedlistqueue" + +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Values() // 1, 2 + _, _ = queue.Peek() // 1, true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + queue.Size() // 0 +} +``` + +#### ArrayStack + +A [queue](#queues) based on a [array list](#arraylist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import ll1 "github.com/emirpasic/gods/stacks/linkedlistqueue" + +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + queue.Values() // 1, 2 + _, _ = queue.Peek() // 1, true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + queue.Size() // 0 +} +``` + ### Maps A Map is a data structure that maps keys to values. A map cannot contain duplicate keys and each key can map to at most one value. From 3c9a1ea06fc4a088542304040693fc13c6c1e876 Mon Sep 17 00:00:00 2001 From: Aryan Ahadinia <62179268+AryanAhadinia@users.noreply.github.com> Date: Wed, 20 Jan 2021 11:37:49 +0330 Subject: [PATCH 5/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd11033..ca68aa1 100644 --- a/README.md +++ b/README.md @@ -453,7 +453,7 @@ func main() { } ``` -#### ArrayStack +#### ArrayQueue A [queue](#queues) based on a [array list](#arraylist). From 6bf61e32bee262e5cc97231fc29bc22c17a7e59a Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 23:05:57 +0200 Subject: [PATCH 6/7] Implements queues, LinkedListQueue and ArrayQueue --- README.md | 99 +++- examples/arrayqueue/arrayqqueue.go | 23 + examples/linkedlistqueue/linkedlistqueue.go | 23 + queues/arrayqueue/arrayqueue.go | 88 ++++ queues/arrayqueue/arrayqueue_test.go | 494 ++++++++++++++++++ queues/arrayqueue/iterator.go | 111 ++++ queues/arrayqueue/serialization.go | 33 ++ queues/linkedlistqueue/iterator.go | 73 +++ queues/linkedlistqueue/linkedlistqueue.go | 88 ++++ .../linkedlistqueue/linkedlistqueue_test.go | 357 +++++++++++++ queues/linkedlistqueue/serialization.go | 33 ++ queues/queues.go | 27 + 12 files changed, 1442 insertions(+), 7 deletions(-) create mode 100644 examples/arrayqueue/arrayqqueue.go create mode 100644 examples/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/arrayqueue/arrayqueue.go create mode 100644 queues/arrayqueue/arrayqueue_test.go create mode 100644 queues/arrayqueue/iterator.go create mode 100644 queues/arrayqueue/serialization.go create mode 100644 queues/linkedlistqueue/iterator.go create mode 100644 queues/linkedlistqueue/linkedlistqueue.go create mode 100644 queues/linkedlistqueue/linkedlistqueue_test.go create mode 100644 queues/linkedlistqueue/serialization.go create mode 100644 queues/queues.go diff --git a/README.md b/README.md index 4681210..3572348 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,9 @@ Implementation of various data structures and algorithms in Go. - [AVLTree](#avltree) - [BTree](#btree) - [BinaryHeap](#binaryheap) + - [Queues](#queues) + - [LinkedListQueue](#linkedlistqueue) + - [ArrayQueue](#arrayqueue) - [Functions](#functions) - [Comparator](#comparator) - [Iterator](#iterator) @@ -94,6 +97,9 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [AVLTree](#avltree) | yes | yes* | no | key | | | [BTree](#btree) | yes | yes* | no | key | | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | +| [Queues](#queues) | +| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | +| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | | | | | *reversible | | *bidirectional | ### Lists @@ -126,7 +132,7 @@ type List interface { A [list](#lists) backed by a dynamic array that grows and shrinks implicitly. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -200,7 +206,7 @@ func main() { A [list](#lists) where each element points to the next and previous elements in the list. -Implements [List](#lists), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [List](#lists), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -290,7 +296,7 @@ func main() { A [set](#sets) backed by a [red-black tree](#redblacktree) to keep the elements ordered with respect to the [comparator](#comparator). -Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -317,7 +323,7 @@ func main() { A [set](#sets) that preserves insertion-order. Data structure is backed by a hash table to store values and [doubly-linked list](#doublylinkedlist) to store insertion ordering. -Implements [Set](#sets), [IteratorWithIndex](#iteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Set](#sets), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithIndex](#enumerablewithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -479,7 +485,7 @@ func main() { A [map](#maps) based on [red-black tree](#redblacktree). Keys are ordered with respect to the [comparator](#comparator). -Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -510,7 +516,7 @@ func main() { A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering. -Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [Map](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -567,7 +573,7 @@ func main() { A [map](#maps) based on red-black tree. This map guarantees that the map will be in both ascending key and value order. Other than key and value ordering, the goal with this structure is to avoid duplication of elements (unlike in [HashBidiMap](#hashbidimap)), which can be significant if contained elements are large. -Implements [BidiMap](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. +Implements [BidiMap](#maps), [ReverseIteratorWithIndex](#reverseiteratorwithindex), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. ```go package main @@ -864,6 +870,85 @@ func main() { } ``` +### Queues + +A queue that represents a first-in-first-out (FIFO) data structure. The usual enqueue and dequeue operations are provided, as well as a method to peek at the first item in the queue. + +

+ +Implements [Container](#containers) interface. + +```go +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} + // String() string +} +``` + +#### LinkedListQueue + +A [queue](#queues) based on a [linked list](#singlylinkedlist). + +Implements [Queue](#queues), [IteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import llq "github.com/emirpasic/gods/queues/linkedlistqueue" + +// LinkedListQueueExample to demonstrate basic usage of LinkedListQueue +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} +``` + +#### ArrayQueue + +A [queue](#queues) based on a [array list](#arraylist). + +Implements [Queue](#queues), [ReverseIteratorWithIndex](#iteratorwithindex), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import aq "github.com/emirpasic/gods/queues/arrayqueue" + +// ArrayQueueExample to demonstrate basic usage of ArrayQueue +func main() { + queue := aq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} +``` + ## Functions Various helper functions used throughout the library. diff --git a/examples/arrayqueue/arrayqqueue.go b/examples/arrayqueue/arrayqqueue.go new file mode 100644 index 0000000..13b8818 --- /dev/null +++ b/examples/arrayqueue/arrayqqueue.go @@ -0,0 +1,23 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import aq "github.com/emirpasic/gods/queues/arrayqueue" + +// ArrayQueueExample to demonstrate basic usage of ArrayQueue +func main() { + queue := aq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} diff --git a/examples/linkedlistqueue/linkedlistqueue.go b/examples/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 0000000..d6800b5 --- /dev/null +++ b/examples/linkedlistqueue/linkedlistqueue.go @@ -0,0 +1,23 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import llq "github.com/emirpasic/gods/queues/linkedlistqueue" + +// LinkedListQueueExample to demonstrate basic usage of LinkedListQueue +func main() { + queue := llq.New() // empty + queue.Enqueue(1) // 1 + queue.Enqueue(2) // 1, 2 + _ = queue.Values() // 1, 2 (FIFO order) + _, _ = queue.Peek() // 1,true + _, _ = queue.Dequeue() // 1, true + _, _ = queue.Dequeue() // 2, true + _, _ = queue.Dequeue() // nil, false (nothing to deque) + queue.Enqueue(1) // 1 + queue.Clear() // empty + queue.Empty() // true + _ = queue.Size() // 0 +} diff --git a/queues/arrayqueue/arrayqueue.go b/queues/arrayqueue/arrayqueue.go new file mode 100644 index 0000000..8d480e9 --- /dev/null +++ b/queues/arrayqueue/arrayqueue.go @@ -0,0 +1,88 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package arrayqueue implements a queue backed by array list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package arrayqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/arraylist" + "github.com/emirpasic/gods/queues" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds elements in an array-list +type Queue struct { + list *arraylist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: arraylist.New()} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + if ok { + queue.list.Remove(0) + } + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "ArrayQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/arrayqueue/arrayqueue_test.go b/queues/arrayqueue/arrayqueue_test.go new file mode 100644 index 0000000..b704dbf --- /dev/null +++ b/queues/arrayqueue/arrayqueue_test.go @@ -0,0 +1,494 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import ( + "encoding/json" + "fmt" + "strings" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIteratorOnEmpty(t *testing.T) { + queue := New() + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorNext(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorPrev(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + for it.Next() { + } + count := 0 + for it.Prev() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, 3-count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorEnd(t *testing.T) { + queue := New() + it := queue.Iterator() + + if index := it.Index(); index != -1 { + t.Errorf("Got %v expected %v", index, -1) + } + + it.End() + if index := it.Index(); index != 0 { + t.Errorf("Got %v expected %v", index, 0) + } + + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + it.End() + if index := it.Index(); index != queue.Size() { + t.Errorf("Got %v expected %v", index, queue.Size()) + } + + it.Prev() + if index, value := it.Index(), it.Value(); index != queue.Size()-1 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, queue.Size()-1, "c") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorLast(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.Last(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 2 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "c") + } +} + +func TestQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + queue := New() + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestQueueIteratorPrevTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // PrevTo (empty) + { + queue := New() + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + it.End() + for it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // PrevTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.End() + if !it.PrevTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Prev() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 0 || value.(string) != "aa" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "aa") + } + if it.Prev() { + t.Errorf("Should not go before first element") + } + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestQueueString(t *testing.T) { + c := New() + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "ArrayQueue") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkArrayQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/arrayqueue/iterator.go b/queues/arrayqueue/iterator.go new file mode 100644 index 0000000..51a30f9 --- /dev/null +++ b/queues/arrayqueue/iterator.go @@ -0,0 +1,111 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import "github.com/emirpasic/gods/containers" + +// Assert Iterator implementation +var _ containers.ReverseIteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// Next moves the iterator to the next element and returns true if there was a next element in the container. +// If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + if iterator.index >= 0 { + iterator.index-- + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return iterator.index +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.index = iterator.queue.Size() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + iterator.End() + return iterator.Prev() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// passed function, and returns true if there was a next element in the container. +// If NextTo() returns true, then next element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} + +// PrevTo moves the iterator to the previous element from current position that satisfies the condition given by the +// passed function, and returns true if there was a next element in the container. +// If PrevTo() returns true, then next element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) PrevTo(f func(index int, value interface{}) bool) bool { + for iterator.Prev() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/queues/arrayqueue/serialization.go b/queues/arrayqueue/serialization.go new file mode 100644 index 0000000..a33a82f --- /dev/null +++ b/queues/arrayqueue/serialization.go @@ -0,0 +1,33 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arrayqueue + +import ( + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} diff --git a/queues/linkedlistqueue/iterator.go b/queues/linkedlistqueue/iterator.go new file mode 100644 index 0000000..cf47b19 --- /dev/null +++ b/queues/linkedlistqueue/iterator.go @@ -0,0 +1,73 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import "github.com/emirpasic/gods/containers" + +// Assert Iterator implementation +var _ containers.IteratorWithIndex = (*Iterator)(nil) + +// Iterator returns a stateful iterator whose values can be fetched by an index. +type Iterator struct { + queue *Queue + index int +} + +// Iterator returns a stateful iterator whose values can be fetched by an index. +func (queue *Queue) Iterator() Iterator { + return Iterator{queue: queue, index: -1} +} + +// Next moves the iterator to the next element and returns true if there was a next element in the container. +// If Next() returns true, then next element's index and value can be retrieved by Index() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + if iterator.index < iterator.queue.Size() { + iterator.index++ + } + return iterator.queue.withinRange(iterator.index) +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + value, _ := iterator.queue.list.Get(iterator.index) + return value +} + +// Index returns the current element's index. +// Does not modify the state of the iterator. +func (iterator *Iterator) Index() int { + return iterator.index +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.index = -1 +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) First() bool { + iterator.Begin() + return iterator.Next() +} + +// NextTo moves the iterator to the next element from current position that satisfies the condition given by the +// passed function, and returns true if there was a next element in the container. +// If NextTo() returns true, then next element's index and value can be retrieved by Index() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) NextTo(f func(index int, value interface{}) bool) bool { + for iterator.Next() { + index, value := iterator.Index(), iterator.Value() + if f(index, value) { + return true + } + } + return false +} diff --git a/queues/linkedlistqueue/linkedlistqueue.go b/queues/linkedlistqueue/linkedlistqueue.go new file mode 100644 index 0000000..fdb9463 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue.go @@ -0,0 +1,88 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package linkedlistqueue implements a queue backed by a singly-linked list. +// +// Structure is not thread safe. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package linkedlistqueue + +import ( + "fmt" + "strings" + + "github.com/emirpasic/gods/lists/singlylinkedlist" + "github.com/emirpasic/gods/queues" +) + +// Assert Queue implementation +var _ queues.Queue = (*Queue)(nil) + +// Queue holds elements in a singly-linked-list +type Queue struct { + list *singlylinkedlist.List +} + +// New instantiates a new empty queue +func New() *Queue { + return &Queue{list: &singlylinkedlist.List{}} +} + +// Enqueue adds a value to the end of the queue +func (queue *Queue) Enqueue(value interface{}) { + queue.list.Add(value) +} + +// Dequeue removes first element of the queue and returns it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to dequeue. +func (queue *Queue) Dequeue() (value interface{}, ok bool) { + value, ok = queue.list.Get(0) + if ok { + queue.list.Remove(0) + } + return +} + +// Peek returns first element of the queue without removing it, or nil if queue is empty. +// Second return parameter is true, unless the queue was empty and there was nothing to peek. +func (queue *Queue) Peek() (value interface{}, ok bool) { + return queue.list.Get(0) +} + +// Empty returns true if queue does not contain any elements. +func (queue *Queue) Empty() bool { + return queue.list.Empty() +} + +// Size returns number of elements within the queue. +func (queue *Queue) Size() int { + return queue.list.Size() +} + +// Clear removes all elements from the queue. +func (queue *Queue) Clear() { + queue.list.Clear() +} + +// Values returns all elements in the queue (FIFO order). +func (queue *Queue) Values() []interface{} { + return queue.list.Values() +} + +// String returns a string representation of container +func (queue *Queue) String() string { + str := "LinkedListQueue\n" + values := []string{} + for _, value := range queue.list.Values() { + values = append(values, fmt.Sprintf("%v", value)) + } + str += strings.Join(values, ", ") + return str +} + +// Check that the index is within bounds of the list +func (queue *Queue) withinRange(index int) bool { + return index >= 0 && index < queue.list.Size() +} diff --git a/queues/linkedlistqueue/linkedlistqueue_test.go b/queues/linkedlistqueue/linkedlistqueue_test.go new file mode 100644 index 0000000..e8e7c74 --- /dev/null +++ b/queues/linkedlistqueue/linkedlistqueue_test.go @@ -0,0 +1,357 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import ( + "encoding/json" + "fmt" + "strings" + "testing" +) + +func TestQueueEnqueue(t *testing.T) { + queue := New() + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + + if actualValue := queue.Values(); actualValue[0].(int) != 1 || actualValue[1].(int) != 2 || actualValue[2].(int) != 3 { + t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") + } + if actualValue := queue.Empty(); actualValue != false { + t.Errorf("Got %v expected %v", actualValue, false) + } + if actualValue := queue.Size(); actualValue != 3 { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueuePeek(t *testing.T) { + queue := New() + if actualValue, ok := queue.Peek(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + if actualValue, ok := queue.Peek(); actualValue != 1 || !ok { + t.Errorf("Got %v expected %v", actualValue, 1) + } +} + +func TestQueueDequeue(t *testing.T) { + queue := New() + queue.Enqueue(1) + queue.Enqueue(2) + queue.Enqueue(3) + queue.Dequeue() + if actualValue, ok := queue.Peek(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 2 || !ok { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, ok := queue.Dequeue(); actualValue != 3 || !ok { + t.Errorf("Got %v expected %v", actualValue, 3) + } + if actualValue, ok := queue.Dequeue(); actualValue != nil || ok { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue := queue.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } + if actualValue := queue.Values(); len(actualValue) != 0 { + t.Errorf("Got %v expected %v", actualValue, "[]") + } +} + +func TestQueueIteratorOnEmpty(t *testing.T) { + queue := New() + it := queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorNext(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + it := queue.Iterator() + count := 0 + for it.Next() { + count++ + index := it.Index() + value := it.Value() + switch index { + case 0: + if actualValue, expectedValue := value, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 1: + if actualValue, expectedValue := value, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := value, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := index, count-1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + queue.Clear() + it = queue.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty queue") + } +} + +func TestQueueIteratorBegin(t *testing.T) { + queue := New() + it := queue.Iterator() + it.Begin() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + for it.Next() { + } + it.Begin() + it.Next() + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorFirst(t *testing.T) { + queue := New() + it := queue.Iterator() + if actualValue, expectedValue := it.First(), false; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if index, value := it.Index(), it.Value(); index != 0 || value != "a" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 0, "a") + } +} + +func TestQueueIteratorNextTo(t *testing.T) { + // Sample seek function, i.e. string starting with "b" + seek := func(index int, value interface{}) bool { + return strings.HasSuffix(value.(string), "b") + } + + // NextTo (empty) + { + queue := New() + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (not found) + { + queue := New() + queue.Enqueue("xx") + queue.Enqueue("yy") + it := queue.Iterator() + for it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + } + + // NextTo (found) + { + queue := New() + queue.Enqueue("aa") + queue.Enqueue("bb") + queue.Enqueue("cc") + it := queue.Iterator() + it.Begin() + if !it.NextTo(seek) { + t.Errorf("Shouldn't iterate on empty queue") + } + if index, value := it.Index(), it.Value(); index != 1 || value.(string) != "bb" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 1, "bb") + } + if !it.Next() { + t.Errorf("Should go to first element") + } + if index, value := it.Index(), it.Value(); index != 2 || value.(string) != "cc" { + t.Errorf("Got %v,%v expected %v,%v", index, value, 2, "cc") + } + if it.Next() { + t.Errorf("Should not go past last element") + } + } +} + +func TestQueueSerialization(t *testing.T) { + queue := New() + queue.Enqueue("a") + queue.Enqueue("b") + queue.Enqueue("c") + + var err error + assert := func() { + if actualValue, expectedValue := fmt.Sprintf("%s%s%s", queue.Values()...), "abc"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := queue.Size(), 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if err != nil { + t.Errorf("Got error %v", err) + } + } + + assert() + + bytes, err := queue.ToJSON() + assert() + + err = queue.FromJSON(bytes) + assert() + + bytes, err = json.Marshal([]interface{}{"a", "b", "c", queue}) + if err != nil { + t.Errorf("Got error %v", err) + } + + err = json.Unmarshal([]byte(`[1,2,3]`), &queue) + if err != nil { + t.Errorf("Got error %v", err) + } +} + +func TestQueueString(t *testing.T) { + c := New() + c.Enqueue(1) + if !strings.HasPrefix(c.String(), "LinkedListQueue") { + t.Errorf("String should start with container name") + } +} + +func benchmarkEnqueue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + } +} + +func benchmarkDequeue(b *testing.B, queue *Queue, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + queue.Dequeue() + } + } +} + +func BenchmarkArrayQueueDequeue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueDequeue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkDequeue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100(b *testing.B) { + b.StopTimer() + size := 100 + queue := New() + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue1000(b *testing.B) { + b.StopTimer() + size := 1000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue10000(b *testing.B) { + b.StopTimer() + size := 10000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} + +func BenchmarkArrayQueueEnqueue100000(b *testing.B) { + b.StopTimer() + size := 100000 + queue := New() + for n := 0; n < size; n++ { + queue.Enqueue(n) + } + b.StartTimer() + benchmarkEnqueue(b, queue, size) +} diff --git a/queues/linkedlistqueue/serialization.go b/queues/linkedlistqueue/serialization.go new file mode 100644 index 0000000..2b34c8e --- /dev/null +++ b/queues/linkedlistqueue/serialization.go @@ -0,0 +1,33 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedlistqueue + +import ( + "github.com/emirpasic/gods/containers" +) + +// Assert Serialization implementation +var _ containers.JSONSerializer = (*Queue)(nil) +var _ containers.JSONDeserializer = (*Queue)(nil) + +// ToJSON outputs the JSON representation of the queue. +func (queue *Queue) ToJSON() ([]byte, error) { + return queue.list.ToJSON() +} + +// FromJSON populates the queue from the input JSON representation. +func (queue *Queue) FromJSON(data []byte) error { + return queue.list.FromJSON(data) +} + +// UnmarshalJSON @implements json.Unmarshaler +func (queue *Queue) UnmarshalJSON(bytes []byte) error { + return queue.FromJSON(bytes) +} + +// MarshalJSON @implements json.Marshaler +func (queue *Queue) MarshalJSON() ([]byte, error) { + return queue.ToJSON() +} diff --git a/queues/queues.go b/queues/queues.go new file mode 100644 index 0000000..80239d4 --- /dev/null +++ b/queues/queues.go @@ -0,0 +1,27 @@ +// Copyright (c) 2021, Aryan Ahadinia. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package queues provides an abstract Queue interface. +// +// In computer science, a queue is a collection of entities that are maintained in a sequence and can be modified by the addition of entities at one end of the sequence and the removal of entities from the other end of the sequence. By convention, the end of the sequence at which elements are added is called the back, tail, or rear of the queue, and the end at which elements are removed is called the head or front of the queue, analogously to the words used when people line up to wait for goods or services. +// The operation of adding an element to the rear of the queue is known as enqueue, and the operation of removing an element from the front is known as dequeue. Other operations may also be allowed, often including a peek or front operation that returns the value of the next element to be dequeued without remove it. +// +// Reference: https://en.wikipedia.org/wiki/Queue_(abstract_data_type) +package queues + +import "github.com/emirpasic/gods/containers" + +// Queue interface that all queues implement +type Queue interface { + Enqueue(value interface{}) + Dequeue() (value interface{}, ok bool) + Peek() (value interface{}, ok bool) + + containers.Container + // Empty() bool + // Size() int + // Clear() + // Values() []interface{} + // String() string +} From 5b2385446eb64b06747c2985bc00490999fc6c73 Mon Sep 17 00:00:00 2001 From: Emir Pasic Date: Wed, 13 Apr 2022 23:14:04 +0200 Subject: [PATCH 7/7] Documentation fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3572348..0c7b25b 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ Containers are either ordered or unordered. All ordered containers provide [stat | | [BTree](#btree) | yes | yes* | no | key | | | [BinaryHeap](#binaryheap) | yes | yes* | no | index | | [Queues](#queues) | -| | [LinkedListQueues](#linkedlistqueues) | yes | yes | no | index | -| | [ArrayQueues](#arrayqueues) | yes | yes* | no | index | +| | [LinkedListQueue](#linkedlistqueue) | yes | yes | no | index | +| | [ArrayQueue](#arrayqueue) | yes | yes* | no | index | | | | | *reversible | | *bidirectional | ### Lists