====== 表达式求值 ======
表达式求值基本有两种算法,算法优先和语法分析
通常我们写的2+3×4叫中缀表达式,算法优先算法很依赖于和中缀表达式等价的后缀表达式,而借助二叉树求值本质也是一样的。
中缀转后缀的基本步骤
有个操作符栈opStack,保留暂时的优先级比较低的操作符,比如3+2*4,当碰到3时就要先入栈
碰到左括号(就一定进opStack,等再碰到左括号)时,将栈中直到左括号为止的所有操作符出栈使用,(使用指的是参与计算或拼二叉树,或拼后缀表达式)
碰到操作符,将栈顶开始往下的所有优先级大于等于本操作符的操作符出栈使用,本操作符入栈。
碰到操作数,直接使用。
贴一下代码先
package expression;
import java.util.Stack;
public class OperatorPrecedence
{
/**
* 暂不支持负号,但可以考虑,字符串开头的或操作符后紧挨的或括号后的减号必须算做负号
* @param infixStr
* @return
*/
public String infix2sufix(String infixStr){
StringBuilder rst = new StringBuilder();
Stack<Operator> opStack = new Stack<Operator>();
int len = infixStr.length();
for(int i=0;i<len;i++)
{
char c = infixStr.charAt(i);
//空格过滤掉
if(c == ' ')
{
rst.append(" ");
}
else if(Character.isDigit(c) || c=='.')
{
rst.append(c);
}
else if(c == '(')
{
opStack.push(new Operator('('));
}
else if(c == ')')
{
while(opStack.size()>0 && !(opStack.peek().equals(new Operator('('))))
{
rst.append(" "+opStack.pop().getSymbol());
}
//将左括号去除
assert opStack.peek().equals(new Operator('('));
opStack.pop();
}
else if(Operator.operators.contains(String.valueOf(c)))
{
Operator current = new Operator(c);
//栈空或当前优先级比栈顶的大才入栈,否则,栈内优先级小的挨次出栈拼结果
//pop out all the greater percedence operator
while(opStack.size()>0 && current.compareTo(opStack.peek())<=0)
{
rst.append(" "+opStack.pop().getSymbol());
}
//本操作符入栈
opStack.push(current);
rst.append(" ");
}
}
while(opStack.size()>0)
{
rst.append(" "+opStack.pop().getSymbol());
}
return rst.toString();
}
/**
* @param args
*/
public static void main(String[] args)
{
OperatorPrecedence o = new OperatorPrecedence();
System.out.println(o.infix2sufix("4-(4-3*5+(2*4)+100)/10"));
}
}
package expression;
import java.util.HashMap;
import java.util.LinkedList;
public class Operator implements Comparable
{
private static HashMap<Operator,Integer> ops = new HashMap<Operator,Integer>();
public static LinkedList<String> operators = new LinkedList<String>();
static{
ops.put(new Operator("("),0);
ops.put(new Operator("+"),1);
ops.put(new Operator("-"),1);
ops.put(new Operator("*"),100);
ops.put(new Operator("/"),100);
for(Operator o : ops.keySet())
{
operators.add(o.s);
}
}
private String s;
public String getSymbol()
{
return s;
}
@Override
public boolean equals(Object obj)
{
if(!(obj instanceof Operator))
{
return false;
}
return this.s.equals(((Operator)obj).s);
}
@Override
public int hashCode()
{
return this.s.hashCode();
}
public Operator(String s)
{
this.s = s;
}
public Operator(char c)
{
this.s = String.valueOf(c);
}
public int compareTo(Object o)
{
return ops.get(this) - ops.get(o);
}
/**
* @param args
*/
public static void main(String[] args)
{
System.out.println(ops.get(new Operator("@")));
}
}
1.
优化:
为避免特殊处理左括号,右括号,以及最后特殊处理操作符栈中的最后剩余操作符。也将他们定义了特定的优先级。
并在栈低放了个优先级很低的特殊的操作符#,初始化一个二维表来存储优先级关系,设定只有栈中(碰到),栈中#碰到#时,优先级为相等,
这时脱去括号。
这样写出的代码更简练一些。
见严蔚敏c语言版《数据结构》,这是偶的大学教程。
2.
其中描述的允许可以拼后缀表达式,
也可以另加一个栈存放操作数,当使用操作数时入栈,当使用操作符时,靠顶两个操作数出栈运算后结果再入栈。这样就直接得到表达式的结果。
如果把其中的运算换成“构建二叉树节点”,这里可以构建出一个表达式的二叉树来(中序遍历就是中缀表达式,后序遍历就是后缀)。
这样可以构建二叉树递归计算二叉树取结果或者直接取表达式的结果
3.
表达式求值的另一种方法,也是最灵活易懂的方式利用编译原理的语法分析。
可以收工根据语法分析来,也可以使用ANTLR这个工具
手工语法分析是要有些编译原理的知识,待续。。
如果用三方工具就简单得多,见另一篇
http://appofis.iteye.com/admin/blogs/743714
分享到:
相关推荐
以下是一个基本的表达式求值算法步骤: 1. 从左到右遍历表达式。 2. 如果遇到操作数,直接压入栈中。 3. 如果遇到运算符,与栈顶运算符比较优先级: - 如果栈为空,或者当前运算符优先级高于/等于栈顶运算符,将...
在C++中,实现表达式求值可以通过以下几种方法: 1. **中缀表达式求值**:这是最常见的形式,即我们日常看到的运算符位于操作数之间的表达式。实现时,可以使用栈数据结构辅助,遇到数字时入栈,遇到运算符时比较...
在表达式求值过程中,通常会使用到以下几种技术: 1. **语法分析**:这是将输入的字符串(表达式)转换成抽象语法树(AST)的过程。在C语言中,可以使用字符串函数如`strtok()`来分隔表达式中的运算符和操作数。 2. ...
在算数表达式求值的实现过程中,我们可以将其分为几个功能模块,例如: * 输入模块:负责读取算数表达式的输入 * 分析模块:负责对算数表达式进行语法分析和语义分析 * 求值模块:负责对算数表达式进行求值 * 输出...
表达式求值的核心算法通常基于“后缀表达式”(也称为逆波兰表示法)或“中缀表达式”转换。后缀表达式避免了括号的使用,通过操作符出现在它们的操作数之后来简化求值过程。在我们的程序中,我们可能需要实现一个...
这篇实验报告主要探讨了如何利用栈来实现算术表达式...总的来说,这篇实验报告详细阐述了如何利用栈和后缀表达式来实现算术表达式的求值,包括了算法设计、数据结构和程序模块划分,为初学者提供了一个很好的学习范例。
整体来看,文档详细介绍了在JavaScript中如何实现几种基础的算术运算算法,这些算法在处理更复杂的数值计算问题时有着广泛的应用,例如在科学计算、工程软件等领域。通过对这些基本算法的理解和掌握,可以帮助我们更...
### C++四则混合运算表达式求值算法详解 #### 引言 四则运算表达式通常由操作数、操作符以及括号组成。其中,操作数可以是任意实数,而操作符主要包括加(+)、减(-)、乘(*)及除(/)。在计算机科学中,有效地...
Java中缀表达式求值是一种常见的计算机算法,用于评估中缀表达式的值。中缀表达式是一种常见的数学表达式形式,但是在计算机中难以直接计算,因为它的运算符优先级和结合性规则使得计算变得复杂。 解决这个问题的一...
栈主要由以下几种基本操作构成: - **初始化**:创建一个新的空栈。 - **压栈(Push)**:向栈顶添加一个新元素。 - **弹栈(Pop)**:移除栈顶元素。 - **获取栈顶元素**:查看但不移除栈顶元素。 - **销毁栈**:...
在C++中,实现表达式求值通常涉及以下几个步骤: 1. **输入解析**:程序首先需要读取用户输入的表达式,例如"3 + 4 / 4 + 9 * 2"。由于表达式是以空格分隔的,因此可以使用C++的标准库函数如`std::getline`来读取...
这篇报告主要讨论的是一个大一下学期数据结构课程的设计项目,目标是实现一个算数表达式求值的程序。这个程序采用“算符优先法”来处理包含加减乘除及括号的算术表达式,并通过栈这一数据结构来辅助计算。 首先,...
在表达式求值中,通常有以下几个步骤: 1. **扫描表达式**:遍历输入的中缀表达式,识别出操作数和操作符。 2. **转换为后缀表达式**:如果需要的话,可以将中缀表达式转换为后缀表达式。这一步通过维护一个操作符栈...
在提供的代码文件"算数表达式2.cpp"中,可能实现了上述的某一种或几种遍历策略来完成算术表达式的求值。通常,这样的代码会包括解析字符串表达式到二叉树的构建过程,以及根据遍历策略进行计算的逻辑。具体实现细节...
5. **表达式求值算法**:基于后缀表达式的求值算法通常采用遍历的方式,从左到右读取表达式中的每一个元素,如果遇到数字就压入操作数栈,遇到运算符就弹出栈顶的两个操作数进行运算,结果再压回栈中。最后,栈顶...
在哈工大的数据结构课程中,学生被分配了一项作业,任务是实现一个算数表达式求值的程序。这个程序不仅需要处理基本的算数运算,如加法、减法、乘法和除法,还要扩展到处理小数计算以及涉及变量的计算。这个项目旨在...
在编程领域,表达式求值(Expression Evaluation)是一项基础但至关重要的任务,它涉及将一个数学或逻辑表达式转换为实际的数值结果。本主题主要关注如何利用栈数据结构和面向对象的思想来实现表达式求值函数。栈是...
在计算机科学中,表达式求值是编程领域中的一个基本概念,它涉及到计算数学或逻辑表达式的值。这里,我们关注的是使用C语言实现表达式求值,特别是通过栈这一数据结构来完成。栈是一种后进先出(LIFO)的数据结构,...
在实现算术表达式求值的过程中,通常会分为以下几个步骤: 1. **输入解析**:这是程序的第一步,需要读取用户输入的算术表达式。这可能涉及到字符串处理,例如使用分隔符(如空格)将表达式拆分成操作数和运算符。 ...
在完成设计时,学生通常会参考相关的教材、论文和技术文档,以获取更多关于表达式求值算法的理论知识和实践经验。 通过这样的课程设计,学生不仅能掌握栈这一基本数据结构的应用,还能深入理解运算符优先级、表达式...