文档章节

后缀表达式转换及计算

 言不莫
发布于 2016/01/03 14:13
字数 1721
阅读 10
收藏 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
南京
数据结构-栈应用(中缀转后缀并计算结果)

关于中缀和后缀表达式基础概念自行百度。 对于中缀转后缀表达式并计算结果思路可归纳为以下: 1、将每个数据当做一个结构体,包含对应的类型以及数值; 2、对于给定的中缀表达式,转为结构体数...

sssssuuuuu666
2017/12/19
0
0
Java数据结构和算法(六)——前缀、中缀、后缀表达式

前面我们介绍了三种数据结构,第一种数组主要用作数据存储,但是后面的两种栈和队列我们说主要作为程序功能实现的辅助工具,其中在介绍栈时我们知道栈可以用来做单词逆序,匹配关键字符等等,...

architect刘源源
02/23
126
1
phoenixor/rpn.js

rpn.js 功能概述 数学运算表达式分3种: 1.前缀表达式(波兰式Prefix Expression):运算符在操作数之前。 2.中缀表达式(Infix Expression):一种通用的算术或逻辑公式表示方法,操作符以中...

phoenixor
04/01
0
0
前缀、中缀、后缀表达式

前缀、中缀、后缀表达式,它们之间的区别在于运算符相对与操作数的位置不同:前缀表达式的运算符位于与其相关的操作数之前;中缀和后缀同理。对计算机来说中缀表达式是很复杂的,因此计算表达...

silenceyawen
2016/10/16
10
0
深入理解前缀、中缀、后缀表达式

1.我们首先来看一下,什么是前缀、中缀、后缀表达式: 中缀表达式: 2 - 3 4 后缀表达式:2 3 4 - 前缀表达式:- 2 * 3 4 简单介绍下,前中后的划分依据为两个数字的操作符处于两个数字的前面...

Lucus_Guo
2015/09/16
475
0

没有更多内容

加载失败,请刷新页面

加载更多

使用JDK自带的jmap和jhat监控处于运行状态的Java进程

对于处于运行状态中的Java进程,JDK自带了很多工具,允许Java开发人员监控运行进程中的各种状态,比如该进程内部创建了多少个对象实例,消耗了多少内存,等等。 本文基于JDK1.8而写成。 我下...

JerryWang_SAP
10分钟前
1
0
下单接口调优实战,性能提高10倍

概述 最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了,如果改动太大,怕有风险。另外开发成本和测试成本也非常大。对于这种...

Sam哥哥聊技术
43分钟前
2
1
rabbitMQ的安装和配置

在Windows下进行rabbitMQ的安装 第一步:软件下载 在安装rabbitMQ之前,需要先安装Erlang。 Erlang官网:http://www.erlang.org/downloads rabbitMQ官网:http://www.rabbitmq.com/download....

狼王黄师傅
今天
3
0
Vue-Element-Upload

记录一下文件上传封装Js 代码示例 封装:uploadFile.vue <template> <el-upload v-model="attachment" ref="upload" class="upload-demo" :action="uploadUrl" ......

华山猛男
今天
4
0
AWVS破解及使用手册

1.安装 因为是windows软件,比较简单,此部分略: 破解插件下载: 链接: https://pan.baidu.com/s/1x9LK9F3KvqDgTvXDjoSZnQ 提取码: 7k4u 2.创建扫描目标 2-1.Targets->Add Target 2-2.对话框...

硅谷课堂
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部