用调度场算法计算表达式的值,javascript实现
Posted 卡德加
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用调度场算法计算表达式的值,javascript实现相关的知识,希望对你有一定的参考价值。
最近想试下做微信小程序,刚开始写,想找点东西练手,试下写个计算器的小程序,查了一下,做表达式求值是用的Dijkstra的调度场算法,用两个栈就可以实现,一个输出栈,一个操作符栈,算法描述如下:
- 依次按顺序读入,
- 读到数字:直接输出;
- 读到一般运算符:如果栈顶的运算符优先级不低于该运算符,则输出栈顶运算符并使之出栈,直到栈空或不满足上述条件为止;然后入栈;
- 读到左括号:直接入栈;
- 读到右括号:输出栈顶运算符并使之出栈,直到栈顶为左括号为止;令左括号出栈。
- 当读入完毕时,依次输出并弹出栈顶运算符,直到栈被清空。
这里我写的比较简单,详细大家可以看以下这篇知乎上的文章:
https://zhuanlan.zhihu.com/p/...
以下是我用javascript实现的代码,加了一点自己的东西,也就是字符串转换成分解好的数组的代码,在node.js上运行通过。
function cal(strArr){
let first={\'+\':1,\'-\':1,\'*\':2,\'/\':2,\'sqrt\':3,\'sin\':3,\'cos\':3}
let opStack=[];
let outputStack=[];
let calStack=[];
for(let i=0;i<strArr.length;i++){
let s=strArr[i];
if(!isNaN(s)){
outputStack.push(s);
}else{
if(s == \'(\')opStack.push(s);
else if (s == \')\'){
while((topOp=opStack.pop()) != \'(\'){
outputStack.push(topOp);
}
}else{
if(opStack.length == 0){
opStack.push(s)
}else{
let topOp=opStack[opStack.length-1];
while(first[topOp] >= first[s]){
outputStack.push(opStack.pop());
if(opStack.length == 0)break;
topOp=opStack[opStack.length-1];
}
opStack.push(s)
}
}
}
}
while(opStack.length > 0)outputStack.push(opStack.pop())
for(let i=0;i<outputStack.length;i++){
let s=outputStack[i];
if(!isNaN(s))calStack.push(s);
else {
let r=Number(calStack.pop());
let v=0;
if(s== \'+\')v=Number(calStack.pop())+r;
else if(s==\'-\')v=Number(calStack.pop())-r;
else if(s==\'*\')v=Number(calStack.pop())*r;
else if(s== \'/\')v=Number(calStack.pop())/r;
else if(s == \'sqrt\')v=Math.sqrt(r)
else if(s == \'sin\')v=Math.sin(r)
else if(s == \'cos\')v=Math.cos(r)
calStack.push(v);
}
}
return calStack.pop();
}
//计算字符串按数字和操作符分解转换成数组
function str2arr(str){
let resultArr=[];
const symbolSet=[\'+\',\'-\',\'*\',\'/\',\'(\',\')\',\'sqrt\',\'sin\',\'cos\',\'log\']
let currentStr=\'\'
for (let s of str){
if(symbolSet.indexOf(s) > -1){
if(currentStr != \'\')resultArr.push(currentStr);
resultArr.push(s)
currentStr=\'\';
}else{
if(s == \'.\'){
currentStr=currentStr+s
}else{
let currentStrType= isNaN(currentStr)
let sType=isNaN(s)
if(sType == currentStrType){
currentStr=currentStr+s
}else{
if(currentStr != \'\')resultArr.push(currentStr)
currentStr=s
}
}
}
}
if(currentStr != \'\')resultArr.push(currentStr)
//检查括号,左括号进栈,右括号出栈,最后栈必须为空
//检查数字
let bracketsStack=[]
for(let i=0;i<resultArr.length;i++){
if(symbolSet.indexOf(resultArr[i]) > -1){
if(resultArr[i] == \'(\')bracketsStack.push(resultArr[i])
else if(resultArr[i] == \')\'){
if(bracketsStack.length == 0)return {result:false,msg:\'括号错误\',data:resultArr};
bracketsStack.pop()
}
}else if (isNaN(resultArr[i])) return {result:false,msg:\'字符串错误\',data:resultArr};
}
if(bracketsStack.length > 0) return {result:false,msg:\'括号错误\',data:resultArr};
return {result:true,msg:\'转换成功\',data:resultArr};
}
let str="1-sin(2)*3.14/5"
let {result,msg,data}=str2arr(str)
if(result == true){
console.log(data)
let calResult=cal(data)
console.log(calResult)
}else console.log(msg)
console.log(1-Math.sin(2)*3.14/5)
以上代码我亲测可用,有写的不好的地方,欢迎大家点评。
以上是关于用调度场算法计算表达式的值,javascript实现的主要内容,如果未能解决你的问题,请参考以下文章