golang:自定义栈 并实现表达式的计算

功能介绍

表达式可以包含+-*/()五种运算符。
若表达式输入错误,则提示错误信息;若表达式无误,则输出正确结果。
例如输入43-40*2-(80-3),输出结果-114
注意:允许输入多组()嵌套,只要合法即可,如(43-40)*(2-(8+3)),属于合法表达式。


实现思路

采用两个栈来实现表达式的计算:(自己实现一个栈)

  1. 数字栈:用来存储表达式中的操作数
  2. 符号栈:用来存储表达式中的运算符号

定义每个符号的优先级,根据优先级顺序来确定什么时候符号存,什么时候取出来运算。

采用一个个遍历运算字符串的字符来进行运算,需要注意两个问题:

  1. 数字不只是个位数,可能有多位数,因此需要注意判断合并。
  2. -号的处理采用将下一个数字取相反数,然后符号存入+号,为了避免当出现如-3-5时,由于两个-号的优先级相同,先计算3-5,然后结果就是-(-2)=2了。
  3. 遍历字符串的时候,每个字符的类型为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)
    }
}

本功能一次只能计算一个表达式,若想要启动一次计算多个表达式可自行实现,注意每一次重新计算清空栈内的数据或重新创建栈。

猜你喜欢

转载自blog.csdn.net/lena7/article/details/120803754