forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(queue): implement queue in golang code
- Loading branch information
Showing
4 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// File: array_queue.go | ||
// Created Time: 2022-11-28 | ||
// Author: Reanon ([email protected]) | ||
|
||
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// File: linkedlist_queue.go | ||
// Created Time: 2022-11-28 | ||
// Author: Reanon ([email protected]) | ||
|
||
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// File: queue.go | ||
// Created Time: 2022-11-29 | ||
// Author: Reanon ([email protected]) | ||
|
||
package chapter_stack_and_queue | ||
|
||
type Queue interface { | ||
// Offer 元素入队 | ||
Offer(num int) | ||
// Peek 访问首元素 | ||
Peek() int | ||
// Poll 元素出队 | ||
Poll() int | ||
// Size 获取队列长度 | ||
Size() int | ||
// IsEmpty 队列是否为空 | ||
IsEmpty() bool | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// File: queue_test.go | ||
// Created Time: 2022-11-28 | ||
// Author: Reanon ([email protected]) | ||
|
||
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() | ||
} | ||
} |