From d872d64fe0a0517d9a0232901f79096b36dba775 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Tue, 15 Feb 2022 10:34:14 +0800 Subject: [PATCH] feat: add CircularQueue --- datastructure/queue/circularqueue.go | 119 +++++++++++++++++ datastructure/queue/circularqueue_test.go | 148 ++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 datastructure/queue/circularqueue.go create mode 100644 datastructure/queue/circularqueue_test.go diff --git a/datastructure/queue/circularqueue.go b/datastructure/queue/circularqueue.go new file mode 100644 index 0000000..04ead3a --- /dev/null +++ b/datastructure/queue/circularqueue.go @@ -0,0 +1,119 @@ +package datastructure + +import ( + "errors" + "fmt" + "reflect" +) + +// CircularQueue implements circular queue with slice, +// last index of CircularQueue don't contain value, so acturl capacity is size - 1 +type CircularQueue[T any] struct { + data []T + front int + rear int + size int +} + +// NewCircularQueue return a empty CircularQueue pointer +func NewCircularQueue[T any](size int) *CircularQueue[T] { + data := make([]T, size) + return &CircularQueue[T]{data: data, front: 0, rear: 0, size: size} +} + +// Data return queue data +func (q *CircularQueue[T]) Data() []T { + data := []T{} + + front := q.front + rear := q.rear + if front <= rear { + return q.data[front:rear] + } + + data = append(data, q.data[front:]...) + data = append(data, q.data[0:rear]...) + + return data +} + +// Length return current data length of queue +func (q *CircularQueue[T]) Length() int { + if q.size == 0 { + return 0 + } + return (q.rear - q.front + q.size) % q.size +} + +// IsEmpty checks if queue is empty or not +func (q *CircularQueue[T]) IsEmpty() bool { + return q.front == q.rear +} + +// IsFull checks if queue is full or not +func (q *CircularQueue[T]) IsFull() bool { + return (q.rear+1)%q.size == q.front +} + +// Front return front value of queue +func (q *CircularQueue[T]) Front() T { + return q.data[q.front] +} + +// Back return back value of queue +func (q *CircularQueue[T]) Back() T { + if q.rear-1 >= 0 { + return q.data[q.rear-1] + } + return q.data[q.size-1] +} + +// EnQueue put element into queue +func (q *CircularQueue[T]) EnQueue(value T) error { + if q.IsFull() { + return errors.New("queue is full!") + } + + q.data[q.rear] = value + // q.data = append(q.data, value) + q.rear = (q.rear + 1) % q.size + + return nil +} + +// DeQueue remove head element of queue and return it, if queue is empty, return nil and error +func (q *CircularQueue[T]) DeQueue() (*T, error) { + if q.IsEmpty() { + return nil, errors.New("queue is empty") + } + + headItem := q.data[q.front] + var t T + q.data[q.front] = t + q.front = (q.front + 1) % q.size + + return &headItem, nil +} + +// Clear the queue data +func (q *CircularQueue[T]) Clear() { + q.data = []T{} + q.front = 0 + q.rear = 0 + q.size = 0 +} + +// Contain checks if the value is in queue or not +func (q *CircularQueue[T]) Contain(value T) bool { + for _, v := range q.data { + if reflect.DeepEqual(v, value) { + return true + } + } + return false +} + +// Print queue data +func (q *CircularQueue[T]) Print() { + fmt.Printf("%+v\n", q) +} diff --git a/datastructure/queue/circularqueue_test.go b/datastructure/queue/circularqueue_test.go new file mode 100644 index 0000000..5e04c61 --- /dev/null +++ b/datastructure/queue/circularqueue_test.go @@ -0,0 +1,148 @@ +package datastructure + +import ( + "testing" + + "github.com/duke-git/lancet/internal" +) + +func TestCircularQueue_EnQueue(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_EnQueue") + + queue := NewCircularQueue[int](6) + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + queue.EnQueue(4) + queue.EnQueue(5) + + queue.Print() + // assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data()) + assert.Equal(5, queue.Length()) + + err := queue.EnQueue(6) + assert.IsNotNil(err) +} + +func TestCircularQueue_DeQueue(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_DeQueue") + + queue := NewCircularQueue[int](6) + assert.Equal(true, queue.IsEmpty()) + + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + queue.EnQueue(4) + queue.EnQueue(5) + + val, err := queue.DeQueue() + assert.IsNil(err) + + assert.Equal(1, *val) + assert.Equal(false, queue.IsFull()) + + val, _ = queue.DeQueue() + queue.Print() + assert.Equal(2, *val) + + queue.EnQueue(6) + queue.Print() + assert.Equal(false, queue.IsFull()) +} + +func TestCircularQueue_Front(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_Front") + + queue := NewCircularQueue[int](6) + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + queue.EnQueue(4) + queue.EnQueue(5) + + queue.Print() + + queue.DeQueue() + queue.DeQueue() + queue.EnQueue(6) + queue.EnQueue(7) + + queue.Print() + + val := queue.Front() + assert.Equal(3, val) + assert.Equal(5, queue.Length()) +} + +func TestCircularQueue_Back(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_Back") + + queue := NewCircularQueue[int](6) + assert.Equal(true, queue.IsEmpty()) + + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + queue.EnQueue(4) + queue.EnQueue(5) + + queue.Print() + assert.Equal(5, queue.Back()) + + queue.DeQueue() + queue.DeQueue() + queue.EnQueue(6) + queue.EnQueue(7) + + queue.Print() + assert.Equal(7, queue.Back()) +} + +func TestCircularQueue_Contain(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_Contain") + + queue := NewCircularQueue[int](2) + queue.EnQueue(1) + assert.Equal(true, queue.Contain(1)) + assert.Equal(false, queue.Contain(2)) +} + +func TestCircularQueue_Clear(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_Clear") + + queue := NewCircularQueue[int](3) + assert.Equal(true, queue.IsEmpty()) + assert.Equal(0, queue.Length()) + + queue.EnQueue(1) + assert.Equal(false, queue.IsEmpty()) + assert.Equal(1, queue.Length()) + + queue.Clear() + assert.Equal(true, queue.IsEmpty()) + assert.Equal(0, queue.Length()) +} + +func TestCircularQueue_Data(t *testing.T) { + assert := internal.NewAssert(t, "TestCircularQueue_Data") + + queue := NewCircularQueue[int](6) + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + queue.EnQueue(4) + queue.EnQueue(5) + + queue.Print() + assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data()) + + queue.DeQueue() + queue.DeQueue() + queue.EnQueue(6) + queue.EnQueue(7) + + queue.Print() + assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data()) + +}