最近想试下做微信小程序,刚开始写,想找点货色练手,试下写个计算器的小程序,查了一下,做表达式求值是用的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)
以上代码我亲测可用,有写的不好的中央,欢送大家点评。