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;
    }
}

原文地址:https://www.cnblogs.com/zhoulixiangblog/p/12347282.html

时间: 2024-09-28 20:43:14

JavaScript实现计算后缀表达式(逆波兰表达式)以及将中缀表达式转为后缀表达式的相关文章

栈的典型实例问题——后缀表达式(逆波兰记号)的计算

//编译程序一般使用后缀表达式求解表达式的值(RPN或者逆波兰记号)//计算后缀表达式的过程为:扫描,如果该项是操作数,压栈:如果是操作符,则从栈中退出两个操作数(先退出的是右操作//数),进行运算,并将运算结果重新压入栈中,扫描完后栈顶存放的就是计算结果.//注意的地方:是否支持2位以上的操作数!//操作数之间也肯定是有分割符的: //比如:12 34 56 * + //如果是123456*+,不管是人还是计算机,都是没法做的: 1 #include<iostream> 2 #include

Java解析字符串表达式--逆波兰表达式的计算

问题来由: 读入一个字符串形式的四则运算表达式,输出对应的计算结果.如读入的是"6 * ( 5 + ( 2 + 3) * 8 + 3)",那么解析后的输出结果应为288. 思路: 一般的计算过程是这样的,首先计算优先级最高的小括号里面的内容,即"( 5 + ( 2 + 3) * 8 + 3)", 将"2 + 3"的计算结果并存为A,接着用计算"A*8",并存为B 计算"5+B+3",结果存为C 最后计算&q

Java解析字符串表达式--逆波兰表达式的生成

上回讲了如何计算后缀表达式,其实真正的难点在于如何将一个正常的字符串表达式(中缀表达式)变成一个后缀表达式.如将6 * ( 5 + ( 2 + 3) * 8 + 3)变为6 5 2 3 + 8 * + 3 + * 逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出.逆波兰表达式又叫做后缀表达式.这个知识点在数据结构和编译原理这两门课程中都有介绍,下面是一些例子: 正常的中缀表示 逆波兰表达式 a+b a,b,+ a+(b-c) a,b,c,-,+ a+(b-c)*d a,b,c,-,

栈的应用之中缀表达式转化为后缀表达式(逆波兰表达式)

1 #include<stdio.h> 2 #include<stdlib.h> 3 4 #define OK 1 5 #define ERROR 0 6 #define STACK_INIT_SIZE 20 7 #define STACK_INCREMENT 10 8 9 typedef char Elemtype; 10 typedef int Status; 11 12 typedef struct StackNode{ 13 Elemtype* base; 14 Elemt

逆波兰表达式(后缀表达式)

逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出.逆波兰表达式又叫做后缀表达式.下面是一些例子: 正常的表达式 逆波兰表达式 a+b ---> a,b,+ a+(b-c) ---> a,b,c,-,+ a+(b-c)*d ---> a,b,c,-,d,*,+ a+d*(b-c)--->a,d,b,c,-,*,+ a=1+3 ---> a=1,3 + 通过后缀表达式计算表达式值的过程:顺序访问表达式的每一项,若该项为操作数,则将其压入栈中:若该项是操作符<o

逆波兰式篇(后缀表达式)

一.逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面.也称为后缀表达式. 二.一般算法 将一个普通的中序表达式转换为逆波兰表达式的一般算法是: 首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则. 读入一个中缀表达式,为了方便起见,可在其最右端追加一个最低优先级运算符(如:#号).(这样做的目的是,最后读入#号运算符时将运算符栈中所有运算符都输       出). 从左至右扫描该中

波兰、逆波兰表达式

软考习题里遇到了这样一道题,给出了一个逆波兰式,让求它对应的中缀表达式. 逆波兰式:ab-cd+* ,它的中缀表达式是(a-b)*(c+d) 思考: 这让我蒙圈了,这是为什么呢.怎么得到的呢,应该有什么规律的吧. 首先我们要知道: 波兰式:前缀表达式 逆波兰式:后缀表达式 了解这三个表达式之前,我们需要知道 表达式 解释 例子 前缀 不含括号的的算数表达式,将运算符写在前面,操作数写在后面 *+ 2 1 3 中缀 必须含括号,操作符处于操作数的中间 (2+1)*3 后缀 不含括号,运算符放在两个

栈应用——逆波兰式表达式的值

问题描述: 计算给定的逆波兰表达式(即后缀表达式)的值. 事实上,二元运算的前提下,中缀表达式可以对应一棵二叉树:逆波兰式即该二叉树后序遍历的结果. 分析思路: 如果当前是操作数,则直接入栈: 如果当前是操作符,则栈顶的两个元素弹出,然后与当前操作符运算后入栈. Code: /** * 给出一个逆波兰式,计算该表达式的值 * @param s * @return */ public int getTheValueOfRPN(String s) { char[] ch = s.toCharArra

基于逆波兰表达式的公式解析器-算法和思路(一)

背景: 近期项目须要自己完毕Excel的公式解析和求值,在Java中能够使用POI解析Excel公式然后求值.可是项目须要JS端和Java后端均须要支持公式解析,所以就须要自己写一套了.事实上公式解析器整体上并不复杂.原理使用逆波兰表达式就可了. 难点: 1. 针对复杂的用户输入环境解析公式,须要注意公式书写不规范.大写和小写.空格等问题,甚至公式出错的推断. 2. 须要解决函数扩展.函数运行等问题. 3. 须要解决地址.地址范围取数,求值问题. 4. 处理括号带来的优先级提升. 5. 解决公式