javascript中解析四则运算表达式的算法和示例
作者:junjie 发布时间:2024-04-28 09:41:37
在编写代码时我们有时候会碰到需要自己解析四则运算表达式的情况,本文简单的介绍使用JavaScript实现对简单四则运算表达式的解析。
一、熟悉概念
中缀表示法(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。也就是我们最常用的算术表达式,中缀表达式对于人类来说比较容易理解,但是不易于计算机解析。
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。逆波兰表示法容易使用堆栈结构对表达式进行解析并计算,所以,这里我们解析四则元素表达式,是先从中缀表达式,转换为逆波兰表达式。然后再计算值。
二、转换流程
中缀表达式转换为后缀表达式(调度场算法)
1.输入队列弹出一个记号
2.如果记号为数字,添加到输出队列中
3.如果是一个操作符(+-*/)则比较它与输出堆栈中栈顶的操作符,如果优先级小于或等于栈顶的操作符,那么将栈顶的操作符弹出并加入输出队列(循环,直到上述条件不满足),最后将本次的操作符压入堆栈。
4.如果是一个左括号,压入堆栈
5.如果是一个右括号,从栈中不断的弹出操作符,并加入输出队列,知道栈顶的元素为左括号。弹出左括号,不加入输出队列。如果没有发现左括号,说明原来的表达式中括号不对称,有错误。
6.如果输入队列为空,而栈中尚有操作符时,如果栈顶的操作符为左括号,则说明原表达式有不匹配的括号。将栈中的操作符逐个弹出,加入输出队列。
7.完成
三、转换代码实现
function isOperator(value){
var operatorString = "+-*/()";
return operatorString.indexOf(value) > -1
}
function getPrioraty(value){
switch(value){
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
function prioraty(o1, o2){
return getPrioraty(o1) <= getPrioraty(o2);
}
function dal2Rpn(exp){
var inputStack = [];
var outputStack = [];
var outputQueue = [];
for(var i = 0, len = exp.length; i < len; i++){
var cur = exp[i];
if(cur != ' ' ){
inputStack.push(cur);
}
}
console.log('step one');
while(inputStack.length > 0){
var cur = inputStack.shift();
if(isOperator(cur)){
if(cur == '('){
outputStack.push(cur);
}else if(cur == ')'){
var po = outputStack.pop();
while(po != '(' && outputStack.length > 0){
outputQueue.push(po);
po = outputStack.pop();
}
if(po != '('){
throw "error: unmatched ()";
}
}else{
while(prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0){
outputQueue.push(outputStack.pop());
}
outputStack.push(cur);
}
}else{
outputQueue.push(new Number(cur));
}
}
console.log('step two');
if(outputStack.length > 0){
if(outputStack[outputStack.length - 1] == ')' || outputStack[outputStack.length - 1] == '('){
throw "error: unmatched ()";
}
while(outputStack.length > 0){
outputQueue.push(outputStack.pop());
}
}
console.log('step three');
return outputQueue;
}
console.log(dal2Rpn('1 + 2'));
console.log(dal2Rpn('1 + 2 + 3'));
console.log(dal2Rpn('1 + 2 * 3'));
console.log(dal2Rpn('1 + 2 * 3 - 4 / 5'));
console.log(dal2Rpn('( 1 + 2 )'));
console.log(dal2Rpn('( 1 + 2 ) * ( 3 - 4 ) / 5'));
console.log(dal2Rpn('( 1 + 2 ) * (( 3 - 4 ) / 5)'));
四、逆波兰表达式求值
1.从输入队列中弹出一个记号
2.如果是操作数,加入输出堆栈
3.如果是一个操作符,从输出堆栈中弹出两个操作数并进行计算,并将计算得到的值压入输出堆栈。
4.循环操作,如果输入队列为空,且输出堆栈只有一个数则这个数为结果,否则是出现了多余的操作数。
五、计算代码
function evalRpn(rpnQueue){
var outputStack = [];
while(rpnQueue.length > 0){
var cur = rpnQueue.shift();
if(!isOperator(cur)){
outputStack.push(cur);
}else{
if(outputStack.length < 2){
throw "unvalid stack length";
}
var sec = outputStack.pop();
var fir = outputStack.pop();
outputStack.push(getResult(fir, sec, cur));
}
}
if(outputStack.length != 1){
throw "unvalid expression";
}else{
return outputStack[0];
}
}
六、结语
逆波兰表示法,在初次接触的时候感觉不太习惯,但是熟悉之后,会发现,其实思路特别简单,不像中缀表示法,还有各种优先级啊,还有小括号之类的,逻辑特别麻烦,还是逆波兰表示法比较简洁,完全不用考虑优先级,也没用小括号,中括号还有大括号搅局。


猜你喜欢
- 1.在python中excel的简单读写操作,推荐使用xlrd(特别是读操作) 2.到http://pypi.python.org/pypi
- 1.实现点击按钮,复制文本框中的的内容<script type="text/javascript">func
- 在之前的一篇文章我们已经介绍过替换python字典中的key值方法 ,本篇文章将作为那篇文章的补充。使用 dict.update() 方法替
- 常见的双倍边距类问题都遇到过,但很少遇到这种有意思的,所以记录一下。这个BUG是发生在Standards模式下(就是包含XHTML或者HTM
- 大家都在关注视觉的盛宴,西方的美学;今天就分享下,中国最为古老的美,也是身边随处可见的美学–中国汉字书法之美;古文者,仓颉做造也。仰观奎星园
- 一直以来都是链接SQL Server数据库服务但是在部署时将很麻烦,所以突发奇想,直接连接到MDF文件,刚开始还很混乱不会连接,后来向导,连
- 之前看到很多人一直都问这个问题,不过当时我没当一回事,因为在 CSS 中要垂直居中,多数是在有高度的情况下,或者容器高度不定的情况下才用,看
- <!doctype html> <html> <head> <meta content="
- 微信小程序实现人脸识别,具体应用场景 前端实现人脸信息采集 拍到正面照片 发送给后端该方法暂
- 题目:求一个3*3矩阵对角线元素之和。程序分析:利用双重for循环控制输入二维数组,再将a[i][i]累加后输出。 def two_dime
- 基于python 3.5,python 2.7 与python3.4 的urllib不同,是urlparse>>> fro
- 脚本要实现的功能:输入instance id1:将所有的volume take snapshot2: 获取public ip 并
- 说明:这里仅展示在已经获取图片链接后的下载方式,对于爬虫获取链接部分参考前面的文章1、利用文件读写的方式下载图片#第一种:用urllib2模
- 在 MySQL 中,可以使用 REVOKE 语句删除某个用户的某些权限(此用户不会被删除),在一定程度上可以保证系统的安全性。例如,如果数据
- 1. 是什么?MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Da
- 一,VSCODE配置Markdown 打开左侧的extensions,或者使用 Ctrl+Shift+X,输入Markdown(1
- 本文实例讲述了python执行等待程序直到第二天零点的方法。分享给大家供大家参考。具体分析如下:如果需要通过python每天凌晨定时执行执行
- 这是我为了学习tkinter用python 写的一个下载m3u8视频的小程序,程序使用了多线程下载,下载后自动合并成一个视频文件,方便播放。
- 本次薯片会讨论了关于分类与类型的问题。怎么找一个item?页面导航一般分类为主,在具体的分类展示下选择类型:典型例子:炫铃(QQ客户端)当只
- 前言利用Django开发网站,可以设计出非常优美的url规则,如果url的匹配规则(包含正则表达式)组织得比较好,view的结构就会比较清晰