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  }
  • 相关阅读:
    LeetCode对撞指针汇总
    167. Two Sum II
    215. Kth Largest Element in an Array
    2018Action Recognition from Skeleton Data via Analogical Generalization over Qualitative Representations
    题解 Educational Codeforces Round 84 (Rated for Div. 2) (CF1327)
    题解 JZPKIL
    题解 八省联考2018 / 九省联考2018
    题解 六省联考2017
    题解 Codeforces Round #621 (Div. 1 + Div. 2) (CF1307)
    题解Codeforces Round #620 (Div. 2)
  • 原文地址:https://www.cnblogs.com/henuliulei/p/10420314.html
Copyright © 2011-2022 走看看