zoukankan      html  css  js  c++  java
  • WUSTOJ 1208: 计算整数四则运算表达式的结果(Java)

    1208: 计算整数四则运算表达式的结果

    参考资料

    数据结构(C语言版)严蔚敏 吴伟民 编著————表达式求值

    题目

      简单四则运算。更多内容点击标题。

    1. 保证表达式合法。
    2. 运算符只包含:加(+),减(-),乘(*),除(/)。
    3. 以等号(=)结束。

    提示

    1. 表达式只包含:数字字符,加,减,乘,除,等号这六种符号。
    2. 测试数据不存在分母为0的情况,代码中不用考虑。
    3. 全部为int型,不存在浮点型,也就是说:3/2=15/2=2
    4. 切记,虽然题目没说多组输入,但是测试数据有很多(我被被坑了)。
    5. 操作数可能不止一位,例如:10+8=

    测试数据(不像OJ的Simple Input跟没有一样QAQ)

    输入
    -5/2+0+1*3+14=
    520=
    
    输出
    15
    520
    

    这两组数据对了,你可以直接提交了,肯定对。

    分析

      这道题目很明显是在考察的运用,不知道栈是什么的,自己参考其他资料。这里只讲题目思路。
      有这本书的可以看看书(应该能看懂),没有的话,我就稍微啰嗦一下。

      四则运算规则不需要我说吧。下面是这道题目的运算关系表:

      这里要用到两个栈(Stack),分别是运算数栈(opnd)运算符栈(optr)。分别保存运算符和运算数。代码声明如下:
    /**
     1. @Field optr 运算符栈
     */
    private Stack<Character> optr;
    /**
     2. @Field opnd 运算数栈
     */
    private Stack<Integer> opnd;
    

      算法思想:

    1. 表达式最后一个字符是’=’,因此将运算符栈栈底置为’=’
    2. 依次读取表达式中的每个字符,如果是数字字符,则将这个操作数进opnd栈,如果是运算符,则和optr栈顶运算符比较优先级后进行操作。
    3. 直到计算结束(optr栈顶和当前字符都为’='说明计算结束)。

      测试数据 1 运算过程如下:

    步骤 optr(运算符栈) opnd(运算数栈) 剩余字符 主要操作
    1 = -5/2+0+1*3+14= opnd.push(0)
    2 = 0 -5/2+0+1*3+14= optr.push(’-’)
    3 = - 0 5/2+0+1*3+14= opnd.push(5)
    4 = - 0 5 /2+0+1*3+14= optr.push(’/’)
    5 = - / 0 5 2+0+1*3+14= opnd.push(2)
    6 = - / 0 5 2 +0+1*3+14= opnd.push(calculate(5,’/’,2))
    7 = - 0 2 +0+1*3+14= opnd.push(calculate(0,’-’,2))
    8 = -2 +0+1*3+14= optr.push(’+’)
    9 = + -2 0+1*3+14= opnd.push(0)
    10 = + -2 0 +1*3+14= opnd.push(calculate(-2,’+’,0))
    11 = -2 +1*3+14= optr.push(’+’)
    12 = + -2 1*3+14= opnd.push(1)
    13 = + -2 1 *3+14= optr.push(’*’)
    14 = + * -2 1 3+14= opnd.push(3)
    15 = + * -2 1 3 +14= opnd.push(calculate(1,’*’,3))
    16 = + -2 3 +14= opnd.push(calculate(-2,’+’,3))
    17 = 1 +14= optr.push(’+’)
    18 = + 1 14= opnd.push(14)
    19 = + 1 14 = opnd.push(calculate(1,’+’,14))
    20 = 15 = Output(opnd.peek())

      【备注】手打不易,且看且珍惜。
      【说明】1、左边是栈底,右边是栈顶。2、剩余字符中的加粗字符(也就是最左边的字符)表示正在读取的字符。3、optr.push()表示进运算符栈;opnd.push()表示进运算数栈;calculate()表示二元运算;opnd.peek()表示获取栈顶元素(Java的Stack类自带方法);Output()表示输出。4、第18步至19步没看懂的阅读代码的getInt()方法。

      下图为课本例题的过程图:

    代码

    /**
     * time 268ms
     * @author PengHao
     * @version A2.0
     * @date 2019-04-23 下午10:48:22
     */
    
    import java.util.Scanner;
    import java.util.Stack;
    
    public class Main {
    
    	private Scanner sc;
    	/**
    	 * @Field formal 算式
    	 */
    	private String formal;
    	/**
    	 * @Field optr 运算符栈
    	 */
    	private Stack<Character> optr;
    	/**
    	 * @Field opnd 运算数栈
    	 */
    	private Stack<Integer> opnd;
    	/**
    	 * @Field index 正在读取的式子中的字符的下标
    	 */
    	private int index;
    	
    	public Main() {
    		sc = new Scanner(System.in);
    		char temp; // 临时变量
    		while (sc.hasNext()) {
    			formal = sc.next(); // 式子
    			init(); // 初始化
    			temp = formal.charAt(index); // 获取当前字符
    			// 只有当前字符和运算符栈栈顶都是‘=’时,才退出循环,表示计算结束
    			while ('=' != temp || '=' != optr.peek()) {
    				if (Character.isDigit(temp)) { // 当前字符是数字
    					opnd.push(getInt()); // 将当前运算数入栈
    				} else { // 当前字符是运算符
    					if (0 == index) { // 这个字符是算式的第0个字符
    						opnd.push(0); // 将数字0入运算数栈栈顶
    					}
    					operate(); // 运算操作
    				}
    				temp = formal.charAt(index); // 获取算式的当前的字符
    			}
    			System.out.println(opnd.peek()); // 输出运算数栈栈顶(即算式结果)
    		}
    		sc.close();
    	}
    
    	/**
    	 * Initializes the properties of the class
    	 */
    	private void init() {
    		optr = new Stack<Character>();
    		opnd = new Stack<Integer>();
    		optr.push('='); // 初始运算符栈有一个‘=’
    		index = 0; // 第0个字符
    	}
    
    	/**
    	 * @return 式子中当前需要输入的运算数
    	 */
    	private int getInt() {
    		int num = 0, n;
    		char temp;
    		do {
    			// char型转成int型,并且下标向后移动一位
    			n = formal.charAt(index++) - '0';
    			num = num * 10 + n; // 转成运算数
    			temp = formal.charAt(index); // 获取当前字符
    		} while (Character.isDigit(temp)); // 当前字符是数字,则属于同一个运算数
    		return num;
    	}
    
    	/**
    	 * Arithmetic operations
    	 */
    	private void operate() {
    		int num1, num2; // 需要计算的两个运算数
    		char op; // 需要计算的运算符
    		char a = optr.peek(); // 运算符栈的栈顶运算符
    		char b = formal.charAt(index); // 算式的当前的运算符
    		if ('>' == priority(a, b)) { // 栈里面的运算符优先级较高
    			num2 = opnd.pop(); // 先出栈的是第二个运算数
    			op = optr.pop(); // 运算符
    			num1 = opnd.pop(); // 后出栈的是第一运算数
    			opnd.push(calculate(num1, op, num2)); // 运算结果入运算数栈
    		} else { // 当前运算符优先级较高
    			optr.push(b); // 当前运算符入运算符栈
    			index++; // 算式下标后移一位
    		}
    	}
    
    	/**
    	 * @param a 第一个运算符
    	 * @param b 第二个运算符
    	 * @return > 如果 <b>a</b> 的优先级高于 <b>b</b> 的优先级</br>
    	 *         < 如果 <b>a</b> 的优先级低于 <b>b</b> 的优先级
    	 */
    	private char priority(char a, char b) {
    		if ('*' == a || '/' == a) { // a运算符优先级最高
    			return '>';
    		}
    		if ('*' == b || '/' == b) { // b运算符优先级最高
    			return '<';
    		}
    		if ('=' == a) { // a是‘=’,优先级肯定是最低的
    			return '<';
    		}
    		return '>'; // 从左到右运算顺序,a优先级高于b(a在b左边)
    	}
    
    	/**
    	 * @param num1 第一个运算数
    	 * @param op   两个运算数之间的运算符
    	 * @param num2 第二个运算数
    	 * @return num1 op num2 的运算结果
    	 */
    	private int calculate(int num1, char op, int num2) {
    		switch (op) {
    		case '+':
    			return num1 + num2;
    		case '-':
    			return num1 - num2;
    		case '*':
    			return num1 * num2;
    		case '/':
    			return num1 / num2;
    		default:
    			return 0;
    		}
    	}
    
    	public static void main(String[] args) {
    		new Main();
    	}
    
    }
    

    写在最后:

    1. 如需转载,请于首页至少注明链接形式的wowpH的博客这几个字;
    2. 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
    3. 如果有疑问欢迎评论留言,尽量解答。

  • 相关阅读:
    数据库事务查看
    在SQL中删除重复记录(多种方法)
    OO设计原则
    NHibernate开源框架Cuyahoga学习之权限映射
    链队列的实现
    二叉树的实现
    NHibernate.cfg.xml文件配置
    HQL查询实例
    对象枚举遍历实现二
    NHibernate开源框架Cuyahoga学习之数据访问泛型约束的实现
  • 原文地址:https://www.cnblogs.com/wowpH/p/11060810.html
Copyright © 2011-2022 走看看