2016-02-13 201 views
0

我不想解一个方程,我的问题不是关于图和树数据结构。我正在尝试从用户给出的公式中为图生成数据点。我想要高效的算法,易于使用且易于维护数据结构。我有两个解决方案在脑海中从等式生成图的数据点

1:这是微不足道的,我见过很多应用程序。

String expr = "2*x+3*x"; 
Evaluator evaluator = new Evaluator();//I have this class 

for (int i = start; i < end; i += step) 
{ 
    evaluator.setConstant("x", i); 
    double ans = evaluator.evaluate(expr); 
} 

这是非常缓慢的,因为每一个每一个步骤重复像tokenzing,验证,转换为RPN,准备栈和队列,并在最后结果的计算时间。这个问题的可能解决方案是以某种方式缓存所有堆栈和队列,但之后需要在当前表达式和以前的表达式之间进行比较以使用最后存储的状态。

2:目前我正在开发第二种解决方案。这样做的目的是效率,并将在未来的符号计算中使用。

到目前为止,我实现

Variable.java

import java.text.DecimalFormat; 

public class Variable 
{ 
    private final double pow; 
    private final double coefficient; 
    private final String symbol; 

    public Variable(String symbol) 
    { 
     this.symbol = symbol; 
     this.pow = 1.0; 
     this.coefficient = 1.0; 
    } 

    public Variable(String symbol, double coefficient, double pow)throws IllegalArgumentException 
    { 
     if (coefficient == 0.0)throw new IllegalArgumentException("trying to create variable with coefficient 0"); 
     if (pow == 0.0)throw new IllegalArgumentException("trying to create variable with exponent 0"); 

     this.symbol = symbol; 
     this.pow = pow; 
     this.coefficient = coefficient; 
    } 

    public final String getSymbol() 
    { 
     return this.symbol; 
    } 

    public final double getPow() 
    { 
     return this.pow; 
    } 

    public final double getCoefficient() 
    { 
     return this.coefficient; 
    } 

    @Override 
    public String toString() 
    { 
     StringBuilder builder = new StringBuilder(); 
     DecimalFormat decimalFormat = new DecimalFormat("#.############"); 
     if (coefficient != 1.0)builder.append(decimalFormat.format(this.coefficient)); 
     builder.append(this.symbol); 
     if (this.pow != 1.0)builder.append("^").append(decimalFormat.format(this.pow)); 

     return builder.toString(); 
    } 

    /* 
    * Stub Method 
    * Generate some unique hash code 
    * such that chances of key collision 
    * become less and easy to identify 
    * variables with same power and same 
    * symbol*/ 
    @Override 
    public int hashCode() 
    { 
     return 0; 
    } 
} 

Equation.java

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 

public class Equation 
{ 
    private final ArrayList<Boolean> operations; 
    private final HashMap<String, Variable> variableHashMap; 
    private int typesOfVariables; 

    public Equation(Variable variable) 
    { 
     this.variableHashMap = new HashMap<>(); 
     this.operations = new ArrayList<>(); 
     this.typesOfVariables = 1; 

     this.variableHashMap.put(variable.getSymbol(), variable); 
    } 

    /*Stub Method*/ 
    public void addVariable(Variable variable, boolean multiply) 
    { 
     /* 
     * Currently not covering many cases 
     * 1: Add two variables which have same name 
     * and same pow. 
     * 2: variable which are wrapped inside functions e.g sin(x) 
     * and many other.*/ 
     if (multiply && variableHashMap.containsKey(variable.getSymbol())) 
     { 
      Variable var = variableHashMap.get(variable.getSymbol()); 
      Variable newVar = new Variable(var.getSymbol(), var.getCoefficient() * variable.getCoefficient(), var.getPow() + variable.getPow()); 
      /* 
      * Collision chances for variables with same name but 
      * with different powers*/ 
      this.variableHashMap.replace(var.getSymbol(), newVar); 
     } 
     else 
     { 
      ++this.typesOfVariables; 
      this.variableHashMap.put(variable.getSymbol(), variable); 
     } 
     this.operations.add(multiply); 
    } 

    /*Stub Method 
    *Value for every variable at any point will be different*/ 
    public double solveFor(double x) 
    { 
     if (typesOfVariables > 1)throw new IllegalArgumentException("provide values for all variables"); 

     Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator(); 

     Variable var; 
     double ans = 0.0; 
     if (entryIterator.hasNext()) 
     { 
      var = entryIterator.next().getValue(); 
      ans = var.getCoefficient() * Math.pow(x, var.getPow()); 
     } 

     for (int i = 0; entryIterator.hasNext(); i++) 
     { 
      var = entryIterator.next().getValue(); 
      if (this.operations.get(i))ans *= var.getCoefficient() * Math.pow(x, var.getPow()); 
      else ans += var.getCoefficient() * Math.pow(x, var.getPow()); 
     } 
     return ans; 
    } 

    @Override 
    public String toString() 
    { 
     StringBuilder builder = new StringBuilder(); 
     Iterator<HashMap.Entry<String, Variable>> entryIterator = this.variableHashMap.entrySet().iterator(); 

     if (entryIterator.hasNext())builder.append(entryIterator.next().getValue().toString()); 

     Variable var; 
     for (int i = 0; entryIterator.hasNext(); i++) 
     { 
      var = entryIterator.next().getValue(); 
      if (this.operations.get(i))builder.append("*").append(var.toString()); 
      else builder.append(var.toString()); 
     } 

     return builder.toString(); 
    } 
} 

Main.java

class Main 
{ 
    public static void main(String[] args) 
    { 
     try 
     { 
      long t1 = System.nanoTime(); 

      Variable variable = new Variable("x"); 
      Variable variable1 = new Variable("x", -2.0, 1.0); 
      Variable variable2 = new Variable("x", 3.0, 4.0); 

      Equation equation = new Equation(variable); 
      equation.addVariable(variable1, true);//2x+x 
      equation.addVariable(variable2, true); 

      for (int i = 0; i < 1000000; i++)equation.solveFor(i);//Calculate Million Data Points 
      long t2 = System.nanoTime(); 

      System.out.println((t2-t1)/1000/1000); 
      System.out.println(equation.toString()); 
     } 
     catch (Exception e) 
     { 
      System.out.println("Error: " + e.getMessage()); 
     } 
    } 
} 

我在正确的方向前进? 这个问题有没有常用的算法?

我的主要目标是效率,代码清洁和代码可维护性。

注意:我不是英语母语的人,所以请忽略任何语法错误。

谢谢。

回答

0

我没有看到您的第一个代码有任何问题。是的,可能在你的代码的每一步“重复如令牌,验证,转换到RPN,准备堆栈和队列以及最后的结果计算”,但最终所有这些只是线性步数。所以我没有看到它如何使它真的很慢。

我看过的最大屏幕之一是2560x1440像素,这意味着大多数时候您需要少于2500点才能绘制图形。

如果你点是代码清洁和代码的可维护性,那么最有可能由5行代码比由200

+0

我想计算数百万个点的代码更好。 –