zoukankan      html  css  js  c++  java
  • 算法训练 表达式计算

    问题描述
      输入一个只包含加减乖除和括号的合法表达式,求表达式的值。其中除表示整除。
    输入格式
      输入一行,包含一个表达式。
    输出格式
      输出这个表达式的值。
    样例输入
    1-2+3*(4-5)
    样例输出
    -4
    数据规模和约定
      表达式长度不超过100,表达式运算合法且运算过程都在int内进行。

    这道题如果不太了解前缀、中缀、后缀表达式的话,处理起来还是很棘手的,所以我先简绍这几个表达式,下面是关于这三个表达式和其转换的介绍。

    前缀、中缀、后缀表达式(逆波兰表达式)

    介绍

    前缀表达式、中缀表达式、后缀表达式都是四则运算的表达方式,用以四则运算表达式求值
    ,即数学表达式的求职

    中缀表达式

    简介

    中缀表达式就是常见的运算表达式,如(3+4)×5-6

    前缀表达式

    简介

    前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前

    比如:- × + 3 4 5 6

    前缀表达式的计算机求值

    从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果

    • 例如:- × + 3 4 5 6

      1. 从右至左扫描,将6、5、4、3压入堆栈
      2. 遇到+运算符,因此弹出3和4(3为栈顶元素,4为次顶元素,注意与后缀表达式做比较),计算出3+4的值,得7,再将7入栈
      3. 接下来是×运算符,因此弹出7和5,计算出7×5=35,将35入栈
      4. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果

    将中缀表达式转换为前缀表达式

    转换步骤如下:

    1. 初始化两个栈:运算符栈s1,储存中间结果的栈s2
    2. 从右至左扫描中缀表达式
    3. 遇到操作数时,将其压入s2
    4. 遇到运算符时,比较其与s1栈顶运算符的优先级
      1. 如果s1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈
      2. 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入s1
      3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较
    5. 遇到括号时
      1. 如果是右括号“)”,则直接压入s1
      2. 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃
    6. 重复步骤2至5,直到表达式的最左边
    7. 将s1中剩余的运算符依次弹出并压入s2
    8. 依次弹出s2中的元素并输出,结果即为中缀表达式对应的前缀表达式

    例如:1+((2+3)×4)-5具体过程,如下表

    扫描到的元素S2(栈底->栈顶)S1 (栈底->栈顶)说明
    5 5 数字,直接入栈
    - 5 - s1为空,运算符直接入栈
    ) 5 -) 右括号直接入栈
    4 5 4 -) 数字直接入栈
    x 5 4 -)x s1栈顶是右括号,直接入栈
    ) 5 4 -)x) 右括号直接入栈
    3 5 4 3 -)x) 数字
    + 5 4 3 -)x)+ s1栈顶是右括号,直接入栈
    2 5 4 3 2 -)x)+ 数字
    ( 5 4 3 2 + -)x 左括号,弹出运算符直至遇到右括号
    ( 5 4 3 2 + x - 同上
    + 5 4 3 2 + x -+ 优先级与-相同,入栈
    1 5 4 3 2 + x 1 -+ 数字
    到达最左端 5 4 3 2 + x 1 + - s1剩余运算符

    结果是:- + 1 × + 2 3 4 5

    后缀表达式

    简介

    后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后

    比如:3 4 + 5 × 6 -

    后缀表达式计算机求值

    与前缀表达式类似,只是顺序是从左至右:

    从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

    例如后缀表达式“3 4 + 5 × 6 -”

    1. 从左至右扫描,将3和4压入堆栈;
    2. 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
    3. 将5入栈;
    4. 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
    5. 将6入栈;
    6. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

    将中缀表达式转换为后缀表达式

    与转换为前缀表达式相似,步骤如下:

    1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
    2. 从左至右扫描中缀表达式;
    3. 遇到操作数时,将其压s2;
    4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
      1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
      2. 否则,若优先级比栈顶运算符的高,也将运算符压入s1(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
      3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
    5. 遇到括号时:
      1. 如果是左括号“(”,则直接压入s1;
      2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
    6. 重复步骤2至5,直到表达式的最右边;
    7. 将s1中剩余的运算符依次弹出并压入s2;
    8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)

    例如,将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下

    扫描到的元素s2(栈底->栈顶)s1 (栈底->栈顶)说明
    1 1 数字,直接入栈
    + 1 + s1为空,运算符直接入栈
    ( 1 + ( 左括号,直接入栈
    ( 1 + ( ( 同上
    2 1 2 + ( ( 数字
    + 1 2 + ( ( + s1栈顶为左括号,运算符直接入栈
    3 1 2 3 + ( ( + 数字
    ) 1 2 3 + + ( 右括号,弹出运算符直至遇到左括号
    × 1 2 3 + + ( × s1栈顶为左括号,运算符直接入栈
    4 1 2 3 + 4 + ( × 数字
    ) 1 2 3 + 4 × + 右括号,弹出运算符直至遇到左括号
    - 1 2 3 + 4 × + - -与+优先级相同,因此弹出+,再压入-
    5 1 2 3 + 4 × + 5 - 数字
    到达最右端 1 2 3 + 4 × + 5 - s1中剩余的运算符

                                   因此结果为“1 2 3 + 4 × + 5 -”

    则用Java实现的代码如下:

      1 package Test1;
      2 import java.util.Scanner;
      3 import java.util.Stack;  
      4     public class Main{   
      5         
      6         public static Stack<Integer> aIntegers=new Stack<>();//HouDui的数值栈
      7         public static Stack<String> aCharacter2=new Stack<>();//MidToHou的数值栈的
      8         public static Stack<String> aCharacter=new Stack<>();//MidToHou的符号栈
      9         static int length;
     10         static int length1;
     11         public static  String[] array1=new String[1000];
     12         public static char array[]=new char[100];
     13         public static void main(String[] args){  
     14             
     15             Scanner scanner=new Scanner(System.in);
     16             String aString=scanner.nextLine();
     17             length=aString.length();
     18             length1=0;
     19             for (int i = 0; i < aString.length(); i++) {
     20                 array[i]=aString.charAt(i);
     21             }
     22             MidToHou(array);
     23             HouDui(array1);
     24         }
     25         static int sum(char a[],int start, int end) {//某些数会大于9,
     26             int i, sum = 0;
     27             for (i = start; i <end; i++)
     28                 sum = sum * 10 + (int)a[i]-48;
     29             return sum;
     30         }
     31         public static void MidToHou(char array[])//中缀变为后缀
     32         {
     33             for (int i = 0; i < length; i++) {
     34                 if(array[i]>='0' && array[i]<='9')
     35                 {
     36                     int j=i+1;
     37                     while(true)
     38                     {
     39                         if(array[j]>='0'&&array[j]<='9') {
     40                             j++;
     41                         }else {
     42                             break;
     43                         }
     44                     }
     45                     int m=sum(array, i, j);
     46                     String m1=String.valueOf(m);
     47                     aCharacter2.push(m1);
     48                     i=j-1;
     49                 }
     50                 else {
     51                     if(array[i]=='(') {
     52                         aCharacter.push(String.valueOf(array[i]));
     53                         continue;
     54                     }
     55                     if(aCharacter.isEmpty()==true || aCharacter.peek().equals("(")) {
     56                         aCharacter.push(String.valueOf(array[i]));
     57                         continue;
     58                     }
     59                     if(array[i]==')') {
     60                         while(true) {
     61                             String s=aCharacter.pop();
     62                             if(s.equals("(")) break;
     63                             else
     64                                 aCharacter2.push(s);
     65                         }
     66                         continue;
     67                     }
     68                     if((array[i]=='*' || array[i]=='/') && (aCharacter.peek().equals("+") || aCharacter.peek().equals("-"))) {
     69                         aCharacter.push(String.valueOf(array[i]));
     70                     }else {
     71                         aCharacter2.push(aCharacter.pop());
     72                         i--;
     73                     }
     74                     
     75                 }
     76             }
     77             while(aCharacter.isEmpty()==false)
     78             {
     79                 aCharacter2.push(aCharacter.pop());
     80             }
     81             length1=0;
     82             while(aCharacter2.isEmpty()==false) {
     83                 array1[length1++]=aCharacter2.pop();
     84             }
     85         }
     86         public static  void HouDui(String array[])//根据后缀表达式求出结果
     87         {
     88             
     89             for (int i = length1-1; i >=0; i--) {
     90               if(array[i].equals("-")==false && array[i].equals("+")==false && array[i].equals("*")==false && array[i].equals("/")==false) {
     91                   aIntegers.push(Integer.parseInt(array[i]));
     92               }else {
     93                  if(array[i].equals("-")) {
     94                      int a=aIntegers.pop();
     95                      int b=aIntegers.pop();
     96                      int c=b-a;
     97                      aIntegers.push(c);
     98                  }
     99                  if(array[i].equals("+")) {
    100                      int a=aIntegers.pop();
    101                      int b=aIntegers.pop();
    102                      int c=b+a;
    103                      aIntegers.push(c);
    104                  }
    105                  if(array[i].equals("*")) {
    106                      int a=aIntegers.pop();
    107                      int b=aIntegers.pop();
    108                      int c=b*a;
    109                      aIntegers.push(c);
    110                  }
    111                  if(array[i].equals("/")) {
    112                      int a=aIntegers.pop();
    113                      int b=aIntegers.pop();
    114                      int c=b/a;
    115                      aIntegers.push(c);
    116                  }
    117                   
    118               }
    119             }
    120             int answer=aIntegers.pop();
    121             System.out.println(answer);
    122         }
    123  }
  • 相关阅读:
    Linux常用命令
    Spring Boot☞ 多数据源配置(二):Spring-data-jpa
    好用的Markdown编辑器一览
    Spring Boot☞ 使用Spring-data-jpa简化数据访问层
    谈谈Spring 注入properties文件总结
    Spring Boot☞ 统一异常处理
    Spring Boot☞ 使用velocity渲染web视图
    Spring Boot☞ 使用freemarker模板引擎渲染web视图
    静态联编与动态联编
    C++ 模板元编程 学习笔记
  • 原文地址:https://www.cnblogs.com/henuliulei/p/10420314.html
Copyright © 2011-2022 走看看