我正在Android Studio中使用Java开发一个科学计算器.我使用Streatergy设计模式来处理操作,并将分流堆场算法用于Calculate函数,因为它遵循BODMAS规则.

我有两个问题.

  1. BODMAS规则运行良好,但如果存在相同的优先操作,则它不遵循从左到右的规则.
  2. 如何在其中包含"cos"、"sin"等函数?它应该遵循BODMAS规则.

Bellow是我到目前为止开发的代码.我关心的是基于char数组实现的算法.如果我要识别"cos",我必须搜索字母‘c’或任何其他函数,首先搜索字母,然后遍历下一个元素,找到完整的函数名.有没有其他方法可以做到这一点?还有它是如何在从左到右的规则中发挥作用的,这些科学功能.

以下是我到目前为止开发的代码.

如有任何建议,我们将不胜感激.

谢谢.

public class ScientificCalculator {
public Operation operation;

public ScientificCalculator(Operation operation){
  this.operation = operation;
}

public double calculate(String exp) {
  char[] tokens = exp.toCharArray();
  Queue values = new LinkedList<>();
  Stack ops = new Stack();

  for (int i = 0; i < tokens.length; i++) {
    if (tokens[i] == ' ') {
      continue;
    }
    else if (Character.isDigit(tokens[i])) {
      StringBuffer sbuf = new StringBuffer();
      while (i < tokens.length && Character.isDigit(tokens[i])) {
        sbuf.append(tokens[i]);
        if ((i + 1) < tokens.length && Character.isDigit(tokens[i+1])) {
          i++;
        } else {
          break;
        }
      }
      values.add(Double.parseDouble(sbuf.toString()));
    } else if (tokens[i] == 'x' || tokens[i] == '-' || tokens[i] == '/' || tokens[i] == '+') {
      if (ops.isEmpty()) {
      ops.push(tokens[i]);
      continue;
    }
      char op1 = ops.peek();
      boolean hasHighPrecedence = hasPrecedence(op1, tokens[i]);
      if (hasHighPrecedence) {
      char op = ops.pop();
      values.add(op);
      ops.push(tokens[i]);
      } else {
        ops.push(tokens[i]);
      }
    } else if (tokens[i] == '(') {
        ops.push(tokens[i]);
    } else if (tokens[i] == ')') {
        while (ops.peek() != '(') {
          values.add(ops.pop());
    }
    ops.pop();
    }
  }
  while (!ops.isEmpty()) {
    values.add(ops.pop());
  }
  Stack numStack = new Stack<>();
  while (!values.isEmpty()) {
    Object val = values.poll();
    if (val instanceof Character) {
      char v = (Character) val;
      if (v == 'x' || v == '-' || v == '/' || v == '+') {
        double num2, num1;
        num1 = numStack.pop();
        num2 = numStack.pop();
        double ans = applyOp(v, num1, num2);
        numStack.push(ans);
      }
    } else {
    double num = (double) val;
    numStack.push(num);
    }
  }
  return numStack.pop();
}
public static double applyOp(char op, double b, double a) {
  switch (op) {
    case '+':
      return new addition().calculate(a,b);
    case '-':
      return new subtraction().calculate(a,b);
    case 'x':
      return new multiplication().calculate(a,b);
    case '/':
      if (b == 0)
        throw new
              IllegalArgumentException("Cannot divide by zero");
      return new division().calculate(a,b);
    }
    return 0;
  }

  public static boolean hasPrecedence(char op1, char op2) {
    if ((op1 == 'x' || op1 == '/') && (op2 == '+' || op2 == '-')){
      return true;
    } else {
      return false;
    }
  }
}

推荐答案

可以使调车场算法遵循左关联规则或右关联规则.最常见的运算符+、-、*、/是左结合的,但有些运算符,如赋值,通常是右结合的.所以x-y- z被解释为(x-y)- z并且x = y = z是x =(y = z),y被设置为z的值,然后x被设置为这个值.

让我们考虑一下,如果我们try 并解析3-4+5,它应该被解释为(3-4)+5,给4,而不是3-(4+5)给-6.+和-通常具有相同的优先级.

  • 首先在输出上加3.
  • 然后将-推入操作符堆栈
  • 接下来,将4加到输出
  • 我们现在找到了+
    • 将-从堆栈中弹出并添加到输出
    • 将+推送到堆栈
  • 接下来,将5加到输出
  • 最后,将剩余的+从堆栈中弹出并添加到输出中

那么输出将是3 4-5+

我们在维基百科的例子中看到了这一点,https://en.wikipedia.org/wiki/Shunting_yard_algorithm#The_algorithm_in_detail

while (
        there is an operator o2 at the top of the operator stack which is not a left parenthesis, 
        and (o2 has greater precedence than o1 or (o1 and o2 have the same precedence and o1 is left-associative))
    ):
        pop o2 from the operator stack into the output queue
push o1 onto the operator stack

在您的代码中

boolean hasHighPrecedence = hasPrecedence(op1, tokens[i]);
if (hasHighPrecedence || 
    ( hasEqualPrecedence(op1,tokens[i]) && isLeftAssociative(op1) )) {
  char op = ops.pop();
  values.add(op);
  ops.push(tokens[i]);
} else {
    ops.push(tokens[i]);
}

对于第二部分,对于调车场算法的目的,应该将函数调用与其他终端符号(变量或数字)同等对待.在我的代码中,我有一个方法prefixSuffix(),它的工作是解析所有的表达式,如5、x、++x、x++、函数调用和带括号的表达式.调车场部分只是用来处理二元运算符.对于函数调用和带括号的表达式,它们的参数通过对调车场部分的递归调用进行解析.这一点在关于这个主题的其他SO答案中有解释.

Java相关问答推荐

Java 21虚拟线程会解决转向react 式单线程框架的主要原因吗?

在Java中将Charsequence数组更改为String数组或List String<>

空手道比赛条件

AlarmManager没有在正确的时间发送alert

我找不到&Quot;配置&的位置

如何修复IndexOutOfBoundsException在ClerView适配器的onRowMoved函数?

呈现文本和四舍五入矩形时出现的JavaFX窗格白色瑕疵

如何修复PDF重建过程中的文本定位

如何在Java记录中设置BigDecimal类型属性的精度?

有没有更快的方法在N个容器中删除重复项?

使SLF4J在Android中登录到Logcat,在测试中登录到控制台(Gradle依赖问题)

在Oracle JDBC连接中,连接失效和身份验证失效是什么意思?

来自外部模块的方面(对于Java+Gradle项目)不起作用

如何获得凌空cookies ,并设置它在下一个请求- android

泛型与泛型问题的完美解决方案?

处理4.3问题:javax.xml.ind包不存在(&Q;).您可能在学习GitHub教程时遗漏了库.&Q

为什么使用lo索引来解决二进制搜索问题不同于使用hi索引?

如何使用stream.allMatch()为空流返回false?

ReturnedRect在升级后反转

为什么Java编译器为没有参数的方法(getter方法)创建桥接方法