中綴表達式轉換為后綴表達式并求值

0.前言

之前用js實現(xiàn)的一個簡易計算器有許多處理得不好的地方,拋開樣式的問題喷众,計算器最核心的計算部分直接使用了eval()函數,今天自己來實現(xiàn)計算部分拂檩,目標是獲取一個算式字符串,并讓計算機得出結果稻励。

在這之前,什么是中綴表達式望抽,什么是后綴表達式加矛??
今天特地查閱了一下《數據結構教程》

......在算術表達式中煤篙,運算符位于兩個操作數中間的表達式稱為中綴表達式(infix expression)...... 后綴表達式(postfix expression)或逆波蘭表達式,就是在算術表達式中運算符在操作數的后面......

我們在日常生活中所使用的幾乎都是中綴表達式辑奈。因為我們知道運算法則:括號內優(yōu)先計算,先乘除后加減......計算機并不懂得我們的計算法則妓羊,后綴表達式才對它的胃口稍计,轉化好的后綴表達式已經事先考慮了優(yōu)先級,不僅沒有括號臣嚣,而且位置越靠前的運算符越優(yōu)先執(zhí)行

在達到我們的目標前硅则,我們事先準備三個“容器”:

var infixExp[];        //存放中綴表達式字符
var postfixExp[];      //存放后綴表達式字符
var tempExp[];         //存放臨時字符

備注:上面的數組應該理解成,js中數組的pop()push()方法弹灭,下文會以出棧揪垄,入棧來稱呼。

1.從一個算式說起

4.25*(3+1)
看到這個算式饥努,我們的第一個問題來了,如何將其正確地存入到infixExp里酷愧?
也就是說我們需要的是['4.25','*','(','3','+','1',')']而不是['4','.','2','5','*','(','3','+','1',')']

這里提供一種思路:

strTemp = "獲取到的中綴表達式字符串";
function expSolve() {
    var i=0;
    var j=0;
    if(strTemp[0] == '-'){
        i = 1;
    }//對負數的處理

    for(; i<strTemp.length; i++){
        if(strTemp[i]=='('&&strTemp[i+1]=='-'){
            infixExp.push('(');
            j = i+1;
            i++;
            continue;
        }//對負數的處理

        if(strTemp[i]=='+'||strTemp[i]=='-'||strTemp[i]=='*'||strTemp[i]=='/'||strTemp[i]=='('||strTemp[i]==')'){
            if(strTemp.slice(j, i)!='')
                infixExp.push(strTemp.slice(j, i));
            infixExp.push(strTemp[i]);
            j=i+1;
        }
    }
    if(strTemp.slice(j)!='')
        infixExp.push(strTemp.slice(j));
}

掃描字符串的每個字符乍迄,當遇到運算符和括號時+-褥伴,*/漾狼,時逊躁,將該符號前部分和該符號依次插入到infixExp里,要做是否為空的判斷(例如括號前可能會出現(xiàn)運算符)核芽。最后剩下部分可能為運算符右側的數也要插入數組酵熙。
可能還存在bug,慎用绿店!一定有更好的方法

2.中綴表達式轉換為后綴表達式

