From 76a7e0b2325b66b4749394da03de95f673824e00 Mon Sep 17 00:00:00 2001 From: reanon <793584285@qq.com> Date: Tue, 29 Nov 2022 01:10:22 +0800 Subject: [PATCH] feat(queue): implement queue in golang code --- .../go/chapter_stack_and_queue/array_queue.go | 92 +++++++++++++++++++ .../linkedlist_queue.go | 79 ++++++++++++++++ codes/go/chapter_stack_and_queue/queue.go | 18 ++++ .../go/chapter_stack_and_queue/queue_test.go | 91 ++++++++++++++++++ 4 files changed, 280 insertions(+) create mode 100644 codes/go/chapter_stack_and_queue/array_queue.go create mode 100644 codes/go/chapter_stack_and_queue/linkedlist_queue.go create mode 100644 codes/go/chapter_stack_and_queue/queue.go create mode 100644 codes/go/chapter_stack_and_queue/queue_test.go diff --git a/codes/go/chapter_stack_and_queue/array_queue.go b/codes/go/chapter_stack_and_queue/array_queue.go new file mode 100644 index 000000000..f771ea214 --- /dev/null +++ b/codes/go/chapter_stack_and_queue/array_queue.go @@ -0,0 +1,92 @@ +// File: array_queue.go +// Created Time: 2022-11-28 +// Author: Reanon (793584285@qq.com) + +package chapter_stack_and_queue + +import ( + "fmt" + "strings" +) + +// ArrayQueue 基于环形数组实现的队列, 不支持扩容 +type ArrayQueue struct { + data []any // 用于存储队列元素的数组 + capacity int // 队列容量(即最多容量的元素个数) + head int // 头指针,指向队首 + tail int // 尾指针,指向队尾 + 1 +} + +// NewArrayQueue 基于环形数组实现的队列 +func NewArrayQueue(capacity int) *ArrayQueue { + return &ArrayQueue{ + data: make([]any, capacity), + capacity: capacity, + head: 0, + tail: 0, + } +} + +// Size 获取队列的长度 +func (q *ArrayQueue) Size() int { + size := (q.capacity + q.tail - q.head) % q.capacity + return size +} + +// IsEmpty 判断队列是否为空 +func (q *ArrayQueue) IsEmpty() bool { + return q.tail-q.head == 0 +} + +// Offer 入队 +func (q *ArrayQueue) Offer(v any) { + // 当 tail == capacity 表示队列已满 + if q.Size() == q.capacity { + return + } + // 尾结点后添加 + q.data[q.tail] = v + // 尾指针向后移动一位,越过尾部后返回到数组头部 + q.tail = (q.tail + 1) % q.capacity +} + +// Poll 出队 +func (q *ArrayQueue) Poll() any { + if q.IsEmpty() { + return nil + } + v := q.data[q.head] + // 队头指针向后移动,越过尾部后返回到数组头部 + q.head = (q.head + 1) % q.capacity + return v +} + +// Peek 访问队首元素 +func (q *ArrayQueue) Peek() any { + if q.IsEmpty() { + return nil + } + v := q.data[q.head] + return v +} + +func (q *ArrayQueue) Print() { + fmt.Println(q.toString()) +} + +// toString 通过字符串的方式输出 +func (q *ArrayQueue) toString() string { + // 为空时 + if q.IsEmpty() { + return "empty items" + } + var builder strings.Builder + size := q.Size() + str := fmt.Sprintf("%+v", q.data[q.head]) + for i := 1; i < size; i++ { + builder.WriteString(str + " -> ") + str = fmt.Sprintf("%+v", q.data[(i+q.head)%q.capacity]) + } + builder.WriteString(str) + return builder.String() +} diff --git a/codes/go/chapter_stack_and_queue/linkedlist_queue.go b/codes/go/chapter_stack_and_queue/linkedlist_queue.go new file mode 100644 index 000000000..6c71f6f7e --- /dev/null +++ b/codes/go/chapter_stack_and_queue/linkedlist_queue.go @@ -0,0 +1,79 @@ +// File: linkedlist_queue.go +// Created Time: 2022-11-28 +// Author: Reanon (793584285@qq.com) + +package chapter_stack_and_queue + +import ( + "container/list" + "fmt" + "strings" +) + +// LinkedListQueue 基于链表实现的栈, 使用内置包 list 来实现栈 +type LinkedListQueue struct { + list *list.List +} + +// NewLinkedListQueue 初始化链表 +func NewLinkedListQueue() *LinkedListQueue { + return &LinkedListQueue{ + list: list.New(), + } +} + +// Offer 入队 +func (s *LinkedListQueue) Offer(value any) { + s.list.PushBack(value) +} + +// Poll 出队 +func (s *LinkedListQueue) Poll() any { + if s.IsEmpty() { + return nil + } + e := s.list.Front() + s.list.Remove(e) + return e.Value +} + +// Peek 访问队首元素 +func (s *LinkedListQueue) Peek() any { + if s.IsEmpty() { + return nil + } + e := s.list.Front() + return e.Value +} + +// Size 获取队列的长度 +func (s *LinkedListQueue) Size() int { + return s.list.Len() +} + +// IsEmpty 判断队列是否为空 +func (s *LinkedListQueue) IsEmpty() bool { + return s.list.Len() == 0 +} + +func (s *LinkedListQueue) Print() { + fmt.Println(s.toString()) +} + +func (s *LinkedListQueue) toString() any { + var builder strings.Builder + if s.IsEmpty() { + fmt.Println("empty stack") + return nil + } + e := s.list.Front() + // 强转为 string, 会影响效率 + str := fmt.Sprintf("%v", e.Value) + for e.Next() != nil { + builder.WriteString(str + " -> ") + e = e.Next() + str = fmt.Sprintf("%v", e.Value) + } + builder.WriteString(str) + return builder.String() +} diff --git a/codes/go/chapter_stack_and_queue/queue.go b/codes/go/chapter_stack_and_queue/queue.go new file mode 100644 index 000000000..c8f16c83a --- /dev/null +++ b/codes/go/chapter_stack_and_queue/queue.go @@ -0,0 +1,18 @@ +// File: queue.go +// Created Time: 2022-11-29 +// Author: Reanon (793584285@qq.com) + +package chapter_stack_and_queue + +type Queue interface { + // Offer 元素入队 + Offer(num int) + // Peek 访问首元素 + Peek() int + // Poll 元素出队 + Poll() int + // Size 获取队列长度 + Size() int + // IsEmpty 队列是否为空 + IsEmpty() bool +} diff --git a/codes/go/chapter_stack_and_queue/queue_test.go b/codes/go/chapter_stack_and_queue/queue_test.go new file mode 100644 index 000000000..f4734a52c --- /dev/null +++ b/codes/go/chapter_stack_and_queue/queue_test.go @@ -0,0 +1,91 @@ +// File: queue_test.go +// Created Time: 2022-11-28 +// Author: Reanon (793584285@qq.com) + +package chapter_stack_and_queue + +import "testing" + +func TestArrayQueue(t *testing.T) { + // 初始化队 + capacity := 10 + queue := NewArrayQueue(capacity) + + // 元素入队 + queue.Offer(1) + queue.Offer(2) + queue.Offer(3) + queue.Offer(4) + queue.Offer(5) + t.Log("队列 queue = ", queue.toString()) + + // 访问队首元素 + peek := queue.Peek() + t.Log("队首元素 peek = ", peek) + + // 元素出队 + pop := queue.Poll() + t.Log("出队元素 pop = ", pop, ", 出队后 queue =", queue.toString()) + + // 获取队的长度 + size := queue.Size() + t.Log("队的长度 size = ", size) + + // 判断是否为空 + isEmpty := queue.IsEmpty() + t.Log("队是否为空 = ", isEmpty) +} + +func TestLinkedListQueue(t *testing.T) { + // 初始化队 + queue := NewLinkedListQueue() + + // 元素入队 + queue.Offer(1) + queue.Offer(2) + queue.Offer(3) + queue.Offer(4) + queue.Offer(5) + t.Log("队列 queue = ", queue.toString()) + + // 访问队首元素 + peek := queue.Peek() + t.Log("队首元素 peek = ", peek) + + // 元素出队 + pop := queue.Poll() + t.Log("出队元素 pop = ", pop, ", 出队后 queue =", queue.toString()) + + // 获取队的长度 + size := queue.Size() + t.Log("队的长度 size = ", size) + + // 判断是否为空 + isEmpty := queue.IsEmpty() + t.Log("队是否为空 = ", isEmpty) +} + +// BenchmarkArrayQueue 8 ns/op in Mac M1 Pro +func BenchmarkArrayQueue(b *testing.B) { + capacity := 1000 + stack := NewArrayQueue(capacity) + // use b.N for looping + for i := 0; i < b.N; i++ { + stack.Offer(777) + } + for i := 0; i < b.N; i++ { + stack.Poll() + } +} + +// BenchmarkLinkedQueue 62.66 ns/op in Mac M1 Pro +func BenchmarkLinkedQueue(b *testing.B) { + stack := NewLinkedListQueue() + // use b.N for looping + for i := 0; i < b.N; i++ { + stack.Offer(777) + } + for i := 0; i < b.N; i++ { + stack.Poll() + } +}