思路:
// @Author sunwenbo
// 2024/4/12 16:51
package main
import (
"errors"
"fmt"
"strconv"
)
// 使用数组来模拟一个栈的应用
type Stack struct {
MaxTop int //表示栈最大可以存放数的个数
Top int //表示栈底,因为栈底是固定的,因此我们可以直接使用Top
arr [20]int //数组模拟栈
}
// 入栈
func (this *Stack) Push(val int) (err error) {
// 先判断栈是否已经满了
if this.Top == this.MaxTop-1 {
fmt.Println("stack full")
return errors.New("stack full")
}
this.Top++
// 放入数据
this.arr[this.Top] = val
return
}
// 遍历栈,需要从栈顶开始遍历
func (this *Stack) List() {
// 先判断栈是否为空
if this.Top == -1 {
fmt.Println("stack empty")
return
}
//curTop := this.Top
fmt.Println("栈的情况如下:")
for i := this.Top; i >= 0; i-- {
fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
}
}
// 出栈
func (this *Stack) Pop() (val int, err error) {
// 判断栈是否为空
if this.Top == -1 {
fmt.Println("stack empty")
return 0, errors.New("stack empty")
}
// 先取值,再this.Top--
val = this.arr[this.Top]
this.Top--
return val, nil
}
// 判断一个字符是不是一个运算符 [+,-,*,/]
func (this *Stack) IsOper(val int) bool {
if val == 42 || val == 43 || val == 45 || val == 47 {
return true
} else {
return false
}
}
// 运算的方法
func (this *Stack) Cal(num1 int, num2 int, oper int) int {
res := 0
switch oper {
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
}
// 编写一个方法返回某个运算符的优先级[程序员定的]
// [* / => 1, +- = 0 ]
func (this *Stack) Priority(oper int) int {
res := 0
if oper == 42 || oper == 47 {
return 1
} else if oper == 44 || oper == 45 {
fmt.Println("oper=", oper)
return 0
}
return res
}
func main() {
// 数栈
numStack := &Stack{
MaxTop: 20,
Top: -1}
// 符号栈
operStack := &Stack{
MaxTop: 20,
Top: -1}
exp := "30+3*6-4"
// 定义一个index,帮助扫描 exp
index := 0
// 为了配合运算,我们定义需要的变量
num1, num2, oper, result, keepNum := 0, 0, 0, 0, ""
for {
fmt.Println("numStack")
numStack.List()
fmt.Println("operStack")
operStack.List()
// 这里需要增加一个逻辑,处理多位数的问题
ch := exp[index : index+1] // 字符串
// ch ==> "+" ==> 43
temp := int([]byte(ch)[0]) // 字符对应的ASCI码
if operStack.IsOper(temp) { //说明是符号
//如果operStack 是一个空栈,直接入栈
if operStack.Top == -1 { // 空栈
operStack.Push(temp)
} else {
// 两个逻辑
// 1. 如果发现operStack 栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级,就从符号栈Pop出,
//并从数栈也pop两个数,进行运算,运算后的结果再重新入栈到栈,符号再入符号栈
if operStack.Priority(operStack.arr[operStack.Top]) >= operStack.Priority(temp) {
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
oper, _ = operStack.Pop()
result = operStack.Cal(num1, num2, oper)
// 将计算结果重新入数栈
numStack.Push(result)
// 将当前的符号压入符号栈
operStack.Push(temp)
} else {
operStack.Push(temp)
}
}
} else { //说明是数字
//处理多位数的思路
// 1. 先定义一个变量keepNum string,做拼接工作
keepNum += ch
// 2. 每次要向index的后面字符测试一下,看看是不是运算符,然后再做处理
// 如果到表达式的最后了,直接将keepNum 转换成整数
if index == len(exp)-1 { // 已经到表达式最后了
val, _ := strconv.ParseInt(keepNum, 10, 64)
numStack.Push(int(val))
} else {
// index 的后一位测试一下,看看是不是运算符,如果不是运算符则继续上面的for循环,做字符串拼接
if operStack.IsOper(int([]byte(exp[index+1 : index+2])[0])) {
val, _ := strconv.ParseInt(keepNum, 10, 64)
numStack.Push(int(val))
keepNum = ""
}
}
//val, _ := strconv.ParseInt(ch, 10, 64)
//numStack.Push(int(val))
}
// 继续扫描,先判断index 是否已经扫描到计算表达式的最后
if index+1 == len(exp) {
break
}
index++
}
// 如果扫描表达式完毕,依次从符号栈取出符号,然后从数栈中取出两个数,
// 运算后的结果,入数栈,直到符号栈为空
for {
if operStack.Top == -1 {
break //退出条件
}
num1, _ = numStack.Pop()
num2, _ = numStack.Pop()
oper, _ = operStack.Pop()
result = operStack.Cal(num1, num2, oper)
// 将计算结果重新入数栈
numStack.Push(result)
}
// 如果我们的算法没有问题,表达式也是正确的则结果就是numStack的最后一个数
res, _ := numStack.Pop()
fmt.Printf("表达式: %s=%v", exp, res)
}