diff --git a/datastructure/node.go b/datastructure/node.go index 7116761..1ceb2b3 100644 --- a/datastructure/node.go +++ b/datastructure/node.go @@ -26,7 +26,7 @@ func NewStackNode[T any](value T) *StackNode[T] { // QueueNode is a node in a queue, which have a Value and Next pointer points to next node in the queue. type QueueNode[T any] struct { Value T - Next *StackNode[T] + Next *QueueNode[T] } // NewQueueNode return a QueueNode pointer diff --git a/datastructure/queue/linkedqueue.go b/datastructure/queue/linkedqueue.go new file mode 100644 index 0000000..f979d64 --- /dev/null +++ b/datastructure/queue/linkedqueue.go @@ -0,0 +1,104 @@ +package datastructure + +import ( + "errors" + "fmt" + + "github.com/duke-git/lancet/datastructure" +) + +// LinkedQueue implements queue with link list +type LinkedQueue[T any] struct { + head *datastructure.QueueNode[T] + tail *datastructure.QueueNode[T] + length int +} + +// NewLinkedQueue return a empty LinkedQueue pointer +func NewLinkedQueue[T any]() *LinkedQueue[T] { + return &LinkedQueue[T]{head: nil, tail: nil, length: 0} +} + +// Data return queue data +func (q *LinkedQueue[T]) Data() []T { + res := []T{} + current := q.head + + for current != nil { + res = append(res, current.Value) + current = current.Next + } + return res +} + +// Size return length of queue data +func (q *LinkedQueue[T]) Size() int { + return q.length +} + +// IsEmpty checks if queue is empty or not +func (q *LinkedQueue[T]) IsEmpty() bool { + return q.length == 0 +} + +// EnQueue add element into queue +func (q *LinkedQueue[T]) EnQueue(value T) { + newNode := datastructure.NewQueueNode(value) + + if q.IsEmpty() { + q.head = newNode + q.tail = newNode + } else { + q.tail.Next = newNode + q.tail = newNode + } + q.length++ +} + +// DeQueue delete head element of queue then return it, if queue is empty, return nil and error +func (q *LinkedQueue[T]) DeQueue() (*T, error) { + if q.IsEmpty() { + return nil, errors.New("queue is empty") + } + + head := q.head + q.head = q.head.Next + q.length-- + + return &head.Value, nil +} + +// Front return front value of queue +func (q *LinkedQueue[T]) Front() (*T, error) { + if q.IsEmpty() { + return nil, errors.New("queue is empty") + } + return &q.head.Value, nil +} + +// Back return back value of queue +func (q *LinkedQueue[T]) Back() (*T, error) { + if q.IsEmpty() { + return nil, errors.New("queue is empty") + } + return &q.tail.Value, nil +} + +// Clear clear the queue data +func (q *LinkedQueue[T]) Clear() { + q.head = nil + q.tail = nil + q.length = 0 +} + +// Print all nodes info of queue link +func (s *LinkedQueue[T]) Print() { + current := s.head + info := "[ " + for current != nil { + info += fmt.Sprintf("%+v, ", current) + current = current.Next + } + info += " ]" + fmt.Println(info) +} diff --git a/datastructure/queue/linkedqueue_test.go b/datastructure/queue/linkedqueue_test.go new file mode 100644 index 0000000..f9cfcd7 --- /dev/null +++ b/datastructure/queue/linkedqueue_test.go @@ -0,0 +1,84 @@ +package datastructure + +import ( + "testing" + + "github.com/duke-git/lancet/internal" +) + +func TestLinkedQueue_EnQueue(t *testing.T) { + assert := internal.NewAssert(t, "TestLinkedQueue_EnQueue") + + queue := NewLinkedQueue[int]() + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + + queue.Print() + + assert.Equal([]int{1, 2, 3}, queue.Data()) + assert.Equal(3, queue.Size()) +} + +func TestLinkedQueue_DeQueue(t *testing.T) { + assert := internal.NewAssert(t, "TestLinkedQueue_DeQueue") + + queue := NewLinkedQueue[int]() + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + + val, _ := queue.DeQueue() + + queue.Print() + + assert.Equal([]int{2, 3}, queue.Data()) + assert.Equal(1, *val) +} + +func TestLinkedQueue_Front(t *testing.T) { + assert := internal.NewAssert(t, "TestLinkedQueue_Front") + + queue := NewLinkedQueue[int]() + val, err := queue.Front() + assert.IsNotNil(err) + + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + + val, err = queue.Front() + assert.Equal(1, *val) + assert.IsNil(err) +} + +func TestLinkedQueue_Back(t *testing.T) { + assert := internal.NewAssert(t, "TestLinkedQueue_Back") + + queue := NewLinkedQueue[int]() + val, err := queue.Back() + assert.IsNotNil(err) + + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + + val, err = queue.Back() + assert.Equal(3, *val) + assert.IsNil(err) +} + +func TestLinkedQueue_Clear(t *testing.T) { + assert := internal.NewAssert(t, "TestLinkedQueue_Back") + + queue := NewLinkedQueue[int]() + assert.Equal(true, queue.IsEmpty()) + + queue.EnQueue(1) + queue.EnQueue(2) + queue.EnQueue(3) + assert.Equal(false, queue.IsEmpty()) + + queue.Clear() + assert.Equal(true, queue.IsEmpty()) +}