概述
栈(stack)是一个先入后出(FILO-First In Last Out)的有序列表。
栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)。
根据堆栈的定义可知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。
栈的示意图
应用场景
- 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
- 处理递归调用:和子程序的调用类似,只是除了储存下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
- 表达式的转换与求值。
- 二叉树的遍历。
- 图形的深度优先(depth-first)搜索法。
栈的案例
基于数组实现的栈
package main
import (
"errors"
"fmt"
)
type Stack struct {
arr []int
count int
top int
}
func (stack *Stack) Push(val int) (err error) {
if stack.top == stack.count-1 {
return errors.New("stack full")
}
stack.top++
stack.arr[stack.top] = val
return
}
func (stack *Stack) Pop() (val int, err error) {
if stack.top == -1 {
return 0, errors.New("stack empty")
}
val = stack.arr[stack.top]
stack.top--
return val, nil
}
func (stack *Stack) List() {
if stack.top == -1 {
fmt.Println("stack empty")
return
}
for i := stack.top; i >= 0; i-- {
fmt.Println(i, "=>", stack.arr[i])
}
}
func main() {
stack := &Stack{
arr: make([]int, 5),
count: 5,
top: -1,
}
stack.Push(1)
stack.Push(2)
stack.Push(3)
stack.Push(4)
stack.Push(5)
stack.List()
val1, _ := stack.Pop()
fmt.Println(val1)
val2, _ := stack.Pop()
fmt.Println(val2)
stack.List()
}
栈实现综合计算器
算法思路:例如计算 exp := "3+2*6-2"
-
创建两个栈,numStack(数栈),operatorStack(符号栈),numStack 存放数,operatorStack 存放操作符。 -
exp 计算表达式是一个字符串,进行依次扫描: (1) 如果扫描发现是一个数字,则直接入 numStack。 (2) 如果发现是一个运算符,则进行判断:如果 operatorStack 是一个空栈,直接入栈。如果 operatorStack 不是一个空栈,如果发现 operatorStack 栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级,就从符号栈pop出,并从数栈也 pop 两个数,进行运算,运算后的结果再重新入栈到数栈,当前符号再入符号栈,否则,运算符就直接入栈。 -
如果扫描表达式完毕,依次从符号栈取出符号,然后从数栈取出两个数,运算后的结果,入数栈,直到符号栈为空。
package main
import (
"errors"
"fmt"
"strconv"
)
type Stack struct {
arr []int
count int
top int
}
func (stack *Stack) Push(val int) (err error) {
if stack.top == stack.count-1 {
return errors.New("stack full")
}
stack.top++
stack.arr[stack.top] = val
return
}
func (stack *Stack) Pop() (val int, err error) {
if stack.top == -1 {
return 0, errors.New("stack empty")
}
val = stack.arr[stack.top]
stack.top--
return val, nil
}
func (stack *Stack) List() {
if stack.top == -1 {
fmt.Println("stack empty")
return
}
for i := stack.top; i >= 0; i-- {
fmt.Println(i, "=>", stack.arr[i])
}
}
func (stack *Stack) IsOperator(val int) bool {
if val == 42 || val == 43 || val == 45 || val == 47 {
return true
}
return false
}
func (stack *Stack) Calculate(num1, num2, operator int) int {
res := 0
switch operator {
case 42:
res = num2 * num1
case 43:
res = num2 + num1
case 45:
res = num2 - num1
case 47:
res = num2 / num1
default:
fmt.Println("运算符错误")
}
return res
}
func (stack *Stack) Priority(operator int) int {
res := 0
if operator == 42 || operator == 47 {
res = 1
} else if operator == 43 || operator == 45 {
res = 0
}
return res
}
func StackCalculate(exp string) int {
numStack := &Stack{
arr: make([]int, 20),
count: 20,
top: -1,
}
operatorStack := &Stack{
arr: make([]int, 20),
count: 20,
top: -1,
}
index := 0
num1 := 0
num2 := 0
operator := 0
result := 0
keepNum := ""
for {
ch := exp[index : index+1]
temp := int([]byte(ch)[0])
if operatorStack.IsOperator(temp) {
if operatorStack.top == -1 {
operatorStack.Push(temp)
} else {
if operatorStack.Priority(operatorStack.arr[operatorStack.top]) >= operatorStack.Priority(temp) {
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
operator, _ = operatorStack.Pop()
result = operatorStack.Calculate(num1, num2, operator)
numStack.Push(result)
operatorStack.Push(temp)
} else {
operatorStack.Push(temp)
}
}
} else {
keepNum += ch
if index == len(exp)-1 {
val, _ := strconv.ParseInt(keepNum, 10, 64)
numStack.Push(int(val))
} else {
if operatorStack.IsOperator(int([]byte(exp[index+1 : index+2])[0])) {
val, _ := strconv.ParseInt(keepNum, 10, 64)
numStack.Push(int(val))
keepNum = ""
}
}
}
if index+1 == len(exp) {
break
}
index++
}
for {
if operatorStack.top == -1 {
break
}
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
operator, _ = operatorStack.Pop()
result = operatorStack.Calculate(num1, num2, operator)
numStack.Push(result)
}
res, _ := numStack.Pop()
return res
}
func main() {
exp1 := "3+2*6-2"
res1 := StackCalculate(exp1)
fmt.Println(res1)
exp2 := "321+21*6-21"
res2 := StackCalculate(exp2)
fmt.Println(res2)
}
|