go 通过栈实现综合计算器

一 图解分析

二 代码

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) 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) List() {
   // 先判断栈是否为空
   if this.Top == -1 {
      fmt.Println("stack empty")
      return
   }
   fmt.Println("栈的情况如下:")
   for i := this.Top; i >= 0; i-- {
      fmt.Printf("arr[%d]=%d\n", i, this.arr[i])
   }


}

// 判断一个字符是不是一个运算符[+, - , * , /]
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 {
      res = 1
   } else if oper == 43 || oper == 45 {
      res = 0
   }
   return res
}

func main() {
   // 数栈
   numStack := &Stack{
      MaxTop: 20,
      Top:    -1,
   }
   // 符号栈
   operStack := &Stack{
      MaxTop: 20,
      Top:    -1,
   }

   exp := "30+30*6-4-6"
   // 定义一个 index ,帮助扫描 exp
   index := 0
   // 为了配合运算,需要定义的变量
   num1 := 0
   num2 := 0
   oper := 0
   result := 0
   keepNum := ""
   for {
      //处理多位数的问题
      ch := exp[index : index+1] // 字符串.
      //ch ==>"+" ===> 43
      temp := int([]byte(ch)[0])  // 就是字符对应的ASCiI码
      if operStack.IsOper(temp) { // 说明是符号
         // 如果 operStack 是一个空栈,直接入栈
         if operStack.Top == -1 { // 空栈
            operStack.Push(temp)
         } else {
            // 如果发现 opertStack 栈顶的运算符的优先级大于等于当前准备入栈的运算符的优先级,
            // 就从符号栈 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 后面测试看看是不是运算符
            if operStack.IsOper(int([]byte(exp[index+1 : index+2])[0])) {
               val, _ := strconv.ParseInt(keepNum, 10, 64)
               numStack.Push(int(val))
               keepNum = ""
            }
         }
      }
      // 继续扫描
      // 先判断 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)
}

三 测试

表达式30+30*6-4-6 = 200

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值