JavaScript实现四则运算表达式解析:中缀转逆波兰算法详解

作者:拾光

时间:2026-10-28

浏览:608

本文介绍如何使用JavaScript解析简单的四则运算表达式。核心思路是将人类易读的中缀表达式转换为计算机易处理的逆波兰(后缀)表达式,再计算结果。文中详细讲解了基于调度场算法的中缀转后缀流程,以及逆波兰表达式的求值逻辑,并提供了完整的JavaScript代码实现示例,帮助开发者理解表达式解析的底层原理。

文章目录

JavaScript实现四则运算表达式解析:中缀转逆波兰算法详解

在开发过程中,有时需要自行处理四则运算表达式的解析。本文将简要介绍如何使用JavaScript实现简单四则运算表达式的解析过程。

基本概念

一、基本概念

中缀表示法(或中缀记法)是一种通用的算术或逻辑公式表示方式,操作符位于操作数中间(例如:3 + 4)。这是日常最常用的算术表达式形式,对人类而言易于理解,但不利于计算机直接解析。

逆波兰表示法(Reverse Polish notation,简称RPN,或逆波兰记法)由波兰数学家扬·武卡谢维奇于1920年引入。在逆波兰记法中,所有操作符置于操作数之后,因此也被称为后缀表示法。这种表示法无需括号来标识操作符的优先级,且易于利用堆栈结构进行解析和计算。因此,本文解析四则运算表达式的策略是:先将中缀表达式转换为逆波兰表达式,再进行数值计算。

转换流程概述

二、转换流程概述

中缀表达式转换为后缀表达式(采用调度场算法)

1. 从输入队列中弹出一个记号。 2. 如果该记号为数字,则将其添加到输出队列中。 3. 如果是一个操作符(+、-、*、/),则将其与输出堆栈中的栈顶操作符比较优先级。如果当前操作符的优先级小于或等于栈顶操作符的优先级,则将栈顶操作符弹出并加入输出队列(循环执行此步骤,直到上述条件不再满足),最后将当前操作符压入堆栈。 4. 如果遇到左括号,直接压入堆栈。 5. 如果遇到右括号,则不断从栈中弹出操作符并加入输出队列,直到栈顶元素为左括号。弹出左括号,但不加入输出队列。若未发现左括号,说明原表达式括号不对称,存在错误。 6. 当输入队列为空而栈中仍有操作符时,若栈顶操作符为左括号,说明原表达式存在未匹配的括号。将栈中剩余操作符逐个弹出并加入输出队列。 7. 完成转换。

JavaScript实现四则运算表达式解析:中缀转逆波兰算法详解

转换代码实现

三、转换代码实现


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];
	}
}

总结

六、总结

逆波兰表示法在初次接触时可能略显生疏,但熟悉后便会发现其思路非常清晰。与中缀表示法不同,逆波兰表示法无需考虑各种优先级规则,也不涉及小括号、中括号或大括号的干扰,逻辑更为简洁,完全免去了优先级判断的繁琐。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章