作业MathExamV2.0

MathExam233

211614269 林凯 211601233张康凌

一、预估与实际

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
• Estimate• 估计这个任务需要多少时间2030
Development开发
• Analysis• 需求分析 (包括学习新技术)60240
• Design Spec• 生成设计文档2040
• Design Review• 设计复审55
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)1010
• Design• 具体设计2040
• Coding• 具体编码120990
• Code Review• 代码复审3020
• Test• 测试(自我测试,修改代码,提交修改)60300
Reporting报告
• Test Repor• 测试报告6070
• Size Measurement• 计算工作量55
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划1010
合计4501800

二、需求分析

我通过上网调查的方式了解到,这次任务有如下的几个特点:

  1. 小学一年级
    • 使用的数字必须小于100
    • 减法方面得出的结果必须为正整数
      2.小学二年级
    • 在乘法方面两个数满足乘法口诀表,小于10
    • 在除法方面,被除数小于90,商和除数还有余数必须为个位数。
    • 乘除法得出的结果为正数
  2. 小学三年级
    • 运算符在2~4个
    • 可以加括号
    • 减法运算的结果不能出现负数
    • 除法运算 必须为整除 而且除数不能为0

三、设计

1. 设计思路

1472619-20180919224932301-695773735.png

  • 这个程序有两个类
    • 主函数负责判断传入参数是否合法,并根据相应参数调用相应方法
    • calculate类专门用来计算表达式的结果
  • 算法的关键是什么?
  • 调度场算法
    • 定义两个栈,一个栈叫做保存运算符记为op,另一个栈保存最终的表达式记为rpn。
    • 数字直接入op栈
    • op栈顶若是(则无条件入栈
    • 运算符要与op栈顶比较,优先级大则入栈,小于或等于则op出栈后再入栈
  • 逆波兰式求值
    • 定义一个栈
    • 从左到右扫描逆波兰式
    • 读到一个数字时就将它压入栈中
    • 读到一个运算符时,就从栈中弹出两个数字,并将该运算符作用于这两个数字,然后将计算结果再压入栈中
    • 逆波兰式读取完毕时,栈中剩下的就是最终结果
  • 生成合适的随机数
    • (int) (min + Math.random() * (max - min + 1)) 可生成min-max范围内的数;

2. 实现方案

- 准备工作:先在github上创建仓库,克隆到本地。
- 重要关键点:逆波兰式的理解以及应用

四、编码

1. 调试日志

-在代码的什么位置,代码出现了什么问题,问题会导致什么结果,怎么解决的
-在使用调度场算法将题目转换成逆波兰式时出现了问题,因为题目的数字可能是个位也可能是两位,直接通过下标截取字符串的方法明显不合适。最后我决定写一个方法,将题目中的符号及数值按顺序存放至字符串数组中,使用的时候遍历数组取出即可。
-在出题时,有可能出现除法有余数的情况,导致题目不符合要求。我的做法是在生成除号时,将前一个被除数取出,同时随机出被除数,若不能整除,则一直循环随机出被除数,最后一定能保证不会有余数。

2. 关键代码

public class Calculate {
    // 构造方法传入题目

    public static int ans(String str) {
        // TODO Auto-generated constructor stub
        squestion = str;
        cutStr();
        reversePolishNotation();
        return compute();
    }

    // 题目的字符串
    public static int slen;
    public static String[] scut = new String[100];
    public static String squestion;
    // 存操作符的栈
    public static Stack<String> soperators = new Stack<>();
    // 存放转换后的逆波兰式
    public static Stack<String> srpn = new Stack<>();
    // 用于调换逆波兰式的顺序
    public static Stack<String> srpnb = new Stack<>();
    // 计算逆波兰式用的栈
    public static Stack<String> cal = new Stack<>();

    public static boolean isNum(String str) {
        for (int i = 0; i < str.length(); i++) {
            if (!Character.isDigit(str.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    // 将字符串的题目切割成数值和符号
    public static void cutStr() {
        int n = 0;
        String str=squestion.replaceAll(" ", "");
        squestion=str;
        for (int i = 0; i < squestion.length(); i++) {
            if (Character.isDigit(squestion.charAt(i))) {
                if ((i + 1) < squestion.length() && Character.isDigit(squestion.charAt(i + 1))) {
                    int num = (squestion.charAt(i) - '0') * 10 + (squestion.charAt(i + 1) - '0');
                    scut[n] = String.valueOf(num);
                    n++;
                    i++;
                } else if (squestion.charAt(i) == ' ') {
                } else {
                    int num = squestion.charAt(i) - '0';
                    scut[n] = String.valueOf(num);
                    n++;
                }
            } else {
                scut[n] = String.valueOf(squestion.charAt(i));
                n++;
            }
        }
        slen = n;
    }

    public static int priority(String str) {
        switch (str) {
        case "(":
            return 0;
        case "+":
        case "-":
            return 1;
        case "*":
        case "/":
            return 2;
        default:
            return -1;
        }

    }

    // 转换成逆波兰式
    public static void reversePolishNotation() {

        for (int i = 0; i < slen; i++) {
            if (!(scut[i].equals("+") || scut[i].equals("-") || scut[i].equals("*") || scut[i].equals("/") || scut[i].equals("(") ||  scut[i].equals(")"))) {
                srpn.push(scut[i]);
            } else {
                if (soperators.isEmpty() || scut[i].equals("(")) {
                    soperators.push(scut[i]);
                } else {
                    if (priority(scut[i]) > priority(soperators.peek())) {
                        soperators.push(scut[i]);
                    } else {
                        if(scut[i].equals(")")) {
                            while (!soperators.peek().equals("(")) {
                                srpn.push(soperators.pop());
                            }
                            soperators.pop();
                        }else {
                            while ((!soperators.isEmpty()) && (priority(soperators.peek()) >= priority(scut[i]))) {
                                srpn.push(soperators.pop());
                            }
                            soperators.push(scut[i]);
                        }
                        
                    }
                }
            }
        }
        while (!soperators.isEmpty()) {
            srpn.push(soperators.pop());
        }
    }

    public static int compute() {
        // 倒换逆波兰式顺序
        while (!srpn.isEmpty()) {
            srpnb.push(srpn.pop());
        }

        while (!srpnb.isEmpty()) {
            if (srpnb.peek().equals("+") || srpnb.peek().equals("-") || srpnb.peek().equals("*")
                    || srpnb.peek().equals("/")) {
                String sym = srpnb.pop();
                int a = Integer.parseInt(cal.pop());
                int b = Integer.parseInt(cal.pop());
                if (sym.equals("+")) {
                    cal.push(String.valueOf(b + a));
                } else if (sym.equals("-")) {
                    cal.push(String.valueOf(b - a));
                } else if (sym.equals("*")) {
                    cal.push(String.valueOf(b * a));
                } else {
                    cal.push(String.valueOf(b / a));
                }

            } else {
                cal.push(srpnb.pop());
            }
        }
        return Integer.parseInt(cal.pop());

    }

}

3. 代码规范

请给出本次实验使用的代码规范:

  • 在for循环/do while/if等语句必须加括号以及字与括号间的空格
  • 在if里嵌套多个if 要对应好if 与else 防止出错
  • 一般情况下使用空格缩进
  • 在括号方面在结束的时候必须换行,左边大括号后面要换行,右边大括号换行
  • 不能使用未定义的变量
    1472619-20180919115923329-617407496.png

五、测试

测试输入输出是否符合预期效果
-n 100 -grade 1执行成功
-n 100 -grade 2执行成功
-n 100 -grade 3执行成功
-grade 1 -n 100执行成功
-grade 2 -n 100执行成功
-grade 3 -n 100执行成功
不输入任何参数输入错误
输入一个参数:20输入错误
-n 20输入错误

六、总结

这次的任务真的太难了,耗费的时间太多了。 很多内容都需要上网查找思路,经过这次的任务让我感到更加没有头绪 的怎么去面对去学习代码去适应,感觉自己还是需要更深的去理解和实践代码。
1472619-20180918232636030-36730898.jpg
1472619-20180918232700806-740609578.jpg

转载于:https://www.cnblogs.com/rickowens/p/9672106.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值