您好我一直在研究我的Java计算器。它现在将所有操作数和运算符放在不同的数组中,并且我还有一个具有每个运算符优先级的数组。
For example * and / are 1 and + and - are 2.
So if my operator array holds '[/, +, +, *]'
My priority array holds '[1, 2, 2, 1]'
我坚持的部分是我现在需要确保我的计算器可以重新排序运算符,这样我就可以通过我的calculateResult
并确保运算符的顺序正确。
我要求帮助的部分是计算结果。我无法弄清楚如何做到这一点,以便按正确的顺序计算它。
import java.util.*;
public class stringCalculator {
//String containing the input from the user
private String userinput;
//List to store the operators in
private ArrayList<String> calcOperator = new ArrayList<String>();
//List to store the operands in
private ArrayList<Integer> calcOperand = new ArrayList<Integer>();
//Array to store all the integers in
private String[] integers;
//Array to store all the operators in
private String[] operators;
//Array to store the priority value
private String[] priorityList;
public stringCalculator(String userinput){
this.userinput = userinput;
//System.out.println(userinput);
integers = userinput.split("[+-/*///]");
operators = userinput.split("\\d+");
}
//This function will check the input and return true if the user enters a correct expression.
public boolean checkInput(){
boolean show = userinput.matches("[-+/*0-9]+");
return show;
}
//This function will add any numbers in the string to the calcOperand array.
//and any operators to the calcOperator field.
public void parseInput(String[] item){
for (String op : item){
if (op.matches("\\d+")){
calcOperand.add(Integer.parseInt(op));
}
//operators go into calcOperators.
else if (op.equals("+")||op.equals("-")||op.equals("*")||op.equals("/")){
calcOperator.add(op);
}
else{//everything else is ignored and left.
}
}
}
//Function to calculate the priority of each operator.
//For example * and / will be 1, and + and - will be 2.
public void calculatePriority(){
priorityList = calcOperator.toArray(new String[calcOperator.size()]);
for (int i = 0; i<priorityList.length; i++){
if (priorityList[i].equals("+")){
priorityList[i] = "2";
}else if (priorityList[i].equals("-")) {
priorityList[i] = "2";
}else if (priorityList[i].equals("/")){
priorityList[i] = "1";
}else if (priorityList[i].equals("*")){
priorityList[i] = "1";
}else{
System.out.println("error");
}
}
}
public void printPri(){
for (String s : priorityList)
System.out.print(s +",");
}
//Function to show the result of the expression.
public void calculateResult(){
if(checkInput()){
parseInput(integers);
parseInput(operators);
System.out.println("Operands: " + calcOperand);
System.out.println("Operators: " + calcOperator);
calculatePriority();
System.out.print("Priority: ");
printPri();
}else{
System.out.println("Please enter a valid input!");
}
}
}
答案 0 :(得分:1)
执行此操作的正确方法是将输入解析为AST(抽象语法树)。然后以正确的顺序对表达式进行评估。
试图将所有问题都减少到表格解决方案的倾向是一种巨大的反模式,遗憾的是,许多程序员从未学习过。不是一切都是一张桌子。那里也有树木和图表。
几乎所有解析作业都应该导致树的构造(可能是也可能不是复合模式的实现)。
答案 1 :(得分:1)
生成操作树的一种方法的一个非常基本的例子。
我已经在一个Test
类中嵌套了这些类(因为我不想用额外的文件来处理)但是它应该很简单,可以拆分)。
MathNode
是表示树中节点的抽象类; ElementNode
是MathNode
的子类,表示数字值(以及树的叶子); SumNode
是表示操作的MathNode
的子类; tokenize()
遍历字符串查找操作(或字符串的结尾)和前面的数字,并创建相应的标记并将它们附加到数组中。makeTree()
遍历标记数组,当找到当前正在搜索的操作时,将树的左右节点设置为前一个和后一个标记(一旦添加,就从数组中删除这些标记)到了树)。tokenize()
然后makeTree()
四次,每次/
,*
,-
和+
操作一次,使用标记数组中剩下的单个节点构建树,树是树的根。 可以包含更多错误检查,并且我确信树构建可以显着提高效率(并且不需要四次通过),但是,希望这可以让您了解如何继续。< / p>
代码:
import java.util.ArrayList;
public class Test
{
public static enum Operation { MULTIPLY, DIVIDE, ADD, SUBTRACT };
abstract static class MathNode {
public abstract double calc();
public abstract String toString();
public abstract boolean set( final MathNode left, final MathNode right, final Operation op );
}
static class ElementNode extends MathNode {
private final double value;
public ElementNode( final double v ) {
this.value = v;
}
public double calc() {
return value;
}
public String toString() {
return Double.toString( value );
}
public boolean set( final MathNode left, final MathNode right, final Operation op ){
return false;
}
}
static class SumNode extends MathNode {
public MathNode left = null;
public MathNode right = null;
public final Operation op;
public SumNode( final Operation op ){
this.op = op;
}
public boolean set( final MathNode left, final MathNode right, final Operation op ){
if ( this.op == op )
{
this.left = left;
this.right = right;
return true;
}
return false;
}
public double calc() {
final double l = left == null ? 0 : left.calc();
final double r = right == null ? 0 : right.calc();
switch ( this.op ){
case MULTIPLY: return l * r;
case DIVIDE: return l / r;
case SUBTRACT: return l - r;
default: return l + r;
}
}
public String toString(){
final String l = left == null?"0":left.toString();
final String r = right == null?"0":right.toString();
switch ( this.op ){
case MULTIPLY: return "( " + l + " * " + r + " )";
case DIVIDE: return "( " + l + " / " + r + " )";
case SUBTRACT: return "( " + l + " - " + r + " )";
default: return "( " + l + " + " + r + " )";
}
}
}
public static ArrayList<MathNode> tokenize( final String sum )
{
int i = 0,
p = 0;
final int l = sum.length();
final ArrayList<MathNode> tokens = new ArrayList<MathNode>();
while ( i < l )
{
final SumNode sn;
switch ( sum.charAt(i) ){
case '*': sn = new SumNode( Operation.MULTIPLY ); break;
case '/': sn = new SumNode( Operation.DIVIDE ); break;
case '+': sn = new SumNode( Operation.ADD ); break;
case '-': sn = new SumNode( Operation.SUBTRACT ); break;
default:
// TODO: Add something to check if number is valid
++i;
continue;
}
// TODO: Add something to check for zero-width numbers
final double value = Double.parseDouble( sum.substring( p, i ) );
p = ++i;
tokens.add( new ElementNode( value ) );
tokens.add( sn );
}
// TODO: Add something to check for zero-width numbers
final double value = Double.parseDouble( sum.substring( p ) );
tokens.add( new ElementNode( value ) );
return tokens;
}
public static void makeTree( final ArrayList<MathNode> tokens, final Operation op ){
for ( int i = tokens.size() - 2; i >= 1; --i )
{
final MathNode node = tokens.get( i );
if ( node.set( tokens.get(i-1), tokens.get(i+1), op) )
{
tokens.remove( i + 1 );
tokens.remove( i - 1 );
--i;
}
}
}
public static void main(final String[] args) {
final String sum = "23.2-5.2*4.4/2.2+14";
final ArrayList<MathNode> tokens = tokenize( sum );
makeTree( tokens, Operation.DIVIDE );
makeTree( tokens, Operation.MULTIPLY );
makeTree( tokens, Operation.SUBTRACT );
makeTree( tokens, Operation.ADD );
final MathNode sum_tree = tokens.get(0);
System.out.println( sum_tree + " = " + sum_tree.calc() );
}
}
答案 2 :(得分:0)
您真的需要扫描所有操作员,计算优先级并重新排序所有内容吗?
如果您浏览了所有运算符和值,并仅评估*
和/
然后重新浏览并评估+
和-
可能比你想做的容易得多。