這幾天也在學習 javascript,前幾日師傅給了一篇關於解析四則運算運算式和演算法的文章,說四則運算很常用讓我好好看看,再讓編寫代碼看看最終結果。
首先我看了代碼瞭解了兩個關於算術或邏輯公式的標記法:中綴標記法以及逆波蘭標記法,也學習了四則運算的實際轉換過程(此定義在原文有詳細解釋)。
原文:http://www.jb51.net/article/53537.htm
然後我看了作者寫的代碼,自己分析看明白後,再加了些代碼。在這個過程中鞏固學習了關於堆棧的知識以及棧(後進先出)和隊列(先進先出)方法。
以下代碼就是自認為比較完整的代碼:
首先判斷加減乘除的優先順序,* 和 / 的優先順序高於 + 和 - :
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); //+-*/() 數字,逐個添加到末尾
}
}
//處理字元和數字
while (inputStack.length > 0) {
//shift 頂部取得一項後移除,unshift 頂部推入
cur = inputStack.shift();
//如果是符號 --> + - * / ( )
if (isOperator(cur)) {
if (cur == '(') {
//push 從尾部推入一項
outputStack.push(cur);
} else if (cur == ')') {
//pop 從尾部取得一項,之後移出
var po = outputStack.pop();
while (po != '(' && outputStack.length > 0) {
outputQueue.push(po);
po = outputStack.pop();
}
if (po != '(') {
throw "錯誤:沒有匹配";
}
} else { //符號時,處理 + - * /
while (prioraty(cur, outputStack[outputStack.length - 1])
&& outputStack.length > 0) {
outputQueue.push(outputStack.pop());
}
outputStack.push(cur);
}
} else { //是數位時候,推入數字
outputQueue.push(new Number(cur));
}
}
if (outputStack.length > 0) {
if (outputStack[outputStack.length - 1] == ')'
outputStack[outputStack.length - 1] == '(') {
throw "錯誤:沒有匹配";
}
while (outputStack.length > 0) {
outputQueue.push(outputStack.pop());
}
}
return evalRpn(outputQueue);
}
定義 evalRpn() 函數,輸出堆棧的長度不小於2的時候,進行計算:
function evalRpn(queue) {
var outputStack = [];
while (queue.length > 0) {
var cur = queue.shift();
if (!isOperator(cur)) {
outputStack.push(cur);
} else {
//如果輸出堆棧長度小於 2
if (outputStack.length < 2) {
throw "無效堆棧長度";
}
var second = outputStack.pop();
var first = outputStack.pop();
outputStack.push(getResult(first, second, cur));
}
}
if (outputStack.length != 1) {
throw "不正確的運算";
} else {
return outputStack[0];
}
}
進行加減乘除計算之後,對其值進行操作,當浮點數的小數位超過兩位時,只保留兩位小數點:
function getResult(first, second, operator){
var result = 0;
switch (operator) {
case '+':
result = first + second;
break;
case '-':
result = first - second;
break;
case '*':
result = first * second;
break;
case '/':
result = first / second;
break;
default:
return 0;
}
//浮點數的小數位超過兩位時,只保留兩位小數點
function formatFloat(f, digit) {
//pow(10,n) 為 10 的 n 次方
var m = Math.pow(10, digit);
return parseInt(f * m, 10) / m;
}
return (formatFloat(result, 2));
}
輸入要計算的運算式,計算結果 ( 結果得到 -0.6 ):
var result=dal2Rpn('( 1 + 2 ) * (( 3 - 4 ) / 5)');
console.log(result); //輸出結果