Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(stack_and_queue): add go code. #45

Merged
merged 7 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions codes/go/chapter_stack_and_queue/array_queue.go
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()
}
73 changes: 73 additions & 0 deletions codes/go/chapter_stack_and_queue/array_stack.go
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()
}
26 changes: 26 additions & 0 deletions codes/go/chapter_stack_and_queue/deque.go
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 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing for the Go built-in deque is required.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you use interface to reveal the usage of built-in Stack, Queue, and Deque?
I'm wondering if it is the only way as It is not consistent with other languages.

// 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
}
53 changes: 53 additions & 0 deletions codes/go/chapter_stack_and_queue/deque_test.go
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()
}
}
102 changes: 102 additions & 0 deletions codes/go/chapter_stack_and_queue/linkedlist_deque.go
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()
}
Loading