现在需要实现一个计算器函数,输入是一个字符串格式的数学运算表达式,要求计算出该表达式的最终结果。表达式的操作符支持加减乘除和小括号。
思路:利用stack,将低优先级的运算压栈,遇到相同优先级的则计算第一个符号。右括号的,把括号内式子单独计算,并把结果代入原式子继续计算
package main
import (
"errors"
"fmt"
"strconv"
"log"
)
type Stack struct {
elements []interface{} //elements
}
func NewStack() *Stack {
return &Stack{make([]interface{}, 0, 100)}
}
func (s *Stack) Push(value ...interface{}) {
s.elements = append(s.elements, value...)
}
//返回下一个元素
func (s *Stack) Top() (value interface{}) {
if s.Size() > 0 {
return s.elements[s.Size()-1]
}
return nil //read empty s
}
//返回下一个元素,并从Stack移除元素
func (s *Stack) Pop() (value interface{}, err error) {
if s.Size() > 0 {
value = s.elements[s.Size()-1]
s.elements = s.elements[:s.Size()-1]
return
}
return nil, errors.New("s is empty") //read empty s
}
//Stack的size
func (s *Stack) Size() (int) {
return len(s.elements)
}
//是否为空
func (s *Stack) Empty() (bool) {
if s.elements == nil || s.Size() == 0 {
return true
}
return false
}
//打印
func (s *Stack) Print() {
for i := len(s.elements) - 1; i >= 0; i-- {
fmt.Println(i, "=>", s.elements[i])
}
}
type Calculator struct {
stDat *Stack
stSym *Stack
}
func NewCalculator() *Calculator {
return &Calculator{NewStack(), NewStack()}
}
func math(num1, num2 float64, sym byte) (result float64) {
switch sym {
case '+':
result = num1 + num2
case '-':
result = num1 - num2
case '*':
result = num1 * num2
case '/':
result = num1 / num2
}
//fmt.Println("math result:", result)
return
}
func (c *Calculator) Step(num float64, sym byte) error {
// 判断栈顶符合与当前符号运算优先级。
// 如果sym不高于栈顶符号,则取出数据栈顶数字、符号栈顶符号 与 num 运算,并将结果压入数据栈,sym压入符号栈。
// 如果sym优先级更高,则分别将 num, sym 压入数据栈和符号栈。
// 如果 sym = '\n' 表示算式结束,依次出栈运算。
if sym == '\n' {
if c.stSym.Size() == 0 {
c.stDat.Push(num)
} else {
length := c.stSym.Size()
for i:=0; i < length; i++ {
symbol, _ := c.stSym.Pop()
ifc, _ := c.stDat.Pop()
num1 := ifc.(float64)
num = math(num1, num, symbol.(byte))
}
c.stDat.Push(num)
}
} else {
if c.stSym.Size() != 0 {
tSymbol := c.stSym.Top().(byte)
pc := priorityCompare(tSymbol, sym)
switch {
case pc < 0:
c.stDat.Push(num)
c.stSym.Push(sym)
case pc >= 0:
c.stSym.Pop()
ifc, _ := c.stDat.Pop()
num1 := ifc.(float64)
c.stDat.Push(math(num1, num, tSymbol))
c.stSym.Push(sym)
}
} else {
c.stDat.Push(num)
c.stSym.Push(sym)
}
}
return nil
}
func (c *Calculator) Result() (result float64, err error) {
if c.stSym.Empty() && c.stDat.Size() == 1 {
result = c.stDat.Top().(float64)
} else {
//计算式未结束或者计算式有误
err = errors.New("计算式未结束或者计算式有误")
}
return
}
// 比较运算符优先级,return >0,则s1高于s2; =0,则s1、s2相同; <0,则s1低于s2
func priorityCompare(s1, s2 byte) int {
level := func(sym byte) int {
lvl := 0
switch sym {
case '+', '-':
lvl = 1
case '*', '/':
lvl = 2
}
return lvl
}
return level(s1) - level(s2)
}
func Calculate(str []byte) (result float64, err error) {
fmt.Println("str:", string(str))
cal := NewCalculator()
sNum, num := make([]byte, 0, 100), 0.0
for idx := 0; idx < len(str); idx++ {
c := str[idx]
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
sNum = append(sNum, c)
case '+', '-', '*', '/':
if (len(sNum) > 0 && num != 0.0) || (len(sNum) == 0 && num == 0.0) {
err = errors.New("计算式有误")
return
}
if len(sNum) > 0 {
strNum := string(sNum)
intNum, _ := strconv.Atoi(strNum)
num = float64(intNum)
}
cal.Step(num, c)
sNum, num = make([]byte, 0, 100), 0.0
case '(':
idx++
Loop:
for j := idx; j < len(str); j++ {
if str[j] == ')' {
num, err = Calculate(str[idx:j])
if err != nil {
return
}
idx = j
break Loop
}
}
default:
err = errors.New(fmt.Sprintf("无效符号: %s", c))
return
}
}
// 扫描结束
if (len(sNum) > 0 && num != 0.0) || (len(sNum) == 0 && num == 0.0) {
err = errors.New("计算式有误")
return
}
if len(sNum) > 0 {
strNum := string(sNum)
intNum, _ := strconv.Atoi(strNum)
num = float64(intNum)
}
cal.Step(num, '\n')
return cal.Result()
}
func main() {
express := []byte("123+(3+5*4)+4-(2*5+6*3/2)")
//express := []byte("3+5")
result, err := Calculate(express)
if err != nil {
log.Fatalln(err)
}
fmt.Println("result:", result)
}
来源:oschina
链接:https://my.oschina.net/u/2961861/blog/3022686