后缀表达式转换及计算
后缀表达式转换及计算
言不莫 发表于2年前
后缀表达式转换及计算
  • 发表于 2年前
  • 阅读 5
  • 收藏 1
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: 最近在做一个项目,用到了后缀表达式的转换思想,这里复习一下后缀表达式的使用。

1、介绍

    中缀表达式:( ( 78 - 72 ) * 4 - ( 1 + 3 ) / 2 ) * 7

      后缀表达式:78, 72, -, 4, *, 1, 3, +, 2, /, -, 7, *(前缀表达式与后缀表达式相反,这里不做介绍)

中缀表达式便于记忆,容易理解,但是计算机不容易理解,毕竟计算机全是 只认识01,不能理解复杂的逻辑,所以,将中缀表达式装换成后缀表达式,便于程序处理。

2、算法思想

2.1、中缀----后缀

 (1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
 (2) 从左至右扫描中缀表达式;
 (3) 遇到操作数时,将其压入S2;
 (4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
 (4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
 (4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
 (4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
 (5) 遇到括号时:
 (5-1) 如果是左括号“(”,则直接压入S1;
 (5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
 (6) 重复步骤(2)至(5),直到表达式的最右边;
 (7) 将S1中剩余的运算符依次弹出并压入S2;
 (8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。

2.2、后缀计算

        从左至右扫描表达式,遇到数字时,将数字压入堆栈,
 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;
 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。

3 Code

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;
/**
 * 中缀表达式得到后缀表达式
 * @author yanbu
 *
 */
public class MidToSuffix {
 
 /*将中缀表达式转换为后缀表达式: 核心思想
 与转换为前缀表达式相似,遵循以下步骤:
 (1) 初始化两个栈:运算符栈S1和储存中间结果的栈S2;
 (2) 从左至右扫描中缀表达式;
 (3) 遇到操作数时,将其压入S2;
 (4) 遇到运算符时,比较其与S1栈顶运算符的优先级:
 (4-1) 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
 (4-2) 否则,若优先级比栈顶运算符的高,也将运算符压入S1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
 (4-3) 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;
 (5) 遇到括号时:
 (5-1) 如果是左括号“(”,则直接压入S1;
 (5-2) 如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
 (6) 重复步骤(2)至(5),直到表达式的最右边;
 (7) 将S1中剩余的运算符依次弹出并压入S2;
 (8) 依次弹出S2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)。*/
 
 /**
  * 运算符栈S1
  */
 Stack<String> s1 = new Stack<>();
 
 /**
  * 中间结果的栈S2
  */
 Stack<Object> s2 = new Stack<>();
 
 /**
  * 存储中缀表达式  格式自己定义
  * 这里每个表达式元素之间均以空格隔开
  */
 List<String> exps = new ArrayList<>();
 
 String expression;
 
 /**
  * 存储操作符优先级
  */
 Map<String, Integer> op = new HashMap<String, Integer>();
 
 public MidToSuffix(){
  op.put("+", 1);
  op.put("-", 1);
  op.put("*", 2);
  op.put("/", 2);
 }
 
 
 public void dealExps(){
  String[] exs = expression.split(" ");
  for (String exp : exs) {
   if(!exp.trim().equals("")){
    this.exps.add(exp.trim());
   }
  }
 }
 
 /**
  * 从左至右扫描中缀表达式
  */
 public void initStacl(){
  
  for (String exp : exps) {
   System.out.println("s1:" + s1 +"     " + "s2:" + s2);
   
   switch (exp) {
   case "(":  //处理括号()--参考操作(5)
    s1.push(exp);
    break;
   case ")":
    s1ToS2();
    break;
   default:
    op4(exp);
    break;
   }
  }
  
  s1ToS2(); 
  
 }
 
 /**
  * 操作(5),括号处理
  * 依次弹出S1栈顶的运算符,并压入S2,直到遇到左括号为止,此时将这一对括号丢弃;
  * /n同时可用于s1元素全部入栈S2
  */
 public void s1ToS2(){
  while(!s1.empty()){
   String ops = s1.pop();
   if(ops.equals("(")){
    return;
   }
   s2.push(ops);
  }
 }
 
 /**
  * 操作(4)
  * @param exp
  */
 public void op4(String exp){
  //参考操作(4)
  if(Pattern.matches("^[0-9]*$", exp)){ //遇到操作数时,将其压入S2;
   s2.push(Integer.parseInt(exp));
  }else{
   if(s1.isEmpty() || s1.peek().equals("(")){  //s1为空,操作符入栈S1
    s1.push(exp);
   }else{
    if(op.get(exp) > op.get(s1.peek())){  //比较操作符优先级,大于直接入栈  否则栈s1顶元素出栈,该操作符入栈
     s1.push(exp);
    }else{
     s2.push(s1.pop()); //栈顶元素出栈
     s1.push(exp); //操作符入栈
    }
   }
  }
 }
 
 public void setExpression(String expression){
  this.expression = expression;
 }
 
 /**
  * 获取后缀表达式
  * @param expression
  * @return
  */
 public  Stack<Object> getSuffix(String expression){
  setExpression(expression);
  dealExps();
  initStacl();
  return this.s2;
 }
 
}

 

import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
/**
 * 计算后缀表达式
 * @author yanbu
 */
public class CpuSuffix {
 
 MidToSuffix midToSuffix = new MidToSuffix();
 
 /** 核心思想
  * 从左至右扫描表达式,
  * 遇到数字时,将数字压入堆栈,
  * 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;
  * 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
  * @param args
  */
 
 /**
  * 用于存放计算结果
  */
 public Stack<Object> s1 = new Stack<>();
 
 
 
 public void initSuffix(String MidExp){
  Stack<Object> stack = midToSuffix.getSuffix(MidExp);
  System.out.println("suffix:" + stack);
  Set<String> op = midToSuffix.op.keySet();
  for (Object object : stack.toArray()) {
   System.err.println(s1);
   if(op.contains(object)){
    Integer num2 = (Integer)s1.pop();
    Integer num1 = (Integer)s1.pop();
    s1.push(op(object.toString(),num1,num2));
   }else{
    s1.push(object);
   }
  }
  
  System.err.println(s1);
 }
 
 public int op(String op, int num1,int num2){
  switch (op) {
  case "+":
   return num1 + num2;
  case "-":
   return num1 - num2;
  case "*":
   return num1 * num2;
  case "/":
   return num1 / num2;
  default:
   return 0;
  }
 }
 
 public static void main(String[] args) {
  CpuSuffix cpuSuffix = new CpuSuffix();
  String exp = new Scanner(System.in).nextLine();
  cpuSuffix.initSuffix(exp);
 }
}

 

Console:

( ( 78 - 72 ) * 4 - ( 1 + 3 ) / 2 ) * 7
s1:[]     s2:[]
s1:[(]     s2:[]
s1:[(, (]     s2:[]
s1:[(, (]     s2:[78]
s1:[(, (, -]     s2:[78]
s1:[(, (, -]     s2:[78, 72]
s1:[(]     s2:[78, 72, -]
s1:[(, *]     s2:[78, 72, -]
s1:[(, *]     s2:[78, 72, -, 4]
s1:[(, -]     s2:[78, 72, -, 4, *]
s1:[(, -, (]     s2:[78, 72, -, 4, *]
s1:[(, -, (]     s2:[78, 72, -, 4, *, 1]
s1:[(, -, (, +]     s2:[78, 72, -, 4, *, 1]
s1:[(, -, (, +]     s2:[78, 72, -, 4, *, 1, 3]
s1:[(, -]     s2:[78, 72, -, 4, *, 1, 3, +]
s1:[(, -, /]     s2:[78, 72, -, 4, *, 1, 3, +]
s1:[(, -, /]     s2:[78, 72, -, 4, *, 1, 3, +, 2]
s1:[]     s2:[78, 72, -, 4, *, 1, 3, +, 2, /, -]
s1:[*]     s2:[78, 72, -, 4, *, 1, 3, +, 2, /, -]
suffix:[78, 72, -, 4, *, 1, 3, +, 2, /, -, 7, *]
[]
[78]
[78, 72]
[6]
[6, 4]
[24]
[24, 1]
[24, 1, 3]
[24, 4]
[24, 4, 2]
[24, 2]
[22]
[22, 7]
[154]

 

 

标签: 后缀表达
共有 人打赏支持
粉丝 0
博文 2
码字总数 2424
×
言不莫
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: