栈(Stack)是一种常见的数据结构,它遵循“后进先出”(Last-In-First-Out,LIFO)的原则。最后被加入栈中的元素,第一个被取出来。栈有两个基本操作:压入(push)和弹出(pop)。压入将一个元素添加到栈的顶部,弹出则将顶部元素移除并返回它。
定义和基本操作
栈是一组元素的集合,可以进行插入和删除操作。栈中的插入和删除操作只能在栈顶进行。栈的基本操作包括:
- 压入(push):将一个元素添加到栈的顶部。
- 弹出(pop):移除栈顶元素并返回它。
- 查看栈顶元素(top/peek):返回栈顶元素,但不移除它。
- 判断栈是否为空(isEmpty):返回栈是否为空的布尔值。
- 获取栈的大小(size):返回栈中元素的数量。
实现方式
栈的实现方式有两种:顺序栈和链式栈。
顺序栈是使用数组实现的栈,可以随机访问栈中的元素。顺序栈的插入和删除操作都在栈顶进行。链式栈则使用链表实现,可以动态地分配和释放内存。
由于我见到的大部分情况都是使用数组实现的栈,这里仅给出使用数组来实现栈的代码:
package main
import "fmt"
// IntSeqStack 结构体,包含一个整型切片和一个整型变量 top,用于实现顺序栈
type IntSeqStack struct {
data []int // 整型切片,用于存储栈中的元素
top int // 整型变量,用于记录栈顶元素的下标
}
// NewIntSeqStack 函数用于创建一个 IntSeqStack 实例,并返回其指针
func NewIntSeqStack() *IntSeqStack {
return &IntSeqStack{make([]int, 0), -1} // 使用 make 函数创建一个空的整型切片,top 初始值为 -1
}
// Push 函数用于向栈中添加一个整型元素
func (s *IntSeqStack) Push(item int) {
s.top++ // 栈顶下标加 1
if s.top < len(s.data) { // 如果栈顶下标小于栈中元素的数量
s.data[s.top] = item // 直接将元素放到栈顶位置
} else { // 如果栈顶下标大于等于栈中元素的数量
s.data = append(s.data, item) // 在栈中添加一个新的元素
}
}
// Pop 函数用于从栈中删除一个整型元素,并返回其值
func (s *IntSeqStack) Pop() int {
if s.top == -1 { // 如果栈为空,返回 0
return 0
}
item := s.data[s.top] // 获取栈顶元素的值
s.top-- // 栈顶下标减 1
return item // 返回栈顶元素的值
}
// Peek 函数用于返回栈顶元素的值但不删除它
func (s *IntSeqStack) Peek() int {
if s.top == -1 { // 如果栈为空,返回 0
return 0
}
return s.data[s.top] // 返回栈顶元素的值
}
// IsEmpty 函数用于判断栈是否为空,返回布尔值
func (s *IntSeqStack) IsEmpty() bool {
return s.top == -1 // 如果栈顶下标为 -1,说明栈为空,返回 true,否则返回 false
}
// Size 函数用于返回栈中元素的数量
func (s *IntSeqStack) Size() int {
return s.top + 1 // 栈中元素的数量等于栈顶下标加 1
}
func main() {
s := NewIntSeqStack()
s.Push(1)
s.Push(2)
s.Push(3)
fmt.Println(s.Pop()) // 3
fmt.Println(s.Peek()) // 2
fmt.Println(s.IsEmpty()) // false
fmt.Println(s.Size()) // 2
}
这里栈顶元素使用了 -1 作为栈空的标识位。
应用场景
栈在计算机程序中有广泛的应用场景,例如:
- 函数调用栈:当一个函数被调用时,函数的参数和局部变量都被压入调用栈中。当函数返回时,栈顶元素(即最后被压入栈中的元素)被弹出,控制权返回到调用函数的位置。
- 表达式求值:操作数和运算符按照一定的顺序被压入栈中,然后根据运算符的优先级和结合性进行计算。
- 括号匹配:当遇到左括号时,将其压入栈中,当遇到右括号时,弹出栈顶元素并检查它是否匹配左括号。
- 浏览器的前进后退功能:当浏览器访问新页面时,将当前页面压入栈中,当用户点击“后退”按钮时,弹出栈顶元素并返回上一个页面。
除了上述应用场景,栈还可以拓展为其他数据结构,例如双端栈和循环栈等。