zoukankan      html  css  js  c++  java
  • javascript使用栈结构将中缀表达式转换为后缀表达式并计算值

    1.概念

      你可能听说过表达式,a+b,a+b*c这些,但是前缀表达式,前缀记法,中缀表达式,波兰式,后缀表达式,后缀记法,逆波兰式这些都是也是表达式。

      a+b,a+b*c这些看上去比较正常的是中缀表达式,就是运算符放在两个操作数之间。前缀表达式是将运算符放在相关操作数之前,后缀表达式是将运算符放在操作数之后。

      至于前面说的那些概念:

      前缀表达式就是波兰式就是前缀记法

      后缀表达式就是逆波兰式就是后缀记法

    举例如下:

    (3+4)*5-6就是中缀表达式

    -*+3456就是前缀表达式

    34+5*6-就是后缀表达式

      虽然人的大脑很容易理解与分析中缀表达式,但是对于计算机来说中缀表达式确是很复杂的,因此计算表达式的值时通常需要把中置表达式转换为前置或者后置表达式,然后再进行求值。对于计算机来说,计算前缀表达式或者后置表达式非常简单。

    2.中置表达式转换为后置表达式

    中缀表达式a + b * c + ( d * e + f ) * g,转化为后缀表达式之后是a b c * + d e * f  + g * +,具体的转换过程如下:

    1)如果遇到操作数,直接将其输出

    2)如果遇到操作符,则将其放入栈中,遇到左括号也将其放入栈中

    3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止,左括号只弹出不输出

    4)遇到其他的操作符例如 + ,* , (从栈中弹出元素直到遇到发现更低优先级的元素或者栈空为止。弹出这些元素之后,才能将遇到的操作符压入到栈中,有一点要注意,只有遇到 ) 的情况下才弹出 ( 其他情况下都不会弹出 (

    5)如果读到了输入的末尾,则将栈中的所有元素依次弹出

    3.示例 

    规则很多,还是用实例比较容易说清楚整个过程。以上面的转换为例,输入为a + b * c + (d * e + f)*g,处理过程如下:

    1)首先读到a,直接输出。

    2)读到“+”,将其放入到栈中。

    3)读到b,直接输出。

    表达式  * c + (d * e + f) * g, 此时栈和输出的情况如下:

     

    4)读到“*”,因为栈顶元素"+"优先级比" * " 低,所以将" * "直接压入栈中。

    5)读到c,直接输出。

    表达式  + (d * e + f) * g, 此时栈和输出情况如下:

     

    6)读到" + ",因为栈顶元素" * "的优先级比它高,所以弹出" * "并输出, 同理,栈中下一个元素" + "优先级与读到的操作符" + "一样,所以也要弹出并输出。然后再将读到的" + "压入栈中。

    表达式 (d * e + f) * g,此时栈和输出情况如下:

     

    7)下一个读到的为"(",它优先级最高,所以直接放入到栈中。

    8)读到d,将其直接输出。

    表达式  * e + f) * g,此时栈和输出情况如下:

     

    9)读到" * ",由于只有遇到" ) "的时候左括号"("才会弹出,所以" * "直接压入栈中。

    10)读到e,直接输出。

    表达式  + f) * g,此时栈和输出情况如下:

     

    11)读到" + ",弹出" * "并输出,然后将"+"压入栈中。

    12)读到f,直接输出。

    表达式 ) * g,此时栈和输出情况:

      

    13)接下来读到“)”,则直接将栈中元素弹出并输出直到遇到"("为止。这里右括号前只有一个操作符"+"被弹出并输出。

    表达式  * g

     

    14)读到" * ",压入栈中。读到g,直接输出。

    表达式为空

     

    15)此时输入数据已经读到末尾,栈中还有两个操作符“*”和" + ",直接弹出并输出。表达式 a + b * c + (d * e + f) * g

    至此整个转换过程完成。程序实现代码后续再补充了

    4.后缀表达式求值

    假设一个后缀表达式为 6 5 2 3 + 8 * + 3 + * ,则其求值过程如下: 

    1)遍历表达式,遇到的数字首先放入栈中,此时栈如下所示: 

     

    2)接着读到“+”,则弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中。 

     

    3)读到8,将其直接放入栈中。 

     

    4)读到“*”,弹出8和5,执行8*5,并将结果40压入栈中。而后过程类似,读到“+”,将40和5弹出,将40+5的结果45压入栈...以此类推。最后求的值288。

    //使用数组dataStore保存站内元素,构造函数将其初始化为一个空数组。
    //变量top定义栈顶的位置,构造时初始化为0,表示栈的起始位置为0
    function Stack(){
        this.dataStore = [];
        this.top = 0;
        this.push = push;
        this.pop = pop;
        this.peek = peek;
        this.clear = clear;
        this.length = length;
        this.printElement = printStack;
    
        //注意++操作符的位置,它放在this.top的后面,这样新入栈的元素就被放在top的当前位置对应的位置,同时top自加1,指向下一个位置
        function push(element){
            this.dataStore[this.top++] = element;
        }
        //返回栈顶元素,同时top的位置减1
        function pop(){
            return this.dataStore[--this.top];
        }
        //peek()方法返回数组的第top-1个位置的元素,即栈顶元素
        function peek(){
            return this.dataStore[this.top-1];
        }
        //将top的值设置0,即清空一个栈
        function clear(){
            this.top = 0;
        }
        //返回变量top的值即为栈内元素的个数
        function length(){
            return this.top;
        }
        
        //输出栈内元素
        function printStack(){
            while (this.top>0){
                document.writeln(this.pop()+"  ");
            }
        }
    }
    
    /*-------------------栈将中缀表达式转换成后缀表达式-------------------*/
    document.write('<br><br>');
    function suffixExpression(){
        var str = 'a+b*c+(d*e+f)*g';
        var stack = new Stack();
        var outStack = new Array();
        for (var i=0; i<str.length; ++i) {
            if(')' == str[i]){
                while (true){
                    var top = stack.peek();
                    stack.pop();
                    if('(' != top){
                        outStack[outStack.length] = top;
                    }else{
                        break;
                    }
                }
            }else if(['-','+'].indexOf(str[i])>-1){
                if(['*','/'].indexOf(stack.peek())>-1){
                    while (['*','/'].indexOf(stack.peek())>-1){
                        outStack[outStack.length] = stack.peek();
                        stack.pop();
                    }
                    outStack[outStack.length] = str[i];
                }else{
                    stack.push(str[i]);
                }
            }else if(['(','*','/'].indexOf(str[i])>-1){
                stack.push(str[i]);
            }else{
                outStack[outStack.length] = str[i];
            }        
        }
        
        for (var i=0; i< outStack.length; i++) {
            document.write(outStack[i]);
        }
        
    
    }
    suffixExpression();
    /*-------------------用栈结构求后缀表达式的值-------------------*/
    document.write('<br><br>');
    function countSuffixExpression(){
        var str = '6523+8*+3+*';
        var stack = new Stack();
        for (var i=0; i<str.length; i++) {
            if(isNaN(str[i])){
                stack.push( eval( stack.pop() + str[i] + stack.pop()) );
            }else{
                stack.push(str[i])
            }
        }
        
        document.write(stack.pop());
    }
    countSuffixExpression();

    输出结果如下:

  • 相关阅读:
    我的浏览器收藏夹分类
    我的浏览器收藏夹分类
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 318 最大单词长度乘积
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 316 去除重复字母
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
    Java实现 LeetCode 315 计算右侧小于当前元素的个数
  • 原文地址:https://www.cnblogs.com/tylerdonet/p/5816464.html
Copyright © 2011-2022 走看看