最终我要接受这个:
2x + 3 = 5
求解x,方法是先从两边减去3,使2x = 2
,然后将两边除以2,从而x = 1
。我在想很多事情,应该如何在JavaScript中创建这样的函数,该函数可以返回按顺序完成的一系列步骤,包括结果。显然,“ eval”对此无能为力,因此貌似必须重新创建方程式。
我最初想到首先忽略X,然后尝试制作一个可以求解简单方程式的函数,而无需eval或任何内置函数。
我认为第一步是使用.split分解术语,但是我遇到了一些麻烦,因为我需要拆分多个 个符号。例如,假设我有一个简单的表达式求值:3 - 6 * 3 / 9 + 5
。因此,在进入操作顺序之前,仅分解每个术语(并将其分类)是困难的部分,这是我目前主要的具体问题。
我开始只是一个接一个地拆分,但是我遇到了一些问题,尤其是考虑顺序。
function solve(eq) {
var minuses = eq.split("-"),
pluses = minuses.map(x=> x.split("+")),
timeses = pluses.map(x=>x.map(y=>y.split("*"))),
dividers = timeses.map(x=>x.map(y=>y.map(z=>z.split("/"))));
console.log(minuses, pluses, timeses, dividers);
}
solve("3 - 6 * 3 / 9 + 5");
如您所见,对于每个连续的运算符,我都需要遍历前一个运算符的每个元素以进行拆分,然后剩下一个数组数组等。
所以1)如何在不为每个变量创建新变量的情况下更有效地分解这些术语,并手动递归地映射每个变量?看来我应该只拥有某种数组字典来跟踪操作顺序(现在不考虑括号或指数):["*","/","+","-"]
-并给出该数组,生成类似于上例中最后一个数组的内容( “除法器”)仅包含常量,并以某种方式跟踪每个存储数组遵循的元素...
和2)在给定值数组的情况下如何求解表达式?
我只是对逻辑有点困惑,我想我需要从最后一个数组开始处理,一次求解一个常量,跟踪哪个运算符是当前的,但是我不确定完全是
答案 0 :(得分:2)
虽然您的问题不需要构造,binary expression tree是集思广益解决数学查询逻辑的好方法。
因此对于查询3 - 6 * 3 / 9 + 5
,代表性的二进制表达式树为:
plus
|_minus
| |_3
| |_divide
| |_times
| | |_3
| | |_6
| |_9
|_5
要求解上面的树,您需要从叶级到根递归求解。
同样,您不需要构造树。它只是帮助我们了解在此处进行解析的逻辑:
考虑到以上逻辑,这是一个实现:
function solve(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return num;
}
} else {
var leftVal = solve(str.substring(0, expressionIndex).trim());
var rightVal = solve(str.substring(expressionIndex + 1).trim());
switch (str[expressionIndex]) {
case "+":
return leftVal + rightVal;
case "-":
return leftVal - rightVal;
case "*":
return leftVal * rightVal;
case "/":
return leftVal / rightVal;
}
}
}
function parse(str) {
var expressionIndex = Math.max(str.lastIndexOf("-"), str.lastIndexOf("+"));
if (expressionIndex === -1) {
expressionIndex = Math.max(str.lastIndexOf("*"), str.lastIndexOf("/"));
}
if (expressionIndex === -1) {
var num = Number.parseInt(str.trim());
if (isNaN(num)) {
throw Exception("not a valid number");
} else {
return { type: "number", value: num };
}
} else {
var leftNode = parse(str.substring(0, expressionIndex).trim());
var rightNode = parse(str.substring(expressionIndex + 1).trim());
return {
type: "expression",
value: str[expressionIndex],
left: leftNode,
right: rightNode
};
}
}
console.log(solve("3 - 6 * 3 / 9 + 5"));
console.log(parse("3 - 6 * 3 / 9 + 5"));
以上是仅使用+,-,*,/(例如不带括号)的非常简单查询的解决方案。为了像第一个示例一样求解方程,需要进行大量工作。
编辑:添加解析函数以返回树。
答案 1 :(得分:2)
您可以按照以下步骤进行操作:
split()
并除以+
和-
,这将在乘法和除法之后发生。map()
,然后split()
和*
再次使用/
。 sovleSingle
并执行加法和减法。只要没有括号()
,该功能与eval相同。
注意:这与在+
和-
中先出现或在*
和/
中先出现无关紧要。但是*,/
应该在+,-
function solveSingle(arr){
arr = arr.slice();
while(arr.length-1){
if(arr[1] === '*') arr[0] = arr[0] * arr[2]
if(arr[1] === '-') arr[0] = arr[0] - arr[2]
if(arr[1] === '+') arr[0] = +arr[0] + (+arr[2])
if(arr[1] === '/') arr[0] = arr[0] / arr[2]
arr.splice(1,1);
arr.splice(1,1);
}
return arr[0];
}
function solve(eq) {
let res = eq.split(/(\+|-)/g).map(x => x.trim().split(/(\*|\/)/g).map(a => a.trim()));
res = res.map(x => solveSingle(x)); //evaluating nested * and / operations.
return solveSingle(res) //at last evaluating + and -
}
console.log(solve("3 - 6 * 3 / 9 + 5")); //6
console.log(eval("3 - 6 * 3 / 9 + 5")) //6