JavaScript實現計算後綴表達式(逆波蘭表達式)以及將中綴表達式轉爲後綴表達式

逆波蘭表達式,它的語法規定,表達式必須以逆波蘭表達式的方式給出。逆波蘭表達式又叫做後綴表達式。這個知識點在數據結構和編譯原理這兩門課程中都有介紹,下面是一些例子:
  正常的表達式 逆波蘭表達式
  a+b ---> a,b,+
  a+(b-c) ---> a,b,c,-,+
  a+(b-c)d ---> a,d,b,c,-,,+
  a=1+3 ---> a=1,3 +
  http=(smtp+http+telnet)/1024 寫成什麼呢?
  http=smtp,http,telnet,+,+,1024,/
  逆波蘭表達式是一種十分有用的表達式,它將複雜表達式轉換爲可以依靠簡單的操作得到計算結果的表達式。例如(a+b)(c+d)轉換爲ab+cd+
  它的優勢在於只用兩種簡單操作,入棧和出棧就可以搞定任何普通表達式的運算。

計算逆波蘭表達式方式如下:
  如果當前字符爲變量或者爲數字,則壓棧,如果是運算符,則將棧頂兩個元素彈出作相應運算,結果再入棧,最後當表達式掃描完後,棧裏的就是結果。

將一個普通的中序表達式轉換爲逆波蘭表達式的一般算法是:
  (1)首先構造一個運算符棧,此運算符在棧內遵循越往棧頂優先級越高的原則。
  (2)讀入一個用中綴表示的簡單算術表達式,爲方便起見,設該簡單算術表達式的右端多加上了優先級最低的特殊符號“#”。
  (3)從左至右掃描該算術表達式,從第一個字符開始判斷,如果該字符是數字,則分析到該數字串的結束並將該數字串直接輸出。
  (4)如果不是數字,該字符則是運算符,此時需比較優先關係。
  做法如下:將該字符與運算符棧頂的運算符的優先關係相比較。如果,該字符優先關係高於此運算符棧頂的運算符,則將該運算符入棧。倘若不是的話,則將棧頂的運算符從棧中彈出,直到棧頂運算符的優先級低於當前運算符,將該字符入棧。
  (5)重複上述操作(3)-(4)直至掃描完整個簡單算術表達式,確定所有字符都得到正確處理,我們便可以將中綴式表示的簡單算術表達式轉化爲逆波蘭表示的簡單算術表達式。
  下面是程序化算法流程:
  1、建立運算符棧stackOperator用於運算符的存儲,壓入'\0'。
  2、預處理表達式,正、負號前加0(如果一個加號(減號)出現在最前面或左括號後面,則該加號(減號)爲正負號) 。
  3、順序掃描表達式,如果當前字符是數字(優先級爲0的符號),則直接輸出該數字;如果當前字符爲運算符或括號(優先級不爲0的符號),則判斷第4點 。
  4、若當前運算符爲'(',直接入棧;
  若爲')',出棧並順序輸出運算符直到遇到第一個'(',遇到的第一個'('出棧但不輸出;
  若爲其它,比較stackOperator棧頂元素與當前元素的優先級:
  如果 棧頂元素 >= 當前元素,出棧並順序輸出運算符直到 棧頂元素 < 當前元素,然後當前元素入棧;
  如果 棧頂元素 < 當前元素,直接入棧。
  5、重複第3點直到表達式掃描完畢。
  6、順序出棧並輸出運算符直到棧頂元素爲'\0'。
  各運算符及符號優先級:
  '\0': -1
  ')': 1
  '(': 2
  '+'、'-': 3
  '*'、'/'、'%': 4
  '^': 5
  其它: 0

/**
* 計算逆波蘭表達式的值
*/
function calculate(RPolishArray){
    var result = 0;
    var tempArray = new Array(100);
    var tempNum = -1;
    for(i = 0;i < RPolishArray.length;i++){
        if(RPolishArray[i].match(/\d/)){
            tempNum++;
            tempArray[tempNum] = RPolishArray[i];
        }else{
            switch(RPolishArray[i]){
                case '+':
                    result = (tempArray[tempNum-1] *1) + (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '-':
                    result = (tempArray[tempNum-1] *1) - (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '*':
                    result = (tempArray[tempNum-1] *1) * (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
                case '/':
                    result = (tempArray[tempNum-1] *1) / (tempArray[tempNum] * 1);
                    tempNum--;
                    tempArray[tempNum] = result;
                    break;
            }
        }
    }
    result = tempArray[tempNum];    
    return result;  
}

/**
* 把普通算術表達式轉換爲逆波蘭表達式
*/
function toRPolish(input){
    var regex = /(\(|\)|\+|\-|\*|\/)+/;
    var array = input.split(regex);
    var RPolish = ""
    var isI = false;
    num = 0;
    var SymbolArray = new Array(100);
    var SymbolNum = -1;
    for(j = 0;j < input.length;j++){        
        if(input.charAt(j).match(/\d/)){
            if(isI == false){
                RPolish += ','
                RPolish += array[num];
                num++;
                isI = true;
            }
        }
        else{
            if(SymbolNum == -1){ 
                    SymbolNum++;
                    SymbolArray[SymbolNum] = input.charAt(j);
            }else{
                if(input.charAt(j).match(/\(/)  || SymbolArray[SymbolNum].match(/\(/)){
                        SymbolNum++;
                        SymbolArray[SymbolNum] = input.charAt(j);
                }else if(input.charAt(j).match(/\)/)){
                    while(!SymbolArray[SymbolNum].match(/\(/)){
                        RPolish += ',';                     
                        RPolish += SymbolArray[SymbolNum];
                        SymbolNum--;
                    }
                    SymbolNum--;
                }else if(compare(input.charAt(j),SymbolArray[SymbolNum])){
                        SymbolNum++;
                        SymbolArray[SymbolNum] = input.charAt(j);
                }else if(!compare(input.charAt(j),SymbolArray[SymbolNum])){
                        RPolish += ','; 
                        RPolish += SymbolArray[SymbolNum];
                        SymbolNum--;
                        if(SymbolNum >= 0){
                            if(SymbolArray[SymbolNum].match(/\(/)){
                                SymbolNum++;
                                SymbolArray[SymbolNum] = input.charAt(j);
                            }else if(!compare(input.charAt(j),SymbolArray[SymbolNum])){
                                RPolish += ',';
                                RPolish += SymbolArray[SymbolNum];
                                SymbolArray[SymbolNum] = input.charAt(j);
                            }else{
                                SymbolNum++;
                                SymbolArray[SymbolNum] = input.charAt(j);
                            }
                        }else{
                            SymbolNum++;
                            SymbolArray[SymbolNum] = input.charAt(j);
                        }
                }
            }
            isI = false;
        }
    }           
    while(SymbolNum >=0){
        RPolish += ',';
        RPolish += SymbolArray[SymbolNum];
        SymbolNum--;
    }
    regex =  /,/;
    var RPolishArray = RPolish.split(regex);
    return RPolishArray;
}

function compare(a,b){
    if((a.match(/\*/)||a.match(/\//))&&(b.match(/\+/)||b.match(/\-/))){
        return true;
    }else{
        return false;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章