前缀表达式转后缀表达式-->逆波兰计算器

package datastructure.stack

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

object PolandNotation {
  def main(args: Array[String]): Unit = {
    val exp_ = "10+((20+30)*40)-50"
    val expArr = toInfixArr(exp_)
    println("前缀表达式为:"+expArr.mkString(" "))
    val suffixArr = parseInfix2Suffix(expArr)
    println("后缀表达式为:"+suffixArr.mkString(" "))
    //思路
    //1.将exp表达式放到List中
    //2.将传给一个方法配合栈,完成计算
    println("res="+calculate(suffixArr))
  }

  /**
   * 计算后缀表达式
   * @param arr 后缀表达式
   * @return
   */
  def calculate(arr: Array[String]): Int = {
    val stack = new mutable.Stack[String]
    var res = 0
    arr.foreach(
      item=>{
        if(item.matches("\\d+")){//多位数入栈
          stack.push(item)
        } else {//pop 出两个数并运算在入栈
          val num1 = stack.pop().toInt
          val num2 = stack.pop().toInt
          item match {
            case "+" => res = num1+num2
            case "-" => res = num2-num1
            case "*" => res = num1*num2
            case "/" => res = num2/num1
            case _ => throw new RuntimeException("运算符有问题")
          }
          stack.push(res.toString)
        }
      }
    )
    //最后留在stack中的数据就是结果
    stack.pop().toInt
  }

  /**
   * 中缀表达式转成arr
   * @param exp 中缀表达式
   * @return
   */
  def toInfixArr(exp: String) : Array[String] = {
    val exp_ = exp.replaceAll("\\s+", "")
    var i = 0 //遍历中缀字符串的下标
    var str = "" //多位数拼接
    val list = new ArrayBuffer[String]()
    var c = '0'
    do {
      //如果是一个非数字,加入到list
      c = exp_.charAt(i)
      if( c < 48 || c > 57){
        list.append(c.toString)
        i += 1
      } else {//如果是数需要考虑多位数
        str = ""
        while (i < exp_.length() && c >= 48 && c <= 57){
          str += c
          i += 1
          if (i < exp_.length) c = exp_.charAt(i)
        }
        list.append(str)
      }
    }while(i < exp_.length)
    list.toArray
  }

  /**
   * 1) 初始化一个栈和List:运算符栈 s1 和储存中间结果的List s2;
   * 2) 从左至右扫描中缀表达式;
   * 3) 遇到操作数时,将其压 s2;
   * 4) 遇到运算符时,比较其与 s1 栈顶运算符的优先级:
   *    1.如果 s1 为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
   *    2.否则,若优先级比栈顶运算符的高,也将运算符压入 s1;
   *    3.否则,将 s1 栈顶的运算符弹出并压入到 s2 中,再次转到(4-1)与 s1 中新的栈顶运算符相比较;
   * 5) 遇到括号时:
   *    1.如果是左括号“(”,则直接压入 s1
   *    2.如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
   * 6) 重复步骤 2 至 5,直到表达式的最右边
   * 7) 将 s1 中剩余的运算符依次弹出并压入 s2
   * 8) 依次弹出 s2 中的元素并输出,结果的逆序(栈)即为中缀表达式对应的后缀表达式
   *
   * 注意:栈s2是做存储作用,一直没有弹栈,可用list替换直接输出list
   */
  def parseInfix2Suffix(infix: Array[String]): Array[String] = {
    //(3 + 4) * 5 - 6
    val s1 = new mutable.Stack[String]
    val s2 = new ArrayBuffer[String]
    infix.foreach(item=>{
      if(item.matches("\\d+")){
        //数直接入栈
        s2.append(item)
      } else if(item.equals("(")){
        //如果是左括号“(”,则直接压入 s1
        s1.push(item)
      } else if(item.equals(")")){
        //如果是右括号“)”,则依次弹出 s1 栈顶的运算符,并压入 s2,直到遇到左括号为止,此时将这一对括号丢弃
        while (!s1.top.equals("(")){
          s2.append(s1.pop())
        }
        s1.pop()//将小括号弹出消除一对括号
      } else {
        //当 item 的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到 s2 中,再次转到(4.1)与 s1 中新的栈顶运算符相比较
        while (s1.nonEmpty && getPri(s1.top) > getPri(item) ){
          s2.append(s1.pop())
        }
        //将item压入栈中
        s1.push(item)
      }
    })
    //将 s1 中剩余的运算符依次弹出并压入 s2
    while (s1.nonEmpty){
      s2.append(s1.pop())
    }
    s2.toArray
  }

  def getPri(oper: String): Int = {
    oper match {
      case "+" => 1
      case "-" => 1
      case "*" => 2
      case "/" => 2
      case _ =>
//        println(s"不存在该运算符:$oper")
        0
    }
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值