javascript之使用逆波蘭表達式(後綴表達式)實現算數表達式計算
使用jexl庫
const jexl = require('jexl');
// addBinaryOp 添加二元運算或者修改
// 可以根據jexl的lib/grammar.js裏面的優先級來決定執行順序
jexl.addBinaryOp('|', 40, (left, right) => {
return left * right;
});
console.log(jexl.evalSync('2|3+4'))
知識點
- 棧
- 逆波蘭表達式(後綴表達式)
注:具體逆波蘭表達式相關介紹可參考
使用JavaScript實現
1.定義棧
class Stack {
constructor() {
this._items = []; // 儲存數據
}
// 向棧內壓入一個元素
push(item) {
this._items.push(item);
}
// 把棧頂元素彈出
pop() {
return this._items.pop();
}
// 返回棧頂元素
peek() {
return this._items[this._items.length - 1];
}
// 判斷棧是否爲空
isEmpty() {
return !this._items.length;
}
// 棧元素個數
size() {
return this._items.length;
}
// 清空棧
clear() {
this._items = [];
}
}
2.將普通的算數表達式(中綴表達式)轉換爲逆波蘭表達式(後綴表達式)
// 將普通算數表達式即中綴表達式轉換爲逆波蘭表達式即後綴表達式
function rp(str) {
var arr = str.split('');
var ops = '+-#*/'.split(''); // #用來分級,+-是同一級,*/同一級,兩級之間的位置差至少爲2
var result = [], temp = [];
arr.forEach(function(ele, ind) {
if (ele == '(') {
temp.push(ele); // 左括號直接推入暫存區
} else if (ele == ')') {
var flag = true;
while (flag) {
if (temp[temp.length-1] != '(') {
result.push(temp.pop())
} else {
temp.pop();
flag = false;
}
}
} else if (ops.indexOf(ele) != -1) {
cb(ele, temp)
function cb(x, o) {
if (o.length == 0 || o[o.length-1] == '(' ||
ops.indexOf(x) - ops.indexOf(o[o.length-1]) > 2) { //判斷分級
o.push(x)
} else {
result.push(o.pop());
return cb(x, o)
}
}
} else {
result.push(ele);
}
})
while (temp.length > 0) {
if(temp[temp.length-1] != '(') {
result.push(temp.pop())
} else {
temp.pop()
}
}
return result;
}
3.計算逆波蘭表達式
function isOperator(str) {
return ['+', '-', '*', '/'].includes(str);
}
// 逆波蘭表達式計算
function clacExp(exp) {
const stack = new Stack();
for (let i = 0; i < exp.length; i++) {
const one = exp[i];
if (isOperator(one)) {
const operatNum1 = stack.pop();
const operatNum2 = stack.pop();
const expStr = `${operatNum2}${one}${operatNum1}`;
const res = eval(expStr);
stack.push(res);
} else {
stack.push(one);
}
}
return stack.peek();
}
測試
const arr = rp('(2*(3+4)+1)*4');
const result = clacExp(arr);
console.log(result); // 60