参考文章:golang数组实现栈(压栈,弹栈,取栈顶元素,获取栈中元素个数)
本文包含栈和队列的七种基本操作:
- 创建 new
- 判空 isEmpty
- 获取大小 getSize
- 获取栈顶 getTop 或者队头 getFront 元素
- 入队或者压栈 push
- 出队或出栈 pop
- 遍历 show
一、栈
1. 示意图:
- 特点:
- 后入先出(LIFO)的顺序表
- 最先入栈的元素在栈底(Bottom),最后入栈的元素在栈顶(Top)
- 插入和删除操作只能在末端(栈顶 Top)进行
- 以下分别使用切片和链表实现了栈:
2. 切片实现:
package main
import (
"fmt"
)
//栈 通过切片实现
//实现栈模型的结构体
type sliceStack struct {
dataStack []interface{} //存储栈数据的切片
size int //栈中元素个数
}
//创建
func newSliceStack() *sliceStack {
return &sliceStack{dataStack: make([]interface{}, 0)}
}
//判断栈是否为空
func (s *sliceStack) isEmpty() bool {
return s.size == 0
}
//栈的大小
func (s *sliceStack) getSize() int {
return s.size
}
//获取栈顶元素
func (s *sliceStack) getTop() interface{} {
if s.isEmpty() {
return nil
}
return s.dataStack[s.size-1]
}
//压栈 push
func (s *sliceStack) push(data interface{}) {
s.dataStack = append(s.dataStack, data)
s.size++
}
func (s *sliceStack) pushs(data ...interface{}) {
for _, v := range data {
s.push(v)
}
}
//出栈 pop
func (s *sliceStack) pop() (data interface{}) {
if s.isEmpty() {
fmt.Println("空栈!")
return nil
}
s.size--
data = s.dataStack[s.size]
s.dataStack = s.dataStack[:s.size]
return data
}
//显示栈元素
func (s *sliceStack) showStack() {
if s.isEmpty() {
fmt.Print("空栈!")
return
}
fmt.Println("当前栈元素如下:")
for k := range s.dataStack {
fmt.Println("index:", s.size-1-k, "val:", s.dataStack[s.size-1-k])
}
}
func main() {
var stack = newSliceStack()
if stack.isEmpty() {
fmt.Println("stack is empty!")
} else {
fmt.Println("stack size:", stack.size)
}
fmt.Println("压栈")
stack.push("data1")
stack.push("data2")
stack.push("data3")
stack.pushs(4, 5, "6")
stack.showStack()
fmt.Println("stack size:", stack.size)
fmt.Println("stack top:", stack.getTop())
fmt.Println("出栈:", stack.pop())
stack.showStack()
fmt.Println("stack size:", stack.size)
fmt.Println("stack top:", stack.getTop())
}
结果:
3. 链表实现:
- 入栈出栈需要移动top指针
- 入栈同链表头插法
package main
import "fmt"
//栈 链表实现
type Node struct {
data interface{}
next *Node
}
type Stack struct {
top *Node //栈顶指针
size int
}
//创建
func newLinkListStack() *Stack {
return &Stack{}
}
//判断是否为空
func (s *Stack) isEmpty() bool {
return s.size == 0
}
//栈的大小
func (s *Stack) getSize() int {
return s.size
}
//获取栈顶元素
func (s *Stack) getTop() interface{} {
if s.isEmpty() {
return nil
}
return s.top.data
}
//压栈 push 操作同链表的 头插法
func (s *Stack) push(val interface{}) {
node := Node{data: val, next: s.top} //第一次压栈时 s.top=nil 也就是说第一个元素的next指向nil
s.top = &node
s.size++
}
func (s *Stack) pushs(vals ...interface{}) {
for _, v := range vals {
s.push(v)
}
}
//出栈 pop
func (s *Stack) pop() interface{} {
if s.isEmpty() {
fmt.Println("空栈!")
return nil
}
val := s.top.data
s.top = s.top.next
s.size--
return val
}
//显示栈元素
func (s *Stack) showStack() {
if s.isEmpty() {
fmt.Println("空栈!")
return
}
fmt.Println("当前栈元素如下:")
topTemp := s.top
index := s.size
for ; topTemp != nil; index-- {
fmt.Println("index:", index, "val:", topTemp.data)
topTemp = topTemp.next
}
return
}
func main() {
var stack = newLinkListStack()
if stack.isEmpty() {
fmt.Println("stack is empty!")
} else {
fmt.Println("stack size:", stack.size)
}
fmt.Println("压栈")
stack.push("data1")
stack.push("data2")
stack.push("data3")
stack.pushs(4, 5, "6")
stack.showStack()
fmt.Println("stack size:", stack.size)
fmt.Println("stack top:", stack.getTop())
fmt.Println("出栈:", stack.pop())
stack.showStack()
fmt.Println("stack size:", stack.size)
fmt.Println("stack top:", stack.getTop())
}
结果:
二、队列
1. 示意图:
- 特点
- 先进先出(FIFO)的顺序表
- 只能从队尾(tear)入队
- 只能出队头(front)出队
- 以下分别使用切片和链表实现了栈:
2. 切片实现:
package main
import "fmt"
//队列 切片实现
type sliceQueue struct {
dataQueue []interface{} //存储队列数据的切片
size int //队列中元素个数
}
//创建
func newSliceQueue() *sliceQueue {
return &sliceQueue{}
}
//判空
func (s *sliceQueue) isEmpty() bool {
return s.size == 0
}
//获取大小
func (s *sliceQueue) getSize() int {
return s.size
}
//获取队头数据
func (s *sliceQueue) getFront() interface{} {
if s.isEmpty() {
fmt.Println("空队列!")
return nil
}
return s.dataQueue[0]
}
//入队
func (s *sliceQueue) push(val interface{}) {
s.dataQueue = append(s.dataQueue, val)
s.size++
}
func (s *sliceQueue) pushs(vals ...interface{}) {
for _, v := range vals {
s.push(v)
}
}
//出队
func (s *sliceQueue) pop() interface{} {
if s.isEmpty() {
fmt.Println("空队列!")
return nil
}
s.size--
val := s.dataQueue[0]
s.dataQueue = s.dataQueue[1:]
return val
}
//显示队列元素
func (s *sliceQueue) showQueue() {
if s.isEmpty() {
fmt.Println("空队列!")
return
}
fmt.Println("当前队列元素如下:")
for k := range s.dataQueue {
fmt.Println("index:", k, "val:", s.dataQueue[k])
}
}
func main() {
var queue = newSliceQueue()
if queue.isEmpty() {
fmt.Println("queue is empty!")
} else {
fmt.Println("queue size:", queue.size)
}
fmt.Println("入队")
queue.push("data1")
queue.push("data2")
queue.push("data3")
queue.pushs(4, 5, "6")
queue.showQueue()
fmt.Println("queue size:", queue.size)
fmt.Println("queue front:", queue.getFront())
fmt.Println("出队:", queue.pop())
queue.showQueue()
fmt.Println("queue size:", queue.size)
fmt.Println("queue front:", queue.getFront())
}
结果:
3. 链表实现:
- 出队移动队头front
- 入队移动队尾tear,同链表尾插法
package main
import "fmt"
//队列 链表实现
type Node struct {
data interface{}
next *Node
}
type Queue struct {
front *Node //队头指针
tear *Node //队尾指针
size int
}
//创建
func newLinkListQueue() *Queue {
return &Queue{}
}
//判空
func (q *Queue) isEmpty() bool {
return q.size == 0
}
//获取队列大小
func (q *Queue) getSize() int {
return q.size
}
//获取队头数据
func (q *Queue) getFront() interface{} {
if q.isEmpty() {
fmt.Println("空队列!")
return nil
}
return q.front.data
}
//入队 链表尾插法
func (q *Queue) push(val interface{}) {
node := Node{data: val}
if q.isEmpty() {
q.front = &node //队头
q.tear = &node //队尾
}
q.tear.next = &node
q.tear = &node
q.size++
}
func (q *Queue) pushs(vals ...interface{}) {
for _, v := range vals {
q.push(v)
}
}
//出队
func (q *Queue) pop() interface{} {
if q.isEmpty() {
fmt.Println("空队列!")
return nil
}
val := q.front.data
q.front = q.front.next
//释放出队节点的任务交给GC
q.size--
return val
}
//显示队列元素
func (q *Queue) showQueue() {
if q.isEmpty() {
fmt.Println("空队列!")
return
}
tailTemp := q.front
for i := 1; tailTemp != nil; i++ {
fmt.Println("index:", i, "val:", tailTemp.data)
tailTemp = tailTemp.next
}
return
}
func main() {
var queue = newLinkListQueue()
if queue.isEmpty() {
fmt.Println("queue is empty!")
} else {
fmt.Println("queue size:", queue.size)
}
fmt.Println("入队")
queue.push("data1")
queue.push("data2")
queue.push("data3")
queue.pushs(4, 5, "6")
queue.showQueue()
fmt.Println("queue size:", queue.size)
fmt.Println("queue front:", queue.getFront())
fmt.Println("出队:", queue.pop())
queue.showQueue()
fmt.Println("queue size:", queue.size)
fmt.Println("queue front:", queue.getFront())
}
结果: