2016012101小学四则运算练习软件项目报告
Coding.net源码仓库地址:https://git.coding.net/naiteu/sgwq.git
一、需求分析
1,程序可以接收一个参数n,然后随机生成n道小学四则运算题
2,每个数字都必须在0~100以内
3,每个运算式必须包括3~5个运算符并且至少有两种运算符
4,运算式在运算过程中不能出现小数以及负数
5,将学号以及输出的n道运算题包括答案一起输出到result.txt文件中
二、功能设计
先建立两个数组,一个存放运算符一个存放数字。运算符数组的个数为随机生成3~5,数字数组的个数则比它多一个。
运用随机函数将两个数组赋值,并生成合理的运算式,并储存到字符串中。
判定该运算式的运算过程中是否出现小数以及负数。
若不出现则该运算式可用,输出运算式以及结果。
三、设计实现
该程序的重点以及难点就是判断随机运算式是否为可用运算式,在查阅的一定的资料后,我先把运算式转化为逆波兰表达式,然后在计算逆波兰表达式的过程中来判断减号运算是否出现负数以及除法运算是否出现小数。
我一共设计了四个类。1,生成运算式,若运算式合理则输出到文件的Suijishuzi类
2,将运算式转化为逆波兰表达式的StringToArithmetic类
3,计算逆波兰表达式并判断运算式是否合理的Calculate类
4,接收数字若合理则调用Suijishuzi类的Main类
四、算法详解
我先把四个运算符的优先级定义,然后再建立一个栈
1、遇到操作数:直接输出(添加到后缀表达式中)
2、栈为空时,遇到运算符,直接入栈
3、遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
4、最终将栈中的元素依次出栈
但是在得到逆波兰表达式后我发现计算它总是会出错,后来分析才发现是转化的逆波兰表达式是一个字符串,而运算式中有很多两位数字,导致Calculate类不能正确断数字。思考了很久后我在StringToArithmetic类的方法中加了一些小东西。具体就是在运算符进栈和出栈时输出”.”。然后再将得到的带”.”的字符串按”.”给断成字符数组。然后计算就没有问题了。
五、测试运行
输入数字
得到结果
六、代码展示
以下为中缀表达式转逆波兰表达式的代码
1 public StringToArithmetic() { 2 3 } 4 5 // 将中缀表达式转换为后缀表达式 6 public static String infixToSuffix(String exp) { 7 8 // 创建操作符堆栈 9 Stack<Character> s = new Stack<Character>(); 10 // 要输出的后缀表达式字符串 11 String suffix = ""; 12 int length = exp.length(); // 输入的中缀表达式的长度 13 for (int i = 0; i < length; i++) { 14 char temp;// 临时字符变量 15 // 获取该中缀表达式的每一个字符并进行判断 16 char ch = exp.charAt(i); 17 switch (ch) { 18 // 忽略空格 19 case ' ': 20 21 break; 22 // 如果是左括号直接压入堆栈 23 case '(': 24 s.push(ch); 25 break; 26 27 // 碰到'+' '-',将栈中的所有运算符全部弹出去,直至碰到左括号为止,输出到队列中去 28 case '+': 29 case '-': 30 suffix+="."; 31 while (s.size() != 0) { 32 temp = s.pop(); 33 if (temp == '(') { 34 // 重新将左括号放回堆栈,终止循环 35 s.push('('); 36 37 break; 38 } 39 40 suffix += temp; suffix +="."; 41 42 } 43 // 没有进入循环说明是当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈 44 s.push(ch); 45 46 break; 47 48 // 如果是乘号或者除号,则弹出所有序列,直到碰到加好、减号、左括号为止,最后将该操作符压入堆栈 49 case '*': 50 case '/': 51 suffix+="."; 52 while (s.size() != 0) { 53 temp = s.pop(); 54 // 只有比当前优先级高的或者相等的才会弹出到输出队列,遇到加减左括号,直接停止当前循环 55 if (temp == '+' || temp == '-' || temp == '(') { 56 s.push(temp); 57 break; 58 } else { 59 suffix += temp; suffix +="."; 60 61 62 } 63 } 64 // 没有进入循环说明是当前为第一次进入或者其他前面运算都有括号等情况导致栈已经为空,此时需要将符号进栈 65 s.push(ch); 66 67 break; 68 69 // 如果碰到的是右括号,则距离栈顶的第一个左括号上面的所有运算符弹出栈并抛弃左括号 70 case ')': 71 // 这里假设一定会遇到左括号了,此为自己改进版,已经验证可以过 72 // while ((temp = s.pop()) != '(') { 73 // suffix += temp; 74 // } 75 while (!s.isEmpty()) { 76 temp = s.pop(); 77 if (temp == '(') { 78 break; 79 } else { 80 suffix += temp; 81 } 82 } 83 break; 84 // 默认情况,如果读取到的是数字,则直接送至输出序列 85 default: 86 suffix += ch; 87 break; 88 } 89 90 } 91 // 如果堆栈不为空,则把剩余运算符一次弹出,送至输出序列 92 while (s.size() != 0) { 93 suffix+="."; 94 suffix += s.pop(); 95 } 96 // 97 98 return suffix; 99 100 }
七、展示psp
PSP2.1 | 任务内容 | 计划共完成需要的时间(min) | 实际完成需要的时间(min) |
Planning | 计划 | 20 | 40 |
· Estimate | · 估计这个任务需要多少时间,并规划大致工作步骤 | 10 | 15 |
Development | 开发 | 15*60 | 23*60 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 40 |
· Design Spec | · 生成设计文档 | 15 | 23 |
· Design Review | · 设计复审 (和同事审核设计文档) | 6 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 3 |
· Design | · 具体设计 | 15 | 25 |
· Coding | · 具体编码 | 12 | 18 |
· Code Review | · 代码复审 | 5 | 9 |
· Test | · 测试(自我测试,修改代码,提交修改) | 15 | 30 |
Reporting | 报告 | 10 | 20 |
· Test Report | · 测试报告 | 3 | 3 |
· Size Measurement | · 计算工作量 | 2 | 1 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 3 | 3
|
八、总结
其实总结我更想谈谈自己这次作业的感受。开始觉得这个作业好像没什么难度。然后仔细分析后发现对我来说没有那么简单。细想还是自己太水了,代码能了太弱了。比如关键的逆波兰表达式的转化以及其运算,虽然之前数据结构里有学过,但是要自己用代码写出来就真的写不出来。然后还是从网上找了代码看了一遍又一遍才把它弄懂。而且在敲一些基础代码时也总会出错,尽管感觉这些很简单,自己都会。测试时问题也是层出不穷,自己又把代码改了一次又一次。我前几天开始尝试做了一点,但是昨天真的是一天都在写这个作业,吃饭和看手机的时间都没超过一个半小时。昨天凌晨把作业大体都完成以后感觉很累,但也很开心。突然想到银魂中的一句话,“我光是活着就已经竭尽全力了。”因为光是完成基本功能就已经让我很吃力了。 不过我原来也不知道自己可以把这次作业完成,也许就像老师说的,有时候就要逼一下自己。