使用栈实现解析算术表达式

目的

  1. 使用栈将中缀表达式转换成后缀表达式

  2. 使用后缀表达式求算术值



注意:

  因为是简单实践,所以代码逻辑已经简化,比如只能对个位数的加减乘除进行解析、没有设异常处理等



一:需要实现一个栈

这个没什么好说的,只是一个结构很简单的栈

 1 public class Stack {
 2
 3     private int maxSize;
 4     private int top;
 5     private Object[] stackArr;
 6
 7     public Stack(int maxSize) {
 8         this.maxSize = maxSize;
 9         stackArr = new Object[maxSize];
10         top = -1;
11     }
12
13     public void push(Object i){
14         stackArr[++top] = i;
15     }
16
17     public Object pop(){
18         return stackArr[top--];
19     }
20
21     public Object peek(){
22         return stackArr[top];
23     }
24
25     public Object peekN(int n) {
26         return stackArr[n];
27     }
28
29     public boolean isEmpty(){
30         return (top == -1);
31     }
32
33     public boolean isFull(){
34         return (top == maxSize-1);
35     }
36
37     public int size(){
38         return top+1;
39     }
40
41     public void dispaly(String s) {
42         System.out.print(s + "\t\t" + "Stack {bottom-->top}: ");
43         for (int i = 0; i < size(); i++) {
44             System.out.print(peekN(i) + "\t");
45         }
46         System.out.println();
47     }
48 }



二:将中缀表达式转换成后缀表达式

这里需要处理的操作符有:"+"、"-"、 "*"、 "/"、 "(" 、")"

需要关注的有四点:

(1)操作符的优先级:  "( )"    >    "* /"    >    "+ -"

(2)同级操作符的操作顺序是无所谓的,只要操作数顺序不变即可

(3)遇到高优先级操作时,栈的压栈和出栈的实现

(4)栈存的是操作符

  1 public class InfixToPostfix {
  2
  3     private Stack stack;
  4     private String input;
  5     private StringBuilder output;
  6     /**
  7      * 加减类型
  8      */
  9     private static final int ADD_SUB_TYPE = 1;
 10     /**
 11      * 乘除类型
 12      */
 13     private static final int MUL_DIV_TYPE = 2;
 14
 15     public InfixToPostfix(String input) {
 16         this.input = input;
 17         stack = new Stack(input.length());
 18         output = new StringBuilder();
 19     }
 20
 21     public String doTransform() {
 22         String[] split = input.split("");
 23         for (int i = 0; i < split.length; i++) {
 24             stack.dispaly("FOR\t\t" + split[i]);
 25             switch (split[i]) {
 26                 case "+":
 27                 case "-":
 28                     // 对"+"、"-"操作符进行处理
 29                     manageOperator(split[i], ADD_SUB_TYPE);
 30                     break;
 31                 case "*":
 32                 case "/":
 33                     // 对"*"、"/"操作符进行处理
 34                     manageOperator(split[i], MUL_DIV_TYPE);
 35                     break;
 36                 case "(":
 37                     // 左括号表示下一个计算块拥有更高一级优先级,直接入栈即可
 38                     stack.push(split[i]);
 39                     break;
 40                 case ")":
 41                     // 对")"操作符进行处理
 42                     manageParen(split[i]);
 43                     break;
 44                 default:
 45                     // 拼接输出结果
 46                     output.append(split[i]);
 47                     break;
 48             }
 49         }
 50         // 将栈内剩余的元素全部出栈
 51         while (!stack.isEmpty()) {
 52             stack.dispaly("WHILE\t");
 53             String pop = (String) stack.pop();
 54             output.append(pop);
 55         }
 56         stack.dispaly("END\t\t");
 57         return output.toString();
 58     }
 59
 60     /**
 61      * 对右括号操作符进行处理
 62      * @param rightParen
 63      */
 64     private void manageParen(String rightParen) {
 65         // 取出当前栈顶元素
 66         while (!stack.isEmpty()) {
 67             String top = (String) stack.pop();
 68             // 有两种情况:
 69             // 1. 取出的是 "(",说明被括号括起来的计算块已经结束,直接break掉循环即可。
 70             // 2. 取出来的是其他操作符(+-*/),出栈并打印即可。这里不能break,因为操作符可能有多个,要一直出栈,直到取到 "("
 71             if (top.equals("(")) {
 72                 break;
 73             } else {
 74                 output.append(top);
 75             }
 76         }
 77     }
 78
 79     /**
 80      * 对加减乘除操作符进行处理
 81      * @param operator
 82      * @param type
 83      */
 84     private void manageOperator(String operator, int type) {
 85         // 当栈不为空时,需要判断
 86         while (!stack.isEmpty()) {
 87             // 先取出栈顶元素
 88             String top = (String) stack.pop();
 89             // 此时,有两种情况:
 90             // 1. 取出的是 "(" 左括号,说明此时正在进行更高优先级的计算(也就是括号内的计算),所以需要把出栈 "(" 重新入栈,并break掉循环。最后将传过来的的操作符入栈。
 91             // 2. 取出的是其他操作符(+-*/),需要进行优先级判断。
 92             //      2.1 取出操作符优先级比读取的(即传过来的)高,说明应该执行上一个计算块,所以要将取出的操作符出栈并打印,break掉循环。最后将传过来的的操作符入栈。
 93             //      2.2 取出操作符优先级比读取的(即传过来的)低或者相等,说明应该或可以先执行下一个计算块,所以要将取出的操作符重新入栈,并break掉循环。最后将传过来的的操作符入栈。
 94             if (top.equals("(")) {
 95                 stack.push(top);
 96                 break;
 97             } else {
 98                 // 确定取出来的操作符的类型
 99                 int topType = 0;
100                 if (top.equals("+") || top.equals("-")) {
101                     // 类型为加减
102                     topType = 1;
103                 } else {
104                     // 类型为乘除
105                     topType = 2;
106                 }
107                 // 与传过来的类型比较
108                 if (topType > type) {
109                     output.append(top);
110                 } else {
111                     stack.push(top);
112                     break;
113                 }
114             }
115         }
116         // 将传过来的操作符入栈
117         stack.push(operator);
118     }
119 }

