文档章节

后缀表达式转换及计算

 言不莫
发布于 2016/01/03 14:13
字数 1721
阅读 68
收藏 1

行业解决方案、产品招募中!想赚钱就来传!>>>

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
作品 0
南京
私信 提问
加载中
请先登录后再评论。
基于 ThinkPHP 的内容管理系统--歪酷CMS

歪酷网站管理系统(歪酷CMS)是一款基于THINKPHP框架开发的PHP+MYSQL网站建站程序,本程序实现了文章和栏目的批量动态管理,支持栏目无限分类,实现多管理员管理,程序辅助功能也基本实现了常见的文...

鲁大在线
2013/02/19
7K
1
Swing界面分析和调试工具--Swing Inspector

Swing Inspector是一个Java Swing/AWT用户界面分析和调试工具,功能与firebug类似,具有强大的Swing/AWT用户界面分析和调试相关功能。 适用于从java swing初级到高级的所有开发人员,能够快速...

匿名
2013/03/06
3.4K
0
开源数据访问组件--Smark.Data

Smark.Data是基于Ado.net实现的数据访问组件,提供基于强类型的查询表达式进行灵活的数据查询,统计,修改和删除等操作;采用基于条件驱动的操作模式,使数据操作更简单轻松;内部通过标准SQL...

泥水佬
2013/03/12
2.6K
0
硬实时操作系统--Raw OS

Raw-OS 起飞于2012年,Raw-OS志在制作中国人自己的最优秀硬实时操作系统。 Raw-OS 操作系统特性 内核最大关中断时间无限接近0us, s3c2440系统最大关中断时间实测0.8us。 支持idle任务级别的事...

jorya_txj
2013/03/19
6.2K
1
Java™ 编译器--Janino

Janino是一个超级小但又超级快的Java™ 编译器. 它不仅能像javac工具那样讲一组源文件编译成字节码文件,还可以对一些Java表达式,代码块,类中的文本(class body)或者内存中源文件进行编译,...

匿名
2013/04/02
4.1K
0

没有更多内容

加载失败,请刷新页面

加载更多

数据库高频面试点,事务/乐观锁/悲观锁/CAS/MySQL存储引擎

事务的ACID特性是什么? 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; 一致性: 执行事务前后,数据保持一致,多个事务对同一个数据读...

osc_45536bvu
56分钟前
16
0
大数据BI软件助力企业数字化转型

当下,「新基建」势头正盛,随着“新基建”成为热议话题,数字化也随之成为企业面临的新机遇和新挑战。新基建的核心就是数据,数据是数字经济和企业数字化转型的生产要素和发展动力。 再看看...

osc_0boqdoe2
57分钟前
7
0
凯旋创投来志刚:基因治疗新时代,大戏刚刚开始

  2017 年,全球第一个基因治疗方法 CAR-T 细胞药物 Kymriah 获得 FDA 上市批准,从此掀起了基因治疗的热潮。随着相关技术和政策的不断成熟,基因治疗市场也随之扩大。根据德勤发布的《引领...

osc_k3vwonkw
59分钟前
10
0
LightningChart.NET使用两个BarSeries创建简单的2D图表

本教程介绍了如何使用两个BarSeries创建简单的2D图表。 BarSeries将数据值表示为矩形条,并且可以用于以非常清晰的方式可视化数据之间的差异和方差。 在本教程中,BarSeries用于表示两年期间...

roffey
59分钟前
0
0
Mybatis trim 标签的 2 个妙用!

云栖号资讯:【点击查看更多行业资讯】 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! mybatis的trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼...

osc_x03qsedc
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部