逆波兰算术表达式解析的JavaScript实现

近期,需要用javascript实现算术表达式的解析,在网上查了一下,逆波兰表达式是最简单快捷的一种。

逆波兰表达式
逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
  正常的表达式 逆波兰表达式
  a+b ---> a,b,+
  a+(b-c) ---> a,b,c,-,+
  a+(b-c)*d ---> a,d,b,c,-,*,+
  a=1+3 ---> a=1,3 +
  http=(smtp+http+telnet)/1024 写成什么呢?
  http=smtp,http,telnet,+,+,1024,/
  逆波兰表达式是一种十分有用的表达式,它将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。例如(a+b)*(c+d)转换为ab+cd+*
  它的优势在于只用两种简单操作,入栈和出栈就可以搞定任何普通表达式的运算。其运算方式如下:
  如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
  将一个普通的中序表达式转换为逆波兰表达式的一般算法是:
  (1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
  (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
  (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
  (4)如果不是数字,该字符则是运算符,此时需比较优先关系。
  做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。
  (5)重复上述操作(3)-(4)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
  下面是程序化算法流程:
  1、建立运算符栈stackOperator用于运算符的存储,压入'\0'。
  2、预处理表达式,正、负号前加0(如果一个加号(减号)出现在最前面或左括号后面,则该加号(减号)为正负号) 。
  3、顺序扫描表达式,如果当前字符是数字(优先级为0的符号),则直接输出该数字;如果当前字符为运算符或括号(优先级不为0的符号),则判断第4点 。
  4、若当前运算符为'(',直接入栈;
  若为')',出栈并顺序输出运算符直到遇到第一个'(',遇到的第一个'('出栈但不输出;
  若为其它,比较stackOperator栈顶元素与当前元素的优先级:
  如果 栈顶元素 >= 当前元素,出栈并顺序输出运算符直到 栈顶元素 < 当前元素,然后当前元素入栈;
  如果 栈顶元素 < 当前元素,直接入栈。
  5、重复第3点直到表达式扫描完毕。
  6、顺序出栈并输出运算符直到栈顶元素为'\0'。
  各运算符及符号优先级:
  '\0': -1
  ')': 1
  '(': 2
  '+'、'-': 3
  '*'、'/'、'%': 4
  '^': 5
  其它: 0
/**
* 计算逆波兰表达式的值
*/
function calculate(RPolishArray){
	var result = 0;
	var tempArray = new Array(100);
	var tempNum = -1;
	for(i = 0;i < RPolishArray.length;i++){
		if(RPolishArray[i].match(/\d/)){
			tempNum++;
			tempArray[tempNum] = RPolishArray[i];
		}else{
			switch(RPolishArray[i]){
				case '+':
					result = (tempArray[tempNum-1] *1) + (tempArray[tempNum] * 1);
					tempNum--;
					tempArray[tempNum] = result;
					break;
				case '-':
					result = (tempArray[tempNum-1] *1) - (tempArray[tempNum] * 1);
					tempNum--;
					tempArray[tempNum] = result;
					break;
				case '*':
					result = (tempArray[tempNum-1] *1) * (tempArray[tempNum] * 1);
					tempNum--;
					tempArray[tempNum] = result;
					break;
				case '/':
					result = (tempArray[tempNum-1] *1) / (tempArray[tempNum] * 1);
					tempNum--;
					tempArray[tempNum] = result;
					break;
			}
		}
	}
	result = tempArray[tempNum];	
	return result;	
}

/**
* 把普通算术表达式转换为逆波兰表达式
*/
function toRPolish(input){
	var regex = /(\(|\)|\+|\-|\*|\/)+/;
	var array = input.split(regex);
	var RPolish = ""
	var isI = false;
	num = 0;
	var SymbolArray = new Array(100);
	var SymbolNum = -1;
	for(j = 0;j < input.length;j++){		
		if(input.charAt(j).match(/\d/)){
			if(isI == false){
				RPolish += ','
				RPolish += array[num];
				num++;
				isI = true;
			}
		}
		else{
			if(SymbolNum == -1){ 
					SymbolNum++;
					SymbolArray[SymbolNum] = input.charAt(j);
			}else{
				if(input.charAt(j).match(/\(/)  || SymbolArray[SymbolNum].match(/\(/)){
						SymbolNum++;
						SymbolArray[SymbolNum] = input.charAt(j);
				}else if(input.charAt(j).match(/\)/)){
					while(!SymbolArray[SymbolNum].match(/\(/)){
						RPolish += ',';						
						RPolish += SymbolArray[SymbolNum];
						SymbolNum--;
					}
					SymbolNum--;
				}else if(compare(input.charAt(j),SymbolArray[SymbolNum])){
						SymbolNum++;
						SymbolArray[SymbolNum] = input.charAt(j);
				}else if(!compare(input.charAt(j),SymbolArray[SymbolNum])){
						RPolish += ',';	
						RPolish += SymbolArray[SymbolNum];
						SymbolNum--;
						if(SymbolNum >= 0){
							if(SymbolArray[SymbolNum].match(/\(/)){
								SymbolNum++;
								SymbolArray[SymbolNum] = input.charAt(j);
							}else if(!compare(input.charAt(j),SymbolArray[SymbolNum])){
								RPolish += ',';
								RPolish += SymbolArray[SymbolNum];
								SymbolArray[SymbolNum] = input.charAt(j);
							}else{
								SymbolNum++;
								SymbolArray[SymbolNum] = input.charAt(j);
							}
						}else{
							SymbolNum++;
							SymbolArray[SymbolNum] = input.charAt(j);
						}
				}
			}
			isI = false;
		}
	}			
	while(SymbolNum >=0){
		RPolish += ',';
		RPolish += SymbolArray[SymbolNum];
		SymbolNum--;
	}
	regex =  /,/;
	var RPolishArray = RPolish.split(regex);
	return RPolishArray;
}

function compare(a,b){
	if((a.match(/\*/)||a.match(/\//))&&(b.match(/\+/)||b.match(/\-/))){
		return true;
	}else{
		return false;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值