搜索

首页  >  问答  >  正文

javascript - 如何用js实现中缀表达式转后缀表达式然后求值

如何用js实现中缀表达式转后缀表达式然后求值

迷茫迷茫2780 天前856

全部回复(2)我来回复

  • 高洛峰

    高洛峰2017-04-10 14:37:32

    算法叫逆波兰表达式
    逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。逆波兰表达式又叫做后缀表达式。这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子:
      正常的表达式 逆波兰表达式
      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;
        }
    }
    

    从网上找来的例子http://huangyuanmu.iteye.com/blog/435938
    网上看到一个有图解释的应该会好理解
    http://blog.csdn.net/sgbfblog/article/details/8001651

    回复
    0
  • 天蓬老师

    天蓬老师2017-04-10 14:37:32

    这事其实和js关系不大,你先要知道“中缀表达式转后缀表达式然后求值”的原理,然后你就知道“如何用js实现中缀表达式转后缀表达式然后求值”了。

    回复
    0
  • 取消回复