20165310java_teamExp1_week1
结对编程项目-四则运算-week1
需求分析
- 第一周达成
- 支持真分数的四则运算
- 支持多运算符
- 能手动输入n道题目,n由使用者输入
 
- 后续拓展的可能
- 能随机生成n道题目,n由使用者输入
- 能够判断正误,错误时能提醒并输出正确答案
- 能计算出正确率
- 能多次生成题目,直到使用者选择退出
- 题目去重
- 处理生成题目并输出到文件
- 完成题目后从文件读入并判题
- 多语言支持:简体中文,繁體中文,English
 
设计思路
- 将带括号的四则运算式的字符串转化为逆波兰式,具体思路在[2016-2017-2 《Java 程序设计》课堂实践项目]中有明确的说明:
1.设立一个栈,存放运算符,首先栈为空;
2.从左到右扫描中缀式,若遇到操作数,直接输出,并输出一个空格作为两个操作数的分隔符;
3.若遇到运算符,则与栈顶比较,比栈顶级别高则进栈,否则退出栈顶元素并输出,然后输出一个空格作分隔符;
4.若遇到左括号,进栈;若遇到右括号,则一直退栈输出,直到退到左括号止。
5.当栈变成空时,输出的结果即为后缀表达式。
根据上述思路,完成代码ChangeExpress.java,将前缀式改为后缀式,并且完成分析括号匹配的功能,若左右括号不匹配,输出错误并退出程序运行:
import java.util.*;
public class ChangeExpress{
    String originalExpression;
    String changedExpression= "";
    int countLeft=0,countRight=0;
    public void setOriginalExpression(String str){
        originalExpression=str;
    }
    public void changedWay(){
        Stack stackChange=new Stack();//创立栈
        int opValue []=new int[100];
        for (int i=0;i<originalExpression.length() ;i++) {
            char chi=originalExpression.charAt(i);
            if (chi>='0'&&chi<='9'){
                changedExpression=changedExpression+chi;
            }
            else if (chi=='+'||chi=='-'||chi=='*'||chi=='÷'||chi=='/') {
                changedExpression=changedExpression+" ";//有运算符,数字之间就要有空格,否则是一个整体
                if (stackChange.empty()){//栈为空直接压栈
                    stackChange.push(chi);
                }
                else if (judgeValue(chi)>=judgeValue((char)stackChange.peek())) {//运算级别高或者相等压入栈
                    stackChange.push(chi);
                }
                else{
                    changedExpression=changedExpression+ String.valueOf(stackChange.pop())+" ";//否则直接进入字符串,空格分割运算符
                    i--;
                }
            }
            else if(chi=='('){
                countLeft++;
                stackChange.push(chi);//左括号压栈
            }
            else if(chi==')'){
                changedExpression+=" ";
                countRight++;
                while((char)stackChange.peek()!='('){//直到(为止
                    changedExpression=changedExpression+ String.valueOf(stackChange.pop())+" ";//弹出栈内东西,空格分割
                }
                stackChange.pop();
            }
        }
        changedExpression+=" ";
        while(!stackChange.empty()){
            changedExpression=changedExpression+String.valueOf(stackChange.pop())+" ";
        }
    /*int size = stackChange.size();
    for (int i=0;i<size;i++){
        changedExpression=changedExpression+String.valueOf(stackChange.pop())+" ";
    }*/
        if (countLeft!=countRight) {
            System.out.println("括号不匹配");
            System.exit(0);
        }
    }
    public int judgeValue(char c){
        int value=0;
        switch(c){
            case '(':
                value=1;
                break;
            case '+':
            case '-':
                value=2;
                break;
            case '*':
            case '÷':
                value=3;
                break;
            case '/':
                value=4;
                break;
            case ')':
                value=5;
            default:
                value=0;
        }
        return value;
    }
}
- 进行后缀式计算:学习了[2016-2017-2 《Java 程序设计》课堂实践项目]之后,发现老师的参考代码MyDC.java,原理是:利用空格作为分隔符将后缀式表达的字符串进行分割,遇到操作数就压栈,遇到操作符就弹出栈顶的两位操作数进行运算,再将运行结果压栈,直到没有下一个分割好的字符串,输出结果:
import java.util.StringTokenizer;
import java.util.Stack;
public class MyDcRational
{
    /** constant for addition symbol */
    private final char ADD = '+';
    /** constant for subtraction symbol */
    private final char SUBTRACT = '-';
    /** constant for multiplication symbol */
    private final char MULTIPLY = '*';
    /** constant for division symbol */
    private final char DIVIDE1 = '÷';
    private  final char DIVIDE2='/';
    /** the stack */
    private Stack stack;//存放操作数的栈
    public MyDcRational()
    {
        stack = new Stack();
    }
    public Rational evaluate (String expr)
    {
        Rational op1=new Rational();
        Rational op2=new Rational();
        Rational result=new Rational();
        result.setNumerator(0);
        String token;
        StringTokenizer tokenizer = new StringTokenizer (expr);//划分表达式
        while (tokenizer.hasMoreTokens())
        {
            token = tokenizer.nextToken();//将算数表达式分解的
            if (isOperator(token))//见下方isOperateor方法,当是运算符的时候进入if语句
            {
                op2 = (Rational) stack.pop();
                op1 = (Rational)stack.pop();//弹出最上面两个操作数
                result = evalSingleOp (token.charAt(0), op1, op2);//见下方evaSingleOp方法
                stack.push (result);//将计算结果压栈
            }
            else{
                Rational num=new Rational();
                num.setNumerator(Integer.parseInt(token));//将操作数由string转变为Rational
                stack.push (num);//操作数入栈
            }
        }
        return result;//输出结果
    }
    private boolean isOperator (String token)//判断是否为运算符,注意用equal语句比较字符串
    {
        return ( token.equals("+") || token.equals("-") ||
                token.equals("*") || token.equals("÷")||token.equals("/"));
    }
    private Rational evalSingleOp (char operation, Rational op1, Rational op2)
    {
        Rational result=new Rational();
        result.setNumerator(0);
        switch (operation)
        {
            case ADD:
                result = op1.add(op2);
                break;
            case SUBTRACT:
                result = op1.sub(op2);
                break;
            case MULTIPLY:
                result = op1.muti(op2);
                break;
            case DIVIDE1:
            case DIVIDE2:
                result = op1.div(op2);
                break;
            default:
                System.out.println("Error!");
        }
        return result;
    }
}
- 最后编写主函数代码Calculation.java,实现功能有:运算式输入、运算、结果输出:
import java.util.*;
public class Calculation {
    public static void main(String[] args) {
        System.out.println("请输入要生成的题目数:");
        Scanner number = new Scanner(System.in);
        int n = number.nextInt();
        for (int i = 1; i <= n; i++) {
            System.out.println("题目" + i + ":");
            Scanner reader = new Scanner(System.in);
            Rational result = new Rational();
            String str = reader.nextLine();
            ChangeExpress change = new ChangeExpress();
            change.setOriginalExpression(str);
            //System.out.println(change.originalExpression);
            change.changedWay();//后缀式化
            //System.out.println(change.changedExpression);
            MyDcRational calculate = new MyDcRational();//后缀式计算
            result = calculate.evaluate(change.changedExpression);
            int a = result.getNumerator();
            int b = result.getDenominator();
            if (b == 1) {
                System.out.println("result=" + a);
            } else {
                System.out.println("result=" + a + "/" + b);
            }
        }
    }
}
UML截图

功能截图
示例结果:

运行结果:

重要代码注释
关键代码在设计思路模块已经解释了整体思路,并给出了具体代码,并且代码中给了注释。
测试截图
由于我们代码多为void类型,能够进行测试的代码并不多,下面为成功的测试截图
- 判断符号优先级
  
- 测试分数运算
  
遇到的困难及解决方法
- 由于上周的实验我正好做的是四则运算,相对其他组更加理解一些关于栈的原理,但是在上周的实验中,我没有将'÷'与'/'分开,统一将分数与除法都当做除法运算进行处理压栈,但是本周实验中,这两者被区分开,开始我只是在switch-case语句判断运算符优先级的时候将'÷'与'/'设置为一样,依旧试图将'÷'与'/'等价,但是我的小伙伴阎含在测试中发现,如下的式子将会报错:
 1/2÷5/8,如果按照我的思路,后缀式将是‘1 2 / 5 ÷ 8 /’,但实际的后缀式应该是:‘1 2 / 5 8 / ÷’,因此我重新定义了运算符优先级'/'比'÷'高一级,运算结果正确
- 由于上周的实验正好做的是四则运算是优势也是弊端,我们整体的设计要延续上周的思路进行设计,要进行思路的整理回忆和改编,所以我们这种更多进行了逻辑框架上的思考与搭建,例如如何设计语言类调用三种语言而不违背S.O.L.I.D原则中的SRP原则,如何生成带有括号的随机四则运算,如何进行去重,更多的具体实现将在下周进行。
对结对的小伙伴做出评价
我的结对小伙伴阎寒很细致耐心,我们可以进行深入探讨,在意见分歧或者时间紧促的时候的时候也能不骄不躁,是个很好的搭档。
PSP
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 
|---|---|---|---|
| Planning | 计划 | ||
| · Estimate | · 估计这个任务需要多少时间 | 30 | 40 | 
| Development | 开发 | ||
| ·Analysis | · 需求分析 (包括学习新技术) | 60 | 90 | 
| ·Design Spec | · 生成设计文档 | 30 | 40 | 
| ·Design Review | · 设计复审 (和同事审核设计文档) | 30 | 20 | 
| ·Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 | 
| ·Design | · 具体设计 | 120 | 160 | 
| · Coding | · 具体编码 | 150 | 180 | 
| ·Code Review | · 代码复审 | 40 | 60 | 
| ·Test | · 测试(自我测试,修改代码,提交修改) | 150 | 200 | 
| Reporting | 报告 | ||
| · Test Report | · 测试报告 | 60 | 90 | 
| · Size Measurement | · 计算工作量 | 20 | 20 | 
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 | 
| 合计 | 750 | 970 | 
代码托管地址
https://gitee.com/BESTI-IS-JAVA-2018/20165310exp/tree/master/expTeamWeek1
20165310java_teamExp1_week1的更多相关文章
随机推荐
- IDEA 配置环境和相关工具整理(新手入门)
			转载自:https://blog.csdn.net/moneyshi/article/details/79722360 因项目环境需要,开发工具需要统一 , 项目团队都使用idea,所以不得已自己也配 ... 
- WordPress 3.8 后台仪表盘将重新设计
			WordPress 3.8 的后台仪表盘界面将会重新设计 概况(RightNow) -> 改为网站内容(SiteContent) 快速发布(QuickPress) -> 改为快速草稿(Qu ... 
- Python模块:配置文件解析器configparser
			版权声明:本文为博主皮皮http://blog.csdn.net/pipisorry原创文章,未经博主同意不得转载. https://blog.csdn.net/pipisorry/article/d ... 
- 【剑指offer】斐波那契数列
			一.题目: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项.n<=39 二.思路: 式子: n=0时,f=0:n=1或者n=2时f=1:否则f=f(n-1)+f(n ... 
- <转>MySQL临时表的简单用法
			当工作在非常大的表上时,你可能偶尔需要运行很多查询获得一个大量数据的小的子集,不是对整个表运行这些查询,而是让MySQL每次找出所需的少数记录,将记录选择到一个临时表可能更快些,然后在这些表运行查询. ... 
- js 的each()方法遍历对象和数组
			<script src="../lib/jquery-1.8.3.min.js" ></script> <script type="text ... 
- [py]requests+json模块处理api数据,flask前台展示
			需要处理接口json数据,过滤字段,处理字段等. 一大波json数据来了 参考: https://stedolan.github.io/jq/tutorial/ https://api.github. ... 
- Bus System(Flody)
			http://acm.hdu.edu.cn/showproblem.php?pid=1690 坑爹的题,必须用__int64 %I64d(以前没用过) 因为这题的数据特别大,所以用-1 #includ ... 
- Python 之 os.walk()
			原文地址https://www.cnblogs.com/JetpropelledSnake/p/8982495.html http://www.runoob.com/python/o ... 
- Summary: difference between public, default, protected, and private key words
			According to Java Tutorial: Controlling Access to Members of a Class Access level modifiers determin ... 