掃描infixExp中的每個元素:

  1. 遇到數庐橙,直接入棧postfixExp
  2. 遇到符號+,-,*,/時:
    • 如果此時臨時棧tempExp為空转培,該符號直接入棧tempExp浆竭。
    • 如果此時臨時棧tempExp不為空,該符號優(yōu)先級高于tempExp中的棧頂元素或棧頂元素為(時删窒,入棧tempExp顺囊。
    • 如果此時臨時棧tempExp不為空,該符號優(yōu)先級低于tempExp中的棧頂元素特碳,將tempExp中的棧頂元素出棧晕换,并入棧postfixExp站宗,直到該符號優(yōu)先級高于tempExp的棧頂元素或棧頂元素為(,才將該符號入棧夷家。
  3. 遇到括號()時:
  • 遇到左括號(或辖,直接入棧tempExp
  • 遇到右括號)颂暇,右括號兩個棧均不入,將tempExp中的棧頂元素出棧湿蛔,并入棧postExp县爬,直到遇到(。左括號只出棧但不進入postfixExp财喳。

左括號只有當遇到右括號時才出棧。
掃描完infixExp中的所有元素后扎瓶,將tempExp中的元素依次彈出入棧postfixExp

中綴轉后綴的實現(xiàn)(js)

function infixTopostfix() {
    var item;
    for (var i = 0; i < infixExp.length; i++) {
        if (!isNaN(infixExp[i])) {
            postfixExp.push(infixExp[i]);
        }
        else if (infixExp[i] == '+' || infixExp[i] == '-' || infixExp[i] == '*' || infixExp[i] == '/'||infixExp[i]=='('||infixExp[i]==')'){
            if (tempExp.length == 0) {
                tempExp.push(infixExp[i]);
            }
            else if (infixExp[i] == '*' || infixExp[i] == '/') {
                item = tempExp.pop();
                if (item == '*' || item == '/') {
                    postfixExp.push(item);
                }
                else {
                    tempExp.push(item);
                }
                tempExp.push(infixExp[i]);
            }
            else if (infixExp[i] == '+' || infixExp[i] == '-') {
                while (tempExp.length != 0) {
                    item = tempExp.pop();
                    if(item == '('){
                        tempExp.push(item);
                        break;
                    }
                    postfixExp.push(item);
                }
                tempExp.push(infixExp[i]);
            }
            else if(infixExp[i] == '('){
                tempExp.push(infixExp[i]);
            }
            else if(infixExp[i] == ')'){
                while (1) {
                    item = tempExp.pop();
                    if(item == '('){
                        break;
                    }
                    postfixExp.push(item);
                }
            }
        }
    }
    while (tempExp.length != 0) {
        postfixExp.push(tempExp.pop());
    }
}

3.后綴表達式的計算

掃描postfixExp中的每個元素:

  1. 遇到數概荷,入棧tempExp碌燕。
  2. 遇到符號+, -, *, /(后綴表達式一定不會含左右括號),從tempExp中依次取出兩個數修壕,并根據符號計算(后取出的數在符號左側)。最后將該次結果入棧tempExp改鲫。

掃描結束,tempExp中只剩一個元素像棘, 即為最終結果!

后綴表達式的計算(js)

function postfixCalc() {
    for (var i = 0; i < postfixExp.length; i++) {
        if (!isNaN(postfixExp[i])) {
            tempExp.push(postfixExp[i]);
        }
        else {
            var strRight = opeStack.pop();
            var strLeft = opeStack.pop();
            switch (postfixExp[i]) {
                case '+':
                    opeStack.push(Number(strLeft) + Number(strRight));
                    break;
                case '-':
                    opeStack.push(Number(strLeft) - Number(strRight));
                    break;
                case '*':
                    opeStack.push(Number(strLeft) * Number(strRight));
                    break;
                case '/':
                    opeStack.push(Number(strLeft) / Number(strRight));
                    break;
                default:
                    alert("運算符號出錯截歉!");
            }
        }
    }
    var out = tempExp.pop();   //out即為最終結果
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末瘪松,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宵睦,更是在濱河造成了極大的恐慌墅诡,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烟馅,死亡現(xiàn)場離奇詭異然磷,居然都是意外死亡,警方通過查閱死者的電腦和手機姿搜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門舅柜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事猖任。” “怎么了太伊?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵僚焦,是天一觀的道長。 經常有香客問我,道長边坤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任茧痒,我火速辦了婚禮融蹂,結果婚禮上,老公的妹妹穿的比我還像新娘区拳。我一直安慰自己意乓,他們只是感情好,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布本涕。 她就那樣靜靜地躺著伙窃,像睡著了一般菩颖。 火紅的嫁衣襯著肌膚如雪为障。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天呻右,我揣著相機與錄音鞋喇,去河邊找鬼。 笑死侦香,一個胖子當著我的面吹牛,可吹牛的內容都是我干的憾赁。 我是一名探鬼主播散吵,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蟆肆,長吁一口氣:“原來是場噩夢啊……” “哼晦款!你這毒婦竟也來了?” 一聲冷哼從身側響起柬赐,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肛宋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后酝陈,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡锈死,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年穆壕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缨该。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡贰拿,死狀恐怖熄云,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情缴允,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響晴及,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一势木、第九天 我趴在偏房一處隱蔽的房頂上張望歌懒。 院中可真熱鬧,春花似錦甫男、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至端幼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間婆跑,已是汗流浹背谱秽。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疟赊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓驮审,卻偏偏與公主長得像吉执,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子戳玫,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內容