功能介绍
表达式可以包含+
,-
,*
,/
,(
,)
五种运算符。
若表达式输入错误,则提示错误信息;若表达式无误,则输出正确结果。
例如输入43-40*2-(80-3)
,输出结果-114
注意:允许输入多组()
嵌套,只要合法即可,如(43-40)*(2-(8+3))
,属于合法表达式。
实现思路
采用两个栈来实现表达式的计算:(自己实现一个栈)
- 数字栈:用来存储表达式中的操作数
- 符号栈:用来存储表达式中的运算符号
定义每个符号的优先级,根据优先级顺序来确定什么时候符号存,什么时候取出来运算。
采用一个个遍历运算字符串的字符来进行运算,需要注意两个问题:
- 数字不只是个位数,可能有多位数,因此需要注意判断合并。
-
号的处理采用将下一个数字取相反数,然后符号存入+
号,为了避免当出现如-3-5
时,由于两个-
号的优先级相同,先计算3-5
,然后结果就是-(-2)=2
了。- 遍历字符串的时候,每个字符的类型为
int32
,在测试的时候发现int32
对应的数字与实际字符串的数字不一致,因此需要编写一个方法Int32ToInt
(具体实现代码如下),实现两种类型的转换。
栈的定义代码
/**
* @Author: lena
* @Date: 2021/9/23 16:32
* @Description: 用数组实现栈
* @Version: 1.0.0
*/
package data_structure
type Stack struct {
size int // 栈能存储的容量
top int // 栈顶
data []interface{
} // 栈内元素
}
// 创建栈
func NewStack(size int) *Stack {
return &Stack{
size: size,
top: 0,
data: make([]interface{
},size),
}
}
// 栈满
func (this *Stack)IsFull() bool {
// 当top=数组最大长度,说明栈满
return this.top == this.size
}
//栈空
func (this *Stack)IsEmpty() bool {
return this.top == 0
}
// 出栈
func (this *Stack)Pop() (interface{
},bool) {
// 栈空
if this.IsEmpty() {
return 0,false
}
// 栈顶指针向下移动
this.top--
//fmt.Println("出栈:",this.data[this.top])
return this.data[this.top],true
}
// 入栈
func (this *Stack)Push(d interface{
}) bool {
// 栈满
if this.IsFull() {
return false
}
this.data[this.top]=d
this.top++
//fmt.Println("入栈:",d)
return true
}
// 获取栈顶元素但不出栈
func (this *Stack)Peek() (interface{
},bool) {
// 栈空
if this.IsEmpty() {
return 0,false
}
return this.data[this.top-1],true
}
// 栈内元素
func (this *Stack)Len() int {
return this.top
}
栈的测试代码
/**
* @Author: lena
* @Date: 2021/9/23 21:53
* @Description: stack_test.go
* @Version: 1.0.0
*/
package data_structure
import (
"reflect"
"testing"
)
func TestStack(t *testing.T) {
stack:= NewStack(3)
if !reflect.DeepEqual(stack.IsEmpty(),true) {
t.Errorf("error")
}
stack.Push("zh")
stack.Push("-")
if !reflect.DeepEqual(stack.IsEmpty(),false) {
t.Errorf("error")
}
if !reflect.DeepEqual(stack.IsFull(),false) {
t.Errorf("error")
}
stack.Push("ku")
if !reflect.DeepEqual(stack.Len(),3) {
t.Errorf("len:%d",stack.Len())
}
if !reflect.DeepEqual(stack.IsFull(),true) {
t.Errorf("error")
}
res,_:=stack.Pop()
if !reflect.DeepEqual(res,"ku") {
t.Errorf("error")
}
res,_=stack.Pop()
if !reflect.DeepEqual(res,"-") {
t.Errorf("error")
}
res,_=stack.Pop()
if !reflect.DeepEqual(res,"zh") {
t.Errorf("error")
}
}
表达式计算代码
/**
* @Author: lena
* @Date: 2021/9/24 20:57
* @Description: 使用栈计算输入的表达式,前提自己实现一个栈
* @Version: 1.0.0
*/
package main
import (
"errors"
"fmt"
. "helloworld/data_structure"
"helloworld/util"
"strconv"
)
// 创建两个栈 一个存储操作数 一个存储操作符
var numStack=NewStack(20)
var symbolStack=NewStack(20)
// 获取输入
func Main() {
var input string
fmt.Printf("请输入要计算的表达式:")
fmt.Scanln(&input)
res,err := calculate(input)
if err != nil {
fmt.Println(err)
}
fmt.Println("计算结果为:",res)
}
/** 计算值:(边计算边检验表达式格式是否正确)
高于符号栈顶优先级->存
低于符号栈顶优先级:1.符号不为)] 栈顶为[( => 入栈
2.符号为)]计算 直到符号栈顶为[(
3.数字栈出两个元素利用栈顶符号计算 存入结果和符号
*/
func calculate(str string) (int, error) {
last:=-1
for _,s := range str {
//fmt.Println("---------------current:",string(s))
// 判断当前s的优先级
p := getPriority(string(s))
// s是数字:直接入栈
if p == 0 {
c,_:=Int32ToInt(s) // 当前数字
// 判断上一个是否是数字
if last == 0 {
n,_ := numStack.Pop()
// 拼接数字:返回string类型
ns:=fmt.Sprintf("%v%v",n,c)
c,_=strconv.Atoi(ns)
}
// 上一个符号是'-'
if last == 2 {
// 将当前数字改为负数
c=-c
// 修改符号栈栈顶的-号 改为+号
symbolStack.Pop()
symbolStack.Push("+")
}
// 数字压入栈
numStack.Push(c)
last=p
} else {
last=p
// s是字符
if symbolStack.IsEmpty() {
// 当前字符栈为空,直接入栈
symbolStack.Push(string(s))
continue
}
// 获取栈顶字符
t,err := symbolStack.Peek()
if !err {
return 0,errors.New("[error]1 符号栈为空,无法出栈。")
}
top:=getPriority(t.(string))
// 当前符号p不为)] 但符号栈栈顶top为[( => 直接入栈
if (p != 1 && top == 8) || (p != 2 && top == 7) {
symbolStack.Push(string(s))
continue
}
// 符号为')' = > 计算 直到符号栈顶为'('
for p == 1 && top != 8 {
// 符号栈出栈
symbol,err := symbolStack.Pop()
if !err {
return 0,errors.New("[error]2 符号栈为空")
}
// 操作数出栈
data1,err := numStack.Pop()
data2,err := numStack.Pop()
if !err {
return 0,errors.New("[error]3 输入表达式有误")
}
res,e := getSum(data1.(int),data2.(int),symbol.(string))
if e != nil {
return 0,e // 不是合法的符号
}
// 计算结果入栈
numStack.Push(res)
// 更新当前栈顶元素
t,err = symbolStack.Peek()
if !err {
// 栈空 直接进入下一个循环
break
//return 0,errors.New("[error]4 符号栈为空,无法出栈。")
}
top=getPriority(t.(string))
}
// 当前符号p位')' 符号栈顶top元素为'('
if p == 1 && top == 8 {
// 符号栈出栈
symbolStack.Pop()
// 当前符号位')'无需处理
continue
}
// top=符号栈栈顶优先级 p=当前符号优先级
// p高于符号栈栈顶优先级top:存
if p > top {
symbolStack.Push(string(s))
} else {
// p低于符号栈栈顶优先级top:计算
// 符号栈出栈
symbol,err := symbolStack.Pop()
if !err {
return 0,errors.New("[error]5 符号栈为空")
}
// 操作数出栈
data1,err := numStack.Pop()
data2,err := numStack.Pop()
if !err {
return 0,errors.New("[error]6 输入表达式有误")
}
res,e := getSum(data1.(int),data2.(int),symbol.(string))
if e != nil {
return 0,e // 不是合法的符号
}
// 计算结果入栈
numStack.Push(res)
// 将当前符号入栈
symbolStack.Push(string(s))
}
}
}
// 计算栈内剩余值
for symbolStack.Len() != 0 {
if numStack.Len() < 2 {
return 0,errors.New("[error]7 输入表达式有误")
}
// 符号栈出栈
symbol,err := symbolStack.Pop()
if !err {
return 0,errors.New("[error]8 符号栈为空")
}
// 操作数出栈
data1,err := numStack.Pop()
data2,err := numStack.Pop()
if !err {
return 0,errors.New("[error]9 输入表达式有误")
}
// 计算
res,e := getSum(data1.(int),data2.(int),symbol.(string))
if e != nil {
return 0,e // 不是合法的符号
}
// 计算结果入栈
numStack.Push(res)
}
if numStack.Len() != 1 {
return 0,errors.New("[error]10 输入表达式有误")
}
res,_:=numStack.Peek()
return res.(int),nil
}
// 计算结果
func getSum(data1 int,data2 int,c string) (int,error) {
switch c {
// 要注意运算顺序
case "+":return data1+data2,nil
case "-":return data2-data1,nil
case "*":return data1*data2,nil
case "/":return data2/data1,nil
}
return 0,errors.New("[error]11 不是合法的符号")
}
// 获取符号优先级:) ] +- */ [ (
func getPriority(c string) int {
switch c {
case "+":return 3
case "-":return 2
case "*":return 5
case "/":return 5
case "(":return 8
case ")":return 1
default:return 0 // 数字
}
}
// 类型转换:int32 -> int
func Int32ToInt(a int32) (int,error) {
b:=string(a)
c,err:=strconv.Atoi(b)
return c,err
}
表达式计算的测试代码
/**
* @Author: lena
* @Date: 2021/10/16 16:48
* @Description: calculate_test.go
* @Version: 1.0.0
*/
package main
import (
"fmt"
"reflect"
"testing"
)
func StartCalculate(input string) int {
res,err := calculate(input)
if err != nil {
fmt.Println(err)
}
return res
}
func Test(t *testing.T) {
sum := StartCalculate("3*4-7")
fmt.Println("[res]",sum)
}
func Test1(t *testing.T) {
input:="4+5"
res:=9
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("[%s] expect:%d,result:%d",input,res,r)
}
}
func Test2(t *testing.T) {
input:="4+5*2"
res:=14
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("[%s] expect:%d,result:%d",input,res,r)
}
}
func Test3(t *testing.T) {
input:="3*4-7"
res:=5
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("[%s] expect:%d,result:%d",input,res,r)
}
}
func Test4(t *testing.T) {
input:="(1+5)+2"
res:=8
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test5(t *testing.T) {
input:="2+(1+5)*2"
res:=14
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test6(t *testing.T) {
input:="2*4+(1-5)*2"
res:=0
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test7(t *testing.T) {
input:="2*4+((1-5)*2-2)"
res:=-2
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test8(t *testing.T) {
input:="12+423"
res:=435
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test9(t *testing.T) {
input:="12+4*(5-7)"
res:=4
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test10(t *testing.T) {
input:="43-40*2"
res:=-37
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test11(t *testing.T) {
input:="43-40*2-(80-3)"
res:=-114
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
func Test12(t *testing.T) {
input:="(43-40)*(2-(8+3))"
res:=-27
r:=StartCalculate(input)
if !reflect.DeepEqual(r,res) {
t.Errorf("cacluate:%s expect:%d,result:%d",input,res,r)
}
}
本功能一次只能计算一个表达式,若想要启动一次计算多个表达式可自行实现,注意每一次重新计算清空栈内的数据或重新创建栈。