704、scala-处理字符串算式,使用栈来实现计算器-自定义优先级[priority]

需求:31+2*(4+15-45+4/2)-1 ,处理此字符串,完成使用栈实现计算功能

思路:

  * 计算式:31+2*(4+1*5-4*5+4/2)-1
  *
  * 处理难点: 1.数字多位
  *            2.操作符优先级设置
  *            3.括号操作符处理
  *
  * 解决:使用两个栈来存放计算式的操作符与数字
  *
  * 思路:1.因为数字可能是多位字符串,则需要一个变量记录每次数字截取开始坐标
  *       2.处理如上计算式为一个字符串,从前到后遍历计算式每个字符,针对每个字符进行判断处理,取出操作符与数字
  *       3.对每次遍历的字符进行判断处理,如果当前字符是数字则遍历下个字符,如果是操作符则有两种情况
  *             2.1 操作符前面是数字,则从数字开始坐标截取到当前坐标,如第一次0-2,将截取数字如数值栈,当前字符如操作符号栈,并将数字截取开始坐标重置为当前坐标 s=2
  *             2.2 操作符前面是符号,如 *( 则直接入操作符栈,并将下次截取的数字的开始坐标设置为此坐标
  *       4.操作符优先级处理,包含括号共有 5 种可能,具体如下 代码中 4. 操作符入栈
  *             cur :当前取出的操作符; top:符号栈栈顶操作符
  *
  *       注意:这里需要循环处理不然会导致计算先后顺序问题导出结果不正确
  *             如下:4-5*3+4
  *             如果不循环处理则变成了:4-15+4-->4-19
  *       5.如果计算式最后一位不是操作符,则需要在最后进行判断最后部分是否为数字,并入数字栈
  *       6.按照优先级处理完计算式后,则需要最后进栈里数据进行计算

代码:

object Calculator {
  def main(args: Array[String]): Unit = {
    //    val valStack3 = new LinkStack02
    //    valStack3.push('+')
    //    valStack3.push('-')
    //    valStack3.push('*')
    //    println(valStack3.pop().toChar)
    //    println(calculator(4, 3, '*'))
    println("-------------")
    val i = compute("3-2*4+1+1")
    println(i)
    println("-------------")
    val i2 = compute("31+2*(4+1*5-4*5+4/2)-1")
    println(i2)
  }

  private val valStack = new LinkStack02 //数值栈
  private val operStack = new LinkStack02 //操作符栈

  // 3+2*2-4+4*(5-2)/3
  /**
    * 字符串计算函数
    *
    * @param str
    * @return
    */
  def compute(str: String): Int = {
    //1. 遍历处理每个字符
    var s = 0
    for (i <- 0 until str.length) {
      val str1 = str.substring(i, i + 1)
      //2.判断字符是否为数字
      if (isVal(str1)) {
        //println("字符不是操作符:"+str1)
      } else {
        //3. 数字入栈
        if (isVal(str.substring(s, i))) {
          val value = str.substring(s, i)
          valStack.push(value.toInt)
        }
        //4. 操作符入栈
        val oper = str.substring(i, i + 1).charAt(0)
        //4.1 判断操作符栈是否为空
        if (operStack.isEmpty()) {
          operStack.push(oper)
        } else {
          //4.2 符号栈不为空:比较操作符大小,cur <= top,则取出栈顶操作符计算
          var flag = true;
          //4.3 循环处理
          while (flag) {
            //4.4 判断符号栈不为空,并且 cur <= top
            if (operStack.size > 0 && priority(oper) <= priority(operStack.getTop.toChar)) {
              //4.4.1 栈顶是( 当前不是 ) ,则可以判断这是括号内的第一个操作符,则直接入栈,并终止循环处理下一个字符
              if (operStack.getTop == '(' && oper != ')') {
                operStack.push(oper)
                flag = false
                //4.4.2 可能一:不是括号内的计算
                //4.4.2 可能二:是括号内的计算,但是可以判断这是括号内的第一个操作符 及 ) 以前的操作符
              } else if (operStack.getTop != '(' && oper != ')') {
                val top = operStack.pop.toChar //操作符
                val num1 = valStack.pop //后
                val num2 = valStack.pop //前
                val res = calculator(num2, num1, top)
                valStack.push(res) //计算结果入栈
                //4.4.3 可判断出到达括号边界,需要将括号里面的算式先计算完成
              } else if (operStack.getTop != '(' && oper == ')') {
                val top = operStack.pop.toChar //操作符
                val num1 = valStack.pop //后
                val num2 = valStack.pop //前
                val res = calculator(num2, num1, top)
                valStack.push(res) //计算结果入栈
              } else {
                //4.4.4 那就只剩下最后一种情况括号内的算式已经计算完成,则需要将 ( 出栈并终止循环,开始处理下一个字符
                //                  if(operStack.getTop =='(' && oper == ')')
                val top = operStack.pop.toChar //操作符
                flag = false
              }
            } else {
              //4.4.5. cur > top 操作符入栈,终止循环处理下一个字符
              operStack.push(oper)
              flag = false
            }
          }
        }
        s = i + 1 //下一次截取位置
      }

    }
    //最后一部分是数字入栈
    if (isVal(str.substring(s, str.length))) {
      valStack.push(str.substring(s, str.length).toInt)
    }
    while (operStack.size > 0) {
      val p1 = operStack.pop.toChar //操作符
      val num1 = valStack.pop //后
      val num2 = valStack.pop //前
      val res = calculator(num2, num1, p1)
      valStack.push(res) //计算结果入栈
    }
    valStack.pop()
  }

  /**
    * 计算
    *
    * @param n1   数1
    * @param n2   数2
    * @param oper 操作符
    * @return
    */
  def calculator(n1: Int, n2: Int, oper: Char): Int = {
    var res = 0
    println(n1 + "" + oper + "" + n2)
    oper match {
      case '+' => res = n1 + n2
      case '-' => res = n1 - n2
      case '*' => res = n1 * n2
      case '/' => res = n1 / n2
    }
    res
  }

  /**
    * 判断是否是数值
    *
    * @param s
    * @return
    */
  def isVal(s: String): Boolean = {
    var res = true
    try {
      val int = s.toInt
    } catch {
      case ex: NumberFormatException => {
        //        println(ex.getMessage)
        res = false
      }
    } finally {
    }
    res
  }

  /**
    * 自定义操作符优先级
    *
    * @param c
    * @return
    */
  def priority(c: Char): Int = {
    if ('+'.equals(c) || '-'.equals(c)) {
      1
    } else if ('*'.equals(c) || '/'.equals(c)) {
      2
    } else if ('('.equals(c)) {
      3
    } else if (')'.equals(c)) {
      0
    } else {
      -1
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值