package com.citi.ww03140.ds.exp;
import java.util.HashMap;
import java.util.Stack;
/*
3. 后缀表达式
后缀表达式也称为逆波兰式(Reverse Polish Notation, RPN),更加广为人知一些,和前缀表达式刚好相反,是将操作符号放置于操作数之后,比如2 + 3 * (5 - 1)用逆波兰式来表示则是:2 3 5 1 - * +。
逆波兰式的计算也是从左往右依次读取,当读到操作符时,将之前的两个操作数做计算,然后替换这两个操作数和操作符,接着读取,重复此步骤。对于这个表达式,读到5 1 -,得到4,然后读取乘号,取出前面的3和上一步的计算结果4,并计算,到12,接着读取加号+,计算2 12 +得到14,计算结束。
上面这个步骤可以很容易的用栈来实现:
从左往右依次读取表达式,如果是数字则将该数字压栈,如果是符号,则将之前的两个数字出栈,做计算后,将计算结果压栈,直到表达式读取结束。栈中剩下的一个数就是计算结果。
逆波兰式看起来像波兰式反过来,比如5 + 1的波兰式是+ 5 1,逆波兰式为5 1 +或者1 5 +。也很明显,逆波兰式并不是简单的将波兰式反过来,因为,减法和除法中减数和被减数、除数与被除数是不能交换的,即- 10 5和- 5 10就完全不一样。
4. 中缀表达式到后缀表达式的转换
因为通过后缀表达式来进行计算只需要一个栈即可,从硬件和软件上实现都是极为便利的,因此逆波兰式在计算机领域的应用更加广泛,因此将中缀表达式转换为逆波兰式非常重要。
依然仅仅使用栈就可以将中缀表达式转换成逆波兰式,转换过程如下:
从左往右遍历中缀表达式中的每个数字和符号,弱是数字就输出,成为逆波兰式的一部分; 如果是右括号,或者是其他符号并且比当前栈顶符号的优先级低,则栈顶元素依次出栈并输出; 然后将当前符号进栈,重复以上操作直到结束。
还是以2 + 3 * (5 - 1)为例:
首先读入数字2,直接将其输出,输出为2,栈为空
接着读入加号+,由于栈为空,因此将其进栈,输出为2,栈为+
接着读入数字3,直接将其输出,输出为2 3,栈为+
接着读入乘号*,比栈顶元素优先级高,进栈,输出为2 3,栈为+ *
读入左括号(,直接进栈,输出2 3,栈为+ * (
读入数字5,直接将其输出,输出为2 3 5,栈为+ * (
读入减号-,栈顶元素为左括号,进栈,输出为2 3 5,栈为+ * ( -
读入数字1,直接将其输出,输出为2 3 5 1,栈为+ * ( -
读入右括号,依次输出栈顶元素,直到左括号,括号不输出,输出2 3 5 1 -,栈为+ *
已经无元素可读,依次输出栈顶元素,直到栈为空,输出2 3 5 1 - * +,栈为空
这样可以仅仅使用栈,首先将中缀表达式转换为逆波兰式,然后用本文第3节中的方法对后缀表达式进行求值,整个过程使用栈来完成即可。
5. 表达式树与逆波兰式
还可以通过另外一种方法来将一个表达式转换成波兰式和逆波兰式,这种方法依赖与树,首先需要根据表达式构建成树,仍然以2 + 3 * (5 - 1)为例,下图是其表达式树。
6. 后缀表达式计算
将表达式,依次取出来,存入Stack,遇到运算符, 依次取2个stack top element 进行运算,并结果压stack,直到中只有最后一个元素
*/
public class StackExp {
private final Stack<String> exps=new Stack<String>();
private final Stack<String> oper=new Stack<String>();
private final HashMap<String,Integer> mapping=new HashMap<String,Integer>();
public StackExp(){
mapping.put("+", 1);
mapping.put("-", 1);
mapping.put("*", 2);
mapping.put("%", 2);
mapping.put("/", 2);
mapping.put("^", 3);
mapping.put("(", 0);
mapping.put(")", 0);
mapping.put("|", -1);
}
public void transform(String expStr){
char[] chs=expStr.toCharArray();
for(int i=0;i<chs.length;i++){
String s=String.valueOf(chs[i]);
if(!mapping.containsKey(s)){
exps.add(s);
}else{
if("(".equals(s)){
oper.add(s);
}else if(")".equals(s)){
while(oper.size()>0 && !oper.peek().equals("(")){
exps.add(oper.pop());
}
oper.pop();
}else{
if(oper.isEmpty()){
oper.add(s);
}else{
int curOp=mapping.get(s);
int topOp=mapping.get(oper.peek());
if(curOp>topOp){
oper.add(s);
}else{
do{
exps.add(oper.pop());
}while(oper.size()>0 && (curOp<=mapping.get(oper.peek())));
oper.add(s);
}
}
}
}
}
while(oper.size()>0){
exps.add(oper.pop());
}
while(exps.size()>0){
oper.add(exps.pop());
}
printExp();
calculate();
System.out.println(exps.toString());
}
private void calculate(){
while(oper.size()>0){
String op=oper.pop();
if(mapping.containsKey(op)){
double d=calculate(op,Double.parseDouble(exps.pop()),Double.parseDouble(exps.pop()));
System.out.println(d);
exps.push(String.valueOf(d));
}else{
exps.push(op);
}
}
}
private void printExp(){
System.out.println(exps.toString());
}
private double calculate(String op,double d1, double d2){
if(op.equals("+")){
return d1+d2;
}
if(op.equals("-")){
return d1-d2;
}
if(op.equals("*")){
return d1*d2;
}
if(op.equals("/")){
return d1/d2;
}
if(op.equals("%")){
return d1%d2;
}
if(op.equals("^")){
return Math.pow(d1, d2);
}
return 0;
}
public static void main(String[] args) {
StackExp exp=new StackExp();
exp.transform("(1+2)*3-5+8+(1+2)*3-5+8");
}
}
分享到:
相关推荐
在这个程序中,数据结构可能包括栈(stack),这是用来处理后缀表达式计算的关键结构。栈遵循“后进先出”(LIFO)的原则,非常适合解决表达式求值的问题。 在C语言中,我们可以使用数组或链表来实现栈。当解析后缀...
在IT领域,表达式计算是计算机科学中的一个重要概念,它涉及到如何解析和处理数学或逻辑表达式以得出正确的结果。本文主要介绍了两种方法来实现表达式自动计算,这两种方法都是基于数据结构,特别是栈(Stack)的...
后缀表达式,又称逆波兰表示法,是数学表达式的一种表示形式,它在计算领域具有重要的应用价值,尤其在算法设计和计算机科学中。后缀表达式的主要优点在于其简洁性和易于用栈来实现计算,这使得它成为解决计算问题的...
- 在中缀表达式计算中,我们用一个栈存储运算符,另一个栈存储中间结果。 2. **算法步骤**: - 从左到右扫描中缀表达式。 - 遇到数字时,将其压入结果栈。 - 遇到运算符时,比较其优先级与栈顶运算符的优先级:...
本主题聚焦于一个“简单实用的表达式计算类”,这是一个用于解析和计算数学表达式的类,其源码用标准C++编写,且无需借助栈来实现。这一设计思路使得代码更加简洁高效,同时也减少了内存管理和性能优化的复杂性。 ...
在本项目中,“数据结构 C语言实现表达式计算”旨在使用C语言来设计一个计算器,该计算器能处理包含整数、小数以及括号的数学表达式。下面将详细介绍涉及的知识点。 1. **C语言基础**: C语言是一种强大的、低级的...
2.赋值运算,即给某一变量赋值或赋计算表达式; 3.函数表达式求值,即运算量为变量。 4.运算量可以为实数,也可以为整数,只需简单修改宏定义。默认为实数运算。 二、数据结构设计 1. 算符优先法数据结构设计 本程序...
这个过程通常应用于计算机科学中的表达式计算,特别是编程语言的解析和计算。 首先,我们要理解中缀表达式和后缀表达式的基本概念。中缀表达式是我们常见的运算符位于操作数之间的表达式,如 `2 + 3 * 4`。而后缀...
MFC计算器项目是一个典型的桌面应用示例,它利用MFC库的强大功能实现了一个功能丰富的计算器,能够处理基本的数学运算以及更复杂的表达式计算。 首先,MFC计算器的核心是MFC框架。MFC提供了许多预定义的类,如...
### 中缀表达式计算知识点详解 #### 一、中缀表达式概述 中缀表达式是我们日常生活中最为常见的表达式形式,例如 \(8 + 5 \times (7 - 3)\)。在这种表达式中,操作符位于两个操作数之间。在计算这类表达式时,需要...
在本主题“栈数据类型之表达式计算”中,我们将深入探讨如何利用栈这一数据结构来解决表达式计算的问题,尤其是对于逆波兰表示法(RPN,也称为后缀表达式)的计算。 栈在表达式计算中的应用主要体现在两个方面:...
7. **堆栈(Stack)**: 堆栈数据结构在表达式计算中起到关键作用,特别是在后缀表达式(也称逆波兰表示法)的计算中。通过将运算符压入堆栈,可以按照后缀表达式规则进行计算,避免了优先级和括号的问题。 8. **...
C 语言后缀表达式计算 C 语言后缀表达式计算是计算机科学中的一种算法,用于计算后缀表达式的值。后缀表达式是一种特殊的表达式,所有操作符都写在操作数的后面。例如,中缀表达式「a+b*c」对应的后缀表达式为「a b...
首先,我们需要了解表达式计算的基本原理。在计算一个数学表达式时,我们通常遵循操作符的优先级,如括号内的运算优先于乘法和除法,乘法和除法又优先于加法和减法。这就是著名的“PEMDAS”规则(括号、指数、乘除、...
- Stack相关的模块:定义结构体stack,以及初始化、压栈、弹栈和检查栈空的函数,用于后缀表达式的计算。 在测试阶段,应设计不同类型的测试用例,包括一般数据(常规输入)、边界数据(如空输入、只有一个元素的...
标题中的“根据表达式计算结果DLL库”是指一个动态链接库(DLL)项目,它包含一组函数,能够根据输入的字符串表达式计算出其数学结果。这个DLL库的核心功能是`double __stdcall ComputeFromString(char *s);`,该...
《CMathString:多功能算术表达式计算类详解》 在计算机编程中,处理数学表达式的计算是一项常见的任务。为了简化这一过程,开发者们通常会创建特定的类或函数来解析和评估算术表达式。CMathString就是这样一种工具...
它通过消除括号和运算符优先级的问题,使得表达式计算变得简单且高效。在后缀表达式中,运算符位于其操作数之后,这与我们常见的中缀表达式(例如 `2 + 3 * 4`)不同,中缀表达式中运算符位于操作数之间。 在C++...
总的来说,用栈实现的中缀表达式计算涉及到栈的特性、运算符的处理、括号匹配和控制流程等多个方面的知识,是一个很好的学习和实践数据结构与算法的实例。通过这个过程,你不仅可以深入理解栈的运作原理,还能掌握...
- 对于左括号“(”,立即压入运算符堆栈,而右括号“)”出现时,会连续弹出运算符堆栈中的运算符,直到遇到左括号,这对应于括号内的表达式计算。 - 运算符的优先级和结合性是关键,例如,乘法和除法的优先级高于...