栈的应用-逆波兰式

Posted sang-bit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了栈的应用-逆波兰式相关的知识,希望对你有一定的参考价值。

---恢复内容开始---

普通的计算方式,也叫中缀表达式计算机识别及正确运用需要耗费大量的资源

23+45*2-(8+2)

计算机想要正确计算出此时的结果需要十分复杂,更何况情况十分多变。

逆波兰式:又叫做后缀表达式,它能去除中缀表达式的括号。十分符合计算机的计算思维,能极大提高效率

表达式不能用字符串进行存储,因为这将无法分辨,应用集合(ArrayList,LinkedList存储)

23 45 2 * 8 2 + - +

那么中缀表达式是如何变成后缀表达式的呢?原则如下:

    1.首先把普通的表达式按照运算符分离出来放在一个集合E中,比如1+2*3 分离后集合里的元素就是 1 + 2 * 3 五个元素

    2.再定义一个集合R(最好是字符串类型的集合,免得后面要转类型),主要是用来存放逆波兰表达式的,还有定义一个堆栈(存储运算符用),最后从左到右遍历集合E     

    3.遍历E的规则如下:

         3.1如果该元素是数字,直接把它添加到集合R中

         3.2否则它肯定是运算符,那么再进行判断

              3.2.1如果该元素是左括号,或者当时栈为空,那么直接入栈

              3.2.2如果该元素是右括号,则把栈内的运算符出栈并添加到集合R中,直到遇到第一个左括号结束(左括号也出栈但不添加到R)

              3.2.3否则该元素是普通的运算符(也就是+-*/之类的),那么用该运算符和栈内的运算符号比较优先级,如果该运算符的优先级比栈内的运算符

                优先级高 或者 栈为空,则直接入栈,否则把栈内的运算符出栈并添加到R中,再判断下个栈内的运算符优先级,直到遇栈内的运

          算符优先级<=该运算符或者栈为空时再把该运算符入栈

         3.3整个过程完成后,再把栈内的所有运算符出栈并添加到R中

成功得到后缀表达式,但计算机又是如何通过后缀表达式计算出结果的呢?

这就需要运用到数据结构栈的特点

    1. 把上面的数值依次压入栈,若遇到运算符,则依次拿出栈顶的两个元素用该运算符进行运算,把结果在压入栈
    2. 直到后缀表达式全部读完,栈顶的数就是运算结果

上式具体流程就是;

    1. 依次把23 45 2 压入栈
    2. 计算45*2=90,90压入栈
    3. 依次把8 2 压入栈
    4. 计算8+2=10 10压栈
    5. 计算90-10=80 80压入栈
    6. 计算23+80=103 103压入栈
    7. 提取栈顶103

代码如下;

import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.Stack;

public class test {

     /** 
     * 将字符串转换为中序表达式 
     */  
    public static ArrayList<String> toZhong(String s){
        ArrayList<String> arrayList=new ArrayList();//存贮中缀表达式
        for(int i=0;i<s.length();i++){
            String str="";
            if(s.charAt(i)<48||s.charAt(i)>57){//48:0,57:9
                str=str+s.charAt(i);
                arrayList.add(str);
            }
            else{
                while(i<s.length()&&s.charAt(i)>=48&&s.charAt(i)<=57){
                    str=str+s.charAt(i);
                    i++;
                }
                arrayList.add(str);
                i--;
            }
        }
        return arrayList;
    }
---------------------------------------------------------------------------------------
    /*
     * 把中缀表达式转成逆波兰式
     */
    public static ArrayList<String> toNishi(ArrayList<String> list){
        ArrayList<String> arr=new ArrayList();//用表存储逆波兰式
        Stack<String> timeStack=new Stack();//临时存储操作符
        for(String s:list){
            if(s.matches("\\d+")){
                arr.add(s);
            }
            else if(s.equals("(")){
                timeStack.push(s);
            }
            else if(s.equals(")")){
                while(!(timeStack.peek().equals("("))){
                    arr.add(timeStack.pop());
                }
            }
            else{
                while(timeStack.size()!=0&&getValue(s)<getValue(timeStack.peek())){
                    arr.add(timeStack.pop());
                }
                timeStack.push(s);
            }
        }
        while(timeStack.size()!=0){
            arr.add(timeStack.pop());
        }
        return arr;
    }
         public static int getValue(String ss) {  
                if (ss.equals("+")) {  
                    return 1;  
                } else if (ss.equals("-")) {  
                    return 1;  
                } else if (ss.equals("*")) {  
                    return 2;  
                } else if (ss.equals("\\")) {  
                    return 2;  
                }  
                return 0;  
            } 
------------------------------------------------------------------------------------------
        //计算逆波兰式结果
    public static int jisuan(ArrayList<String> arr){
         Stack<Integer> jieguo=new Stack<Integer>();
         for(String s:arr){
             if(s.matches("\\d+")){
                 jieguo.push(Integer.parseInt(s));
             }
             else if(jieguo.size()>=2){
                 Integer a=jieguo.pop();
                 Integer b=jieguo.pop();
             if(s.equals("+")){
                 jieguo.push(b+a);
             }
             else if(s.equals("-")){
                 jieguo.push(b-a);
             }
             else if(s.equals("*")){
                 jieguo.push(b*a);
             }
             else if(s.equals("//")){
                 jieguo.push(b/a);
             }
         }
         }
         return jieguo.pop();
    }

 

---恢复内容结束---

以上是关于栈的应用-逆波兰式的主要内容,如果未能解决你的问题,请参考以下文章

栈的应用,中后缀表达式的转换:波兰式和逆波兰式

栈的应用-逆波兰式

算法与数据结构--栈的应用-逆波兰计算器完整版代码

(C语言中)逆波兰算法(及计算器)

栈的应用之求逆波兰表达式的值

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