zoukankan      html  css  js  c++  java
  • 20162311 结对编程项目-四则运算 阶段总结

    20162311 结对编程项目-四则运算 阶段总结

    一、需求分析

    • 能随机生成n道题目,n由使用者输入
    • 支持整数的四则运算
    • 能够判断正误,错误时能提醒并输出正确答案
    • 能计算出正确率
    • 能多次生成题目,直到使用者选择退出

    后续拓展的可能

    • 支持真分数
    • 题目去重
    • 支持多运算符

    备注:这次只实现了单运算符,而且做整数除法时只能得到整数结果;如8 / 7结果为1。这周还没有解决这些问题,下周会继续学习并解决。

    二、设计思路

    Operand类用来生成两个10以内的随机数,作为操作数。设计一个IntQuestions类,其中实例化一个Operand对象,用来生成操作数,还包含四种方法,分别生成两个10以内随机整数的加、减、乘、除,这四种方法返回值都为String类型。还有一个Judgement类,用来判断输入的答案是否正确。NiToSuffix类是用来将中缀表达式转化为后缀表达式,运用了栈的方法。把生成的后缀表达式作为参数传入Judgement类中的evaluate()方法,从而判断结果是否正确。ResultTest是结果测试类,它依赖于之前的类,用于生成表达式,输出结果是否正确,输出正确率。

    UML类图

    三、实现过程中的关键代码

    • 中缀表达式转化为后缀表达式
    package Arithmetic;
    
    import java.util.*;
    
    
    /**
     * Created by Administrator on 2017/5/13.
     */
    public class NifixToSuffix {
        private Stack<String> stack;
        private List<String> list;
    
        private String message,Message="";
    
    
        public NifixToSuffix() {
            stack = new Stack<String>();
            list = new ArrayList<String>();
        }
    
        public void conversion(String expr) {
            int op1, op2, result = 0;
            String token;
            StringTokenizer tokenizer = new StringTokenizer(expr);
    
            while (tokenizer.hasMoreTokens()) {
                token = tokenizer.nextToken();
    
                if (token.equals("("))
                    stack.push(token);
                else if (token.equals("+") || token.equals("-")) {
                    if(!stack.empty()) {
                        if (stack.peek().equals("(")){
                            stack.push(token);
                        }
                 else if (stack.peek().equals("*") || stack.peek().equals("/"))
                            list.add(stack.pop());
                    }
                   else stack.push(token);
                }
                else if (token.equals("*") || token.equals("/")) {
                    if(!stack.empty()){
                        if(stack.peek().equals("*")||stack.peek().equals("/")) {
                            list.add(stack.pop());
                        }
                    }
                    stack.push(token);
                }
                else if (token.equals(")")) {
                    while (true) {
                        String A = stack.pop();
                        if (!A.equals( "("))
                            list.add(A);
                        else break;
                    }
                }
                else list.add(token);
            }
            while (!stack.empty()) {
                list.add(stack.pop());
            }
            ListIterator<String > li = list.listIterator();
            while (li.hasNext()) {
                Message += li.next() + " ";
                li.remove();
            }
            message = Message;
    
        }
    
        public String getMessage() {
            return message;
        }
    }
    
    

    转换规则

    • 设立一个栈和一个列表,栈存放运算符,列表存放操作数,栈和列表都为空。
    • 编译程序从左到右扫描原表达式,若遇到操作数,进入列表。
    • 若遇到运算符,与栈顶进行比较,比栈顶级别高则进栈,否则退出栈顶元素,将其加到列表中。
    • 若遇到左括号,进栈;若遇到右括号,则一直退栈输出到列表中,退到左括号为止。
    • 当栈变为空时,用迭代器将列表中的元素取出,每取出一个,都加一个空格作为分隔符,最后得到后缀表达式

    迭代代码如下

     ListIterator<String > li = list.listIterator();
     while (li.hasNext()) {
         Message += li.next() + " ";
         li.remove();
     }
    

    四、测试方法

    • NifixToSuffix类的方法的测试

    • Judgement类的方法测试

      • evaluate()方法
      • isOperator()方法

    五、运行过程截图

    六、代码托管地址

    七、遇到的困难及解决方法

    • 问题1

    如何计算表达式的值?

    • 解决方法

    老师之前布置过一个课堂练习,让我们计算后缀表达式的值。老师把代码框架给了我们,教我们用栈进行计算。我将之前的那部分代码复制过来,新建一个Judgement类,把实现计算过程的代码作为判断的方法,通过获取返回值与用户输入的答案进行比较

    package Arithmetic;
    
    /**
     * Created by Administrator on 2017/5/13.
     */
    import java.util.StringTokenizer;
    import java.util.Stack;
    
    public class Judgement
    {
        /* 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 DIVIDE = '/';
        /* the stack */
        private Stack<Integer> stack;
    
        public Judgement() {
            stack = new Stack<Integer>();
        }
    
        public int evaluate (String expr)
        {
            int op1, op2, result = 0;
            String token;
            StringTokenizer tokenizer = new StringTokenizer (expr);
    
            while (tokenizer.hasMoreTokens())
            {
                token = tokenizer.nextToken();
    
                //如果是运算符,调用isOperator
                if (isOperator(token))
                {
                    //从栈中弹出操作数2
                    op2 = stack.pop();
                    //从栈中弹出操作数1
                    op1 = stack.pop();
                    //根据运算符和两个操作数调用evalSingleOp计算result;
                    result = evalSingleOp(token.toCharArray()[0], op1, op2);
                    //计算result入栈;
                    result = stack.push(result);
                }
                else //如果是操作数
                    stack.push(Integer.parseInt(token));
                //操作数入栈;
            }
    
            return result;
        }
    
        public  boolean isOperator (String token)
        {
            return ( token.equals("+") || token.equals("-") ||
                    token.equals("*") || token.equals("/") );
        }
    
        private int evalSingleOp (char operation, int op1, int op2)
        {
            int result = 0;
    
            switch (operation)
            {
                case ADD:
                    result = op1 + op2;
                    break;
                case SUBTRACT:
                    result = op1 - op2;
                    break;
                case MULTIPLY:
                    result = op1 * op2;
                    break;
                case DIVIDE:
                    result = op1 / op2;
            }
    
            return result;
        }
    }
    
    
    
    • 问题2

    IntQuestions类生成的是中缀表达式,如何转化为后缀表达式呢?

    • 解决方法

    也是运用栈。老师上课时也讲过,但是不清楚具体怎么实施。问了学的比较好的张旭升同学,看了一下他的代码。代码截图在上面有,具体操作在实现过程中的关键代码这点里面讲了,这里就不重复了。

    八、对结对的小伙伴的评价

    与其说是结对编程,不如说是一个人编(搭档不给力)。坦白说,金立清同学之前学的不是很好,作为搭档,我也有责任,我没有起到监督作用。结对编程时基本上是我编,金立清同时也学习。金立清同学在经过我的讲解后,可以看懂代码,但是不会自己编。所以我觉得她最需要改进的就是把之前学的知识恶补一下,这样在以后的结对编程中才能有自己的想法,而不是只能看着我编,然后再讲解给她听。不过值得肯定的是她能认识到自己的不足,虚心学习,现在还来得及。

    九、参考或引用的设计、实现

    • 后缀表达式求值

    参考娄老师的mini dc课堂测试,这里是题目链接

     while (tokenizer.hasMoreTokens())
            {
                token = tokenizer.nextToken();
    
                //如果是运算符,调用isOperator
                if (isOperator(token))
                {
                    //从栈中弹出操作数2
                    op2 = stack.pop();
                    //从栈中弹出操作数1
                    op1 = stack.pop();
                    //根据运算符和两个操作数调用evalSingleOp计算result;
                    result = evalSingleOp(token.toCharArray()[0], op1, op2);
                    //计算result入栈;
                    result = stack.push(result);
                }
                else //如果是操作数
                    stack.push(Integer.parseInt(token));
                //操作数入栈;
            }
    

    这段代码老师只给了中文注释,是自己实现的,其余的框架是老师写好的

    • 中缀表达式转化成后缀表达式

    参考娄老师的栈的应用PPT,学习了转化的思路;还请教了张旭升同学,并参考引用了他的代码

    十、PSP

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划
    · Estimate · 估计这个任务需要多少时间 20 30
    Development 开发
    · Analysis · 需求分析 (包括学习新技术) 90 120
    · Design Spec · 生成设计文档 120 140
    · Design Review · 设计复审 (和同事审核设计文档) 30 25
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 30
    · Design · 具体设计 120 150
    · Coding · 具体编码 300 400
    · Code Review · 代码复审 60 50
    · Test · 测试(自我测试,修改代码,提交修改) 60 90
    Reporting 报告
    · Test Report · 测试报告 90 120
    · Size Measurement · 计算工作量 30 30
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 30
    合计 980 1215

    注:以上耗时均为本周耗时,下周完成后会有变动

    本周的预计和实际耗时相差较大,主要是没有认识到任务的难度(高估了自己,哎),对Java的一些类的运用还不够熟练,所以在问同学,查资料上花了很多时间,不过这也促进了我的学习,希望下周能合理预估时间,同时学习到更多。

  • 相关阅读:
    扑克牌顺子
    反转字符串
    左旋转字符串
    和为S的两个数
    C++中substr()详解
    STL库中的equal_range()
    和为S的连续正序列
    数组中只出现一次的数
    二叉树的深度
    mysql找安装路经,更改密码
  • 原文地址:https://www.cnblogs.com/-zzr-/p/6852085.html
Copyright © 2011-2022 走看看