0
点赞
收藏
分享

微信扫一扫

算法训练 表达式计算

问题描述   输入一个只包含加减乖除和括号的合法表达式,求表达式的值。其中除表示整除。 输入格式   输入一行,包含一个表达式。 输出格式   输出这个表达式的值。 样例输入 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中新的栈顶运算符相比较
  1. 遇到括号时
  1. 如果是右括号“)”,则直接压入s1
  2. 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃
  1. 重复步骤2至5,直到表达式的最左边
  2. 将s1中剩余的运算符依次弹出并压入s2
  3. 依次弹出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中新的栈顶运算符相比较;
  1. 遇到括号时:
  1. 如果是左括号“(”,则直接压入s1;
  2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  1. 重复步骤2至5,直到表达式的最右边;
  2. 将s1中剩余的运算符依次弹出并压入s2;
  3. 依次弹出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 }

 

作者:你的雷哥

本文版权归作者所有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。

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

介绍


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


中缀表达式

简介


中缀表达式就是常见的运算表达式,如(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中新的栈顶运算符相比较
  1. 遇到括号时
  1. 如果是右括号“)”,则直接压入s1
  2. 如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃
  1. 重复步骤2至5,直到表达式的最左边
  2. 将s1中剩余的运算符依次弹出并压入s2
  3. 依次弹出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中新的栈顶运算符相比较;
  1. 遇到括号时:
  1. 如果是左括号“(”,则直接压入s1;
  2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  1. 重复步骤2至5,直到表达式的最右边;
  2. 将s1中剩余的运算符依次弹出并压入s2;
  3. 依次弹出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 }

 

 

举报

相关推荐

0 条评论