From 6db8b00768ea15dec33f439cad9f69f1b027e67f Mon Sep 17 00:00:00 2001 From: Mehdi Eidi Date: Sat, 6 Aug 2022 22:36:26 +0430 Subject: [PATCH] feat: add deque, tests, and docs --- README.md | 21 +++++++ deque.go | 67 +++++++++++++++++++++ deque_test.go | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++ doc.go | 2 + go.mod | 14 +++++ go.sum | 17 ++++++ 6 files changed, 285 insertions(+) create mode 100644 deque.go create mode 100644 deque_test.go create mode 100644 doc.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/README.md b/README.md index c4b9697..15a7ed6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,23 @@ # deque Library of generic deque data structure for Go. + +## Install + +```Go +$ go get github.com/golang-ds/deque +``` + +## Deque Usage + +### Import + +```Go +import "github.com/golang-ds/deque" +``` + +### Use + +```Go +d := deque.New[int]() +d.AddFirst(1) +``` diff --git a/deque.go b/deque.go new file mode 100644 index 0000000..4158dfa --- /dev/null +++ b/deque.go @@ -0,0 +1,67 @@ +package deque + +import "github.com/golang-ds/linkedlist/doubly" + +type Deque[T any] struct { + data doubly.LinkedList[T] +} + +// New constructs and returns an empty deque. +// time-complexity: O(1) +func New[T any]() Deque[T] { + return Deque[T]{data: doubly.New[T]()} +} + +// Size returns the number of the elements in the deque. +// time-complexity: O(1) +func (d *Deque[T]) Size() int { + return d.data.Size +} + +// IsEmpty returns true if the deque doesn't have any elements. +// time-complexity: O(1) +func (d *Deque[T]) IsEmpty() bool { + return d.Size() == 0 +} + +// First returns the first element in the deque. It returns false if the deque is empty. +// time-complexity: O(1) +func (d *Deque[T]) First() (T, bool) { + return d.data.First() +} + +// Last returns the last element in the deque. It returns false if the deque is empty. +// time-complexity: O(1) +func (d *Deque[T]) Last() (T, bool) { + return d.data.Last() +} + +// AddFirst adds an element to the front of the deque. +// time-complexity: O(1) +func (d *Deque[T]) AddFirst(data T) { + d.data.AddFirst(data) +} + +// AddLast adds an element to the end of the deque. +// time-complexity: O(1) +func (d *Deque[T]) AddLast(data T) { + d.data.AddLast(data) +} + +// RemoveFirst removes the first element from the deque and returns it. It returns false if the deque is empty. +// time-complexity: O(1) +func (d *Deque[T]) RemoveFirst() (T, bool) { + return d.data.RemoveFirst() +} + +// RemoveLast removes the last element from the deque and returns it. It returns false if the deque is empty. +// time-complexity: O(1) +func (d *Deque[T]) RemoveLast() (T, bool) { + return d.data.RemoveLast() +} + +// String returns the string representation of the deque. +// time-complexity: O(n) +func (d *Deque[T]) String() string { + return d.data.String() +} diff --git a/deque_test.go b/deque_test.go new file mode 100644 index 0000000..ddd223c --- /dev/null +++ b/deque_test.go @@ -0,0 +1,164 @@ +package deque + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSize(t *testing.T) { + deque := New[int]() + + s := deque.Size() + assert.Equal(t, 0, s) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + s = deque.Size() + assert.Equal(t, 4, s) +} + +func TestIsEmpty(t *testing.T) { + deque := New[int]() + + assert.True(t, deque.IsEmpty()) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + assert.False(t, deque.IsEmpty()) +} + +func TestFirst(t *testing.T) { + deque := New[int]() + + f, ok := deque.First() + assert.False(t, ok) + assert.Equal(t, 0, f) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + f, ok = deque.First() + assert.True(t, ok) + assert.Equal(t, 4, f) +} + +func TestLast(t *testing.T) { + deque := New[int]() + + l, ok := deque.Last() + assert.False(t, ok) + assert.Equal(t, 0, l) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + l, ok = deque.Last() + assert.True(t, ok) + assert.Equal(t, 1, l) +} + +func TestAddFirst(t *testing.T) { + deque := New[int]() + + f, ok := deque.First() + assert.False(t, ok) + assert.Equal(t, 0, f) + + deque.AddFirst(1) + deque.AddFirst(2) + + f, ok = deque.First() + assert.True(t, ok) + assert.Equal(t, 2, f) + + deque.AddFirst(3) + deque.AddFirst(4) + + f, ok = deque.First() + assert.True(t, ok) + assert.Equal(t, 4, f) +} + +func TestAddLast(t *testing.T) { + deque := New[int]() + + l, ok := deque.Last() + assert.False(t, ok) + assert.Equal(t, 0, l) + + deque.AddLast(1) + deque.AddLast(2) + + l, ok = deque.Last() + assert.True(t, ok) + assert.Equal(t, 2, l) + + deque.AddLast(3) + deque.AddLast(4) + + l, ok = deque.Last() + assert.True(t, ok) + assert.Equal(t, 4, l) +} + +func TestRemoveFirst(t *testing.T) { + deque := New[int]() + + f, ok := deque.RemoveFirst() + assert.False(t, ok) + assert.Equal(t, 0, f) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + f, ok = deque.RemoveFirst() + assert.True(t, ok) + assert.Equal(t, 4, f) +} + +func TestRemoveLast(t *testing.T) { + deque := New[int]() + + l, ok := deque.RemoveLast() + assert.False(t, ok) + assert.Equal(t, 0, l) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddFirst(4) + + l, ok = deque.RemoveLast() + assert.True(t, ok) + assert.Equal(t, 1, l) +} + +func TestString(t *testing.T) { + deque := New[int]() + + s := deque.String() + assert.Equal(t, "[ ]", s) + + deque.AddFirst(1) + deque.AddFirst(2) + deque.AddFirst(3) + deque.AddLast(10) + deque.AddLast(20) + deque.AddFirst(4) + + s = deque.String() + assert.Equal(t, "[ 4 3 2 1 10 20 ]", s) +} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..c5ebbdb --- /dev/null +++ b/doc.go @@ -0,0 +1,2 @@ +// Package deque implements a generic deque using a doubly-linked-list as the underlying data structure. +package deque diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..98b656a --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module github.com/golang-ds/deque + +go 1.18 + +require ( + github.com/golang-ds/linkedlist v1.0.0 + github.com/stretchr/testify v1.8.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..639268c --- /dev/null +++ b/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang-ds/linkedlist v1.0.0 h1:MrbDfIhQ9SL1my/siW/2va52kKO3IRCFdOa9EfzFFjM= +github.com/golang-ds/linkedlist v1.0.0/go.mod h1:oRpzIKkdhV7lom4F8dgjDgq+1LGWs37Lge55MwXwNi8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=