-
Notifications
You must be signed in to change notification settings - Fork 12.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #45 from Reanon/feature/support-go-chapter-stack-q…
…ueue Feature/support go chapter stack queue
- Loading branch information
Showing
14 changed files
with
730 additions
and
2 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 (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() | ||
} |
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,73 @@ | ||
// File: array_stack.go | ||
// Created Time: 2022-11-26 | ||
// Author: Reanon (793584285@qq.com) | ||
|
||
package chapter_stack_and_queue | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// ArrayStack 基于数组实现的栈 | ||
type ArrayStack struct { | ||
data []int // 数据 | ||
} | ||
|
||
func NewArrayStack() *ArrayStack { | ||
return &ArrayStack{ | ||
// 设置栈的长度为 0,容量为 16 | ||
data: make([]int, 0, 16), | ||
} | ||
} | ||
|
||
// Size 栈的长度 | ||
func (s *ArrayStack) Size() int { | ||
return len(s.data) | ||
} | ||
|
||
// IsEmpty 栈是否为空 | ||
func (s *ArrayStack) IsEmpty() bool { | ||
return s.Size() == 0 | ||
} | ||
|
||
// Push 入栈 | ||
func (s *ArrayStack) Push(v int) { | ||
// 切片会自动扩容 | ||
s.data = append(s.data, v) | ||
} | ||
|
||
func (s *ArrayStack) Pop() any { | ||
// 弹出栈前,先判断是否为空 | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
val := s.Peek() | ||
s.data = s.data[:len(s.data)-1] | ||
return val | ||
} | ||
|
||
func (s *ArrayStack) Peek() any { | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
val := s.data[len(s.data)-1] | ||
return val | ||
} | ||
|
||
func (s *ArrayStack) Print() { | ||
fmt.Println(s.toString()) | ||
} | ||
|
||
func (s *ArrayStack) toString() string { | ||
var builder strings.Builder | ||
if s.IsEmpty() { | ||
return "empty stack" | ||
} | ||
for i := len(s.data) - 1; i > 0; i-- { | ||
builder.WriteString(strconv.Itoa(s.data[i]) + " -> ") | ||
} | ||
builder.WriteString(strconv.Itoa(s.data[0])) | ||
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,26 @@ | ||
// File: deque.go | ||
// Created Time: 2022-11-29 | ||
// Author: Reanon (793584285@qq.com) | ||
|
||
package chapter_stack_and_queue | ||
|
||
type Deque interface { | ||
// OfferFirst 元素入队 | ||
OfferFirst(num any) | ||
// OfferLast 元素入队 | ||
OfferLast(num any) | ||
// PeekFirst 访问首元素 | ||
PeekFirst() any | ||
// PeekLast 访问尾元素 | ||
PeekLast() any | ||
// PollFirst 元素出队 | ||
PollFirst() any | ||
// PollLast 元素出队 | ||
PollLast() any | ||
// Size 获取队列长度 | ||
Size() int | ||
// IsEmpty 队列是否为空 | ||
IsEmpty() bool | ||
// toString 队列输出为字符串 | ||
toString() 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,53 @@ | ||
// File: deque_test.go | ||
// Created Time: 2022-11-29 | ||
// Author: Reanon (793584285@qq.com) | ||
|
||
package chapter_stack_and_queue | ||
|
||
import "testing" | ||
|
||
func TestLinkedListDeque(t *testing.T) { | ||
// 初始化队列 | ||
var deque Deque | ||
deque = NewLinkedListDeque() | ||
|
||
// 元素入队 | ||
deque.OfferLast(2) | ||
deque.OfferLast(5) | ||
deque.OfferLast(4) | ||
deque.OfferFirst(3) | ||
deque.OfferFirst(1) | ||
t.Log("队列 deque = ", deque.toString()) | ||
|
||
// 访问队首元素 | ||
peekFirst := deque.PeekFirst() | ||
t.Log("队首元素 peek = ", peekFirst) | ||
peekLast := deque.PeekLast() | ||
t.Log("队尾元素 peek = ", peekLast) | ||
|
||
// 元素出队 | ||
pollFirst := deque.PollFirst() | ||
t.Log("队首出队元素 pollFirst = ", pollFirst, ",队首出队后 deque = ", deque.toString()) | ||
pollLast := deque.PollLast() | ||
t.Log("队尾出队元素 pollLast = ", pollLast, ",队尾出队后 deque = ", deque.toString()) | ||
|
||
// 获取队的长度 | ||
size := deque.Size() | ||
t.Log("队的长度 size = ", size) | ||
|
||
// 判断是否为空 | ||
isEmpty := deque.IsEmpty() | ||
t.Log("队是否为空 = ", isEmpty) | ||
} | ||
|
||
// BenchmarkArrayQueue 67.92 ns/op in Mac M1 Pro | ||
func BenchmarkLinkedListDeque(b *testing.B) { | ||
stack := NewLinkedListDeque() | ||
// use b.N for looping | ||
for i := 0; i < b.N; i++ { | ||
stack.OfferLast(777) | ||
} | ||
for i := 0; i < b.N; i++ { | ||
stack.PollFirst() | ||
} | ||
} |
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,102 @@ | ||
// File: linkedlist_deque.go | ||
// Created Time: 2022-11-29 | ||
// Author: Reanon (793584285@qq.com) | ||
|
||
package chapter_stack_and_queue | ||
|
||
import ( | ||
"container/list" | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// LinkedListDeque 基于链表实现的双端队列, 使用内置包 list 来实现栈 | ||
type LinkedListDeque struct { | ||
list *list.List | ||
} | ||
|
||
// NewLinkedListDeque 初始化双端队列 | ||
func NewLinkedListDeque() *LinkedListDeque { | ||
return &LinkedListDeque{ | ||
list: list.New(), | ||
} | ||
} | ||
|
||
// OfferFirst 元素入队 | ||
func (s *LinkedListDeque) OfferFirst(value any) { | ||
s.list.PushFront(value) | ||
} | ||
|
||
// OfferLast 元素入队 | ||
func (s *LinkedListDeque) OfferLast(value any) { | ||
s.list.PushBack(value) | ||
} | ||
|
||
// PollFirst 元素出队 | ||
func (s *LinkedListDeque) PollFirst() any { | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
e := s.list.Front() | ||
s.list.Remove(e) | ||
return e.Value | ||
} | ||
|
||
// PollLast 元素出队 | ||
func (s *LinkedListDeque) PollLast() any { | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
e := s.list.Back() | ||
s.list.Remove(e) | ||
return e.Value | ||
} | ||
|
||
// PeekFirst 访问首元素 | ||
func (s *LinkedListDeque) PeekFirst() any { | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
e := s.list.Front() | ||
return e.Value | ||
} | ||
|
||
// PeekLast 访问尾元素 | ||
func (s *LinkedListDeque) PeekLast() any { | ||
if s.IsEmpty() { | ||
return nil | ||
} | ||
e := s.list.Back() | ||
return e.Value | ||
} | ||
|
||
// Size 获取队列的长度 | ||
func (s *LinkedListDeque) Size() int { | ||
return s.list.Len() | ||
} | ||
|
||
// IsEmpty 判断队列是否为空 | ||
func (s *LinkedListDeque) IsEmpty() bool { | ||
return s.list.Len() == 0 | ||
} | ||
|
||
func (s *LinkedListDeque) Print() { | ||
fmt.Println(s.toString()) | ||
} | ||
|
||
func (s *LinkedListDeque) toString() string { | ||
var builder strings.Builder | ||
if s.IsEmpty() { | ||
fmt.Println("empty stack") | ||
} | ||
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() | ||
} |
Oops, something went wrong.