测试:

1 @Test
2 public void fun1(){
3     // String input = "A+B-C";
4     String input = "A*(B+C)-D/(E+F)";
5     InfixToPostfix2 trans = new InfixToPostfix2(input);
6     String output = trans.doTransform();
7     System.out.println("----------------------");
8     System.out.println("后缀表达式为: " + output);
9 }

结果:

FOR        A        Stack {bottom-->top}:
FOR        *        Stack {bottom-->top}:
FOR        (        Stack {bottom-->top}: *
FOR        B        Stack {bottom-->top}: *    (
FOR        +        Stack {bottom-->top}: *    (
FOR        C        Stack {bottom-->top}: *    (    +
FOR        )        Stack {bottom-->top}: *    (    +
FOR        -        Stack {bottom-->top}: *
FOR        D        Stack {bottom-->top}: -
FOR        /        Stack {bottom-->top}: -
FOR        (        Stack {bottom-->top}: -    /
FOR        E        Stack {bottom-->top}: -    /    (
FOR        +        Stack {bottom-->top}: -    /    (
FOR        F        Stack {bottom-->top}: -    /    (    +
FOR        )        Stack {bottom-->top}: -    /    (    +
WHILE            Stack {bottom-->top}: -    /
WHILE            Stack {bottom-->top}: -
END                Stack {bottom-->top}:
----------------------
后缀表达式为: ABC+*DEF+/-


三:使用后缀表达式求算术值

需要注意的是:

  栈存的是操作数,和上面的相反

 1 public class ParsePostfix {
 2
 3     private Stack stack;
 4     private String input;
 5     private StringBuilder sb;
 6
 7     public ParsePostfix(String input) {
 8         this.input = input;
 9         stack = new Stack(input.length());
10         sb = new StringBuilder();
11     }
12
13     public int doParse(){
14         for (int i = 0; i < input.length(); i++) {
15             char c = input.charAt(i);
16             // 两种情况:
17             // 1. 传过来的是一个数字,直接压入栈
18             // 2. 传过来的是一个操作符,那就取两个栈内元素,进行算术处理,并将结果压入栈
19             if (c >= ‘0‘ && c <= ‘9‘) {
20                 // 直接压入栈,需要转成int,网上找的,-‘0‘ 即可
21                 stack.push(c - ‘0‘);
22             } else {
23                 int result = 0;
24                 // 取两个栈内元素,进行算术处理
25                 int num1 = (int) stack.pop();
26                 int num2 = (int) stack.pop();
27                 switch (c) {
28                     case ‘+‘:
29                         result = num2 + num1;
30                         break;
31                     case ‘-‘:
32                         result = num2 - num1;
33                         break;
34                     case ‘*‘:
35                         result = num2 * num1;
36                         break;
37                     case ‘/‘:
38                         result = num2 / num1;
39                         break;
40                 }
41                 stack.push(result);
42             }
43         }
44         int finalResult = (int) stack.pop();
45         return finalResult;
46     }
47 }

测试:

1 @Test
2 public void fun2(){
3     String input = "531-+";
4     ParsePostfix pp = new ParsePostfix(input);
5     int i = pp.doParse();
6     System.out.println(i);
7 }

结果:

7


四:两者结合测试

 1 public static void main(String[] args) {
 2     String input = "5+3-5*8/2";
 3     InfixToPostfix trans = new InfixToPostfix(input);
 4     String output = trans.doTransform();
 5     System.out.println("----------------------");
 6     System.out.println("后缀表达式为: " + output);
 7     System.out.println("----------------------");
 8     ParsePostfix pp = new ParsePostfix(output);
 9     int result = pp.doParse();
10     System.out.println("最终结果为: " + result);
11 }

结果:

FOR        5        Stack {bottom-->top}:
FOR        +        Stack {bottom-->top}:
FOR        3        Stack {bottom-->top}: +
FOR        -        Stack {bottom-->top}: +
FOR        5        Stack {bottom-->top}: +    -
FOR        *        Stack {bottom-->top}: +    -
FOR        8        Stack {bottom-->top}: +    -    *
FOR        /        Stack {bottom-->top}: +    -    *
FOR        2        Stack {bottom-->top}: +    -    *    /
WHILE              Stack {bottom-->top}: +    -    *    /
WHILE              Stack {bottom-->top}: +    -    *
WHILE              Stack {bottom-->top}: +    -
WHILE              Stack {bottom-->top}: +
END                 Stack {bottom-->top}:
----------------------
后缀表达式为: 53582/*-+
----------------------
最终结果为: -12


使用栈实现解析算术表达式

原文地址:https://www.cnblogs.com/shadowdoor/p/9221139.html

时间: 2024-11-06 15:03:10

使用栈实现解析算术表达式的相关文章

堆栈解析算术表达式

利用栈,解析算术表达式问题就立刻变得容易许多.给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式. 中缀表达式和后缀表达式中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4.后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-.这种表达式可以直接利用栈来求解. 运算符的优先级 优先级 运算符 1 括号() 2 负号- 3 乘方** 4 乘*,除/,求余% 5 加+,减- 6 小于<,小于等于<=,大于>,大于等

栈的应用—算术表达式求值

例三.算术表达式求值 1.问题描述 当一个算术表达式中含有多个运算符,且运算符的优先级不同的情况下,如何才能处理一个算术表达式????? 2.思路 首先我们要知道表达式分为三类:  ①中缀表达式:a+(b-c/d)*e ②前缀表达式+a*-be ③后缀表达式abcd/-e*+ 由于运算符有优先级,所以在计算机中计算一个中缀的表达式非常困难,特别是带括号的更麻烦,而后缀表达式中既无运算符优先又无括号的约束问题因为在后缀表达式中运算符出现的顺序正是计算的顺序,所以计算一个后缀的表达式更简单.所以,可

数据结构之 栈和队列---算术表达式的转换(前缀+中缀+后缀)

算术表达式的转换 Time Limit: 1000MS Memory limit: 65536K 题目描述 小明在学习了数据结构之后,突然想起了以前没有解决的算术表达式转化成后缀式的问题,今天他想解决一下. 因为有了数据结构的基础小明很快就解出了这个问题,但是他突然想到怎么求出算术表达式的前缀式和中缀式呢?小明很困惑.聪明的你帮他解决吧. 输入 输入一算术表达式,以\'#\'字符作为结束标志.(数据保证无空格,只有一组输入) 输出 输出该表达式转换所得到的前缀式 中缀式 后缀式.分三行输出,顺序

栈的应用 算术表达式求值 学习笔记

//SeqStack.h typedef struct stack { DATA data[SIZE+1];  //数据元素  int top;  //栈顶  }SeqStack; SeqStack *SeqStackInit() { SeqStack *p; if(p=(SeqStack *)(malloc)(sizeof(SeqStack)))  //申请栈内存  { p->top = 0; //设置栈顶为零  return p; //返回指向栈的指针  } return NULL; } i

数据结构 栈解析 算法表达式

1 本文目标分析用堆栈解析算术表达式的基本方法.给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式. 2 中缀表达式和后缀表达式 中缀表达式就是通常所说的算术表达式,比如(1+2)*3-4. 后缀表达式是指通过解析后,运算符在运算数之后的表达式,比如上式解析成后缀表达式就是12+3*4-.这种表达式可以直接利用栈来求解. 3 运算符的优先级 优先级 运算符 1 括号() 2 负号- 3 乘方** 4 乘*,除/,求余% 5 加+,减- 6 小于<,小于等于<=,大于&

算术表达式解析(第三版)词法分析版

以前写过两版算术表达式解析代码,但都是基于栈结构或者树模型的,并不是通用的算法.其实算术表达式解析是最基本的词法分析算法,直到我看了<自制编程语言>里面介绍的递归向下分析法,才明白这种问题的终极解决方案是使用词法分析和语法分析.. //用于词法定界的头文件 token.h 1 #ifndef _TOKEN_H_VERSION_20140930 2 #define _TOKEN_H_VERSION_20140930 3 4 enum TokenKind{ 5 BAD_TOKEN, 6 NUMBE

双栈计算算术表达式

1.介绍 算术表达式的计算,是比较常见的问题,但这个问题的背后隐藏着栈的思想. 这里就介绍使用两个栈来计算表达式的方法. 2. 算法 2.1 定义: a) 建立两个栈: 一个是数据栈dataStak,用于存放数据: 一个是符号栈operatorStack,用于存放运算符: b) 建立运算符号之间的优先级表,用于比较两个符号之间的优先级: 优先级定义为三种运算结果:>(表示高于),<(表示低于),=(表示相等): 并且对于"("与")",认为两者的优先级相

SDUTOJ 2484 算术表达式的转换(栈)

算术表达式的转换 Time Limit: 1000MS Memory limit: 65536K 题目描述 小明在学习了数据结构之后,突然想起了以前没有解决的算术表达式转化成后缀式的问题,今天他想解决一下. 因为有了数据结构的基础小明很快就解出了这个问题,但是他突然想到怎么求出算术表达式的前缀式和中缀式呢?小明很困惑.聪明的你帮他解决吧. 输入 输入一算术表达式,以\'#\'字符作为结束标志.(数据保证无空格,只有一组输入) 输出 输出该表达式转换所得到的前缀式 中缀式 后缀式.分三行输出,顺序

运用栈把算术表达式+,-,*,/,%(中缀表达式)转换成后缀表达式并且计算出值

原理: 1.首先判断是数值还是符号,如果是数值放进字符数组以#表示结束, 2.如果是符号,放进栈, 3.每个符号之间要比较优先级,如果栈顶符号优先级低,符号进栈,如果相等(即“(” “)”)出栈,栈顶符号优先级高,栈顶元素出栈进入字符数组,得到后缀表达式 4.计算后缀表达式,判断是数字还是符号.直到遇到符号,将前面的数字计算后放进栈,一直重复,知道“\0” 代码(局限用整数,因为有模运算,若要任何类型的代码,我的blog有) 1 #include <stdio.h> 2 #include &l