這幾天也在學習 javascript,前幾日看了一篇關於解析四則運算表達式和算法的文章,覺得四則運算很常用,打算編寫代碼看看最終結果。
首先我看代碼了解了兩個關於算術或邏輯公式的表示法:中綴表示法以及逆波蘭表示法,也學習了四則運算的實際轉換過程(此定義在原文有詳細解釋)。
原文:http://www.jb51.net/article/53537.htm
分析了作者寫的代碼后,在此基礎上加了些代碼。在這個過程中鞏固學習了關於堆棧的知識以及棧(后進先出)和隊列(先進先出)方法。
以下代碼就是自認為比較完整的代碼:
首先判斷加減乘除的優先級,* 和 / 的優先級高於 + 和 - :
1 function isOperator(value) { 2 var operatorString = "+-*/()"; 3 return operatorString.indexOf(value) > -1 4 } 5 6 function getPrioraty(value) { 7 switch (value) { 8 case '+': 9 case '-': 10 return 1; 11 case '*': 12 case '/': 13 return 2; 14 default: 15 return 0; 16 } 17 } 18 19 //判斷加減乘除的優先級 20 function prioraty(o1, o2) { 21 return getPrioraty(o1) <= getPrioraty(o2); 22 }
定義輸入、輸出棧以及輸出隊列,循環逐個添加到輸入棧的末尾,之后處理符號和數字,當找到 "(" 和 ")" 時特殊處理:
1 function dal2Rpn(exp) { 2 //輸入棧 3 var inputStack = []; 4 //輸出棧 5 var outputStack = []; 6 //輸出隊列 7 var outputQueue = []; 8 9 for (var i = 0, len = exp.length; i < len; i++) { 10 var cur = exp[i]; 11 if (cur != ' ') { 12 inputStack.push(cur); //+-*/() 數字,逐個添加到末尾 13 } 14 } 15 16 //處理字符和數字 17 while (inputStack.length > 0) { 18 19 //shift 頂部取得一項后移除,unshift 頂部推入 20 cur = inputStack.shift(); 21 22 //如果是符號 --> + - * / ( ) 23 if (isOperator(cur)) { 24 if (cur == '(') { 25 //push 從尾部推入一項 26 outputStack.push(cur); 27 } else if (cur == ')') { 28 //pop 從尾部取得一項,之后移出 29 var po = outputStack.pop(); 30 while (po != '(' && outputStack.length > 0) { 31 outputQueue.push(po); 32 po = outputStack.pop(); 33 } 34 if (po != '(') { 35 throw "錯誤:沒有匹配"; 36 } 37 } else { //符號時,處理 + - * / 38 while (prioraty(cur, outputStack[outputStack.length - 1]) 39 && outputStack.length > 0) { 40 outputQueue.push(outputStack.pop()); 41 } 42 outputStack.push(cur); 43 } 44 } else { //是數字的時候,推入數字 45 outputQueue.push(new Number(cur)); 46 } 47 } 48 49 if (outputStack.length > 0) { 50 if (outputStack[outputStack.length - 1] == ')' 51 || outputStack[outputStack.length - 1] == '(') { 52 throw "錯誤:沒有匹配"; 53 } 54 while (outputStack.length > 0) { 55 outputQueue.push(outputStack.pop()); 56 } 57 } 58 return evalRpn(outputQueue); 59 }
定義 evalRpn() 函數,輸出堆棧的長度不小於2的時候,進行計算:
1 function evalRpn(queue) { 2 var outputStack = []; 3 while (queue.length > 0) { 4 var cur = queue.shift(); 5 6 if (!isOperator(cur)) { 7 outputStack.push(cur); 8 } else { 9 //如果輸出堆棧長度小於 2 10 if (outputStack.length < 2) { 11 throw "無效堆棧長度"; 12 } 13 var second = outputStack.pop(); 14 var first = outputStack.pop(); 15 16 outputStack.push(getResult(first, second, cur)); 17 } 18 } 19 20 if (outputStack.length != 1) { 21 throw "不正確的運算"; 22 } else { 23 return outputStack[0]; 24 } 25 }
進行加減乘除計算之后,對其值進行操作,當浮點數的小數位超過兩位時,只保留兩位小數點:
1 function getResult(first, second, operator){ 2 var result = 0; 3 switch (operator) { 4 case '+': 5 result = first + second; 6 break; 7 case '-': 8 result = first - second; 9 break; 10 case '*': 11 result = first * second; 12 break; 13 case '/': 14 result = first / second; 15 break; 16 default: 17 return 0; 18 } 19 20 //浮點數的小數位超過兩位時,只保留兩位小數點 21 function formatFloat(f, digit) { 22 //pow(10,n) 為 10 的 n 次方 23 var m = Math.pow(10, digit); 24 return parseInt(f * m, 10) / m; 25 } 26 return (formatFloat(result, 2)); 27 }
輸入要計算的表達式,計算結果 ( 結果得到 -0.6 ):
1 var result=dal2Rpn('( 1 + 2 ) * (( 3 - 4 ) / 5)'); 2 console.log(result); //輸出結果