结对作业

结对作业

这个作业属于哪个课程 班级链接
这个作业要求在哪里 作业要求
这个作业的目标 结对编程完成四则运算生成器
Github地址 3119005419
项目成员1 黎余明 3119005419
项目成员2 刘 煜 3119005424

1. PSP表格

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

2.效能分析

  • 全部性能分析如下



3.设计实现过程

大致的过程是:
首先封装一个计算的工具类包括加减乘除,还包括一些分子分母的构建,之后在来一个可以解析并计算四则运算表达式(含括号),返回计算结果,其中要用到IO流就是读写文件。

4.代码说明

项目关键代码及其注释说明(其实就是注释,写注释好累)
public String calculate(String numStr) {
        numStr = removeStrSpace(numStr); // 去除空格
        // 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
        if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
            numStr += "=";
        }
        // 检查表达式是否合法
        if (!isStandard(numStr)) {
            System.err.println("错误:算术表达式有误!");
            return "0";
        }
        // 初始化栈
        numberStack = new Stack<String>();
        symbolStack = new Stack<Character>();
        // 用于缓存数字,因为数字可能是多位的
        StringBuffer temp = new StringBuffer();
        // 从表达式的第一个字符开始处理
        for (int i = 0; i < numStr.length(); i++) {
            char ch = numStr.charAt(i); // 获取一个字符
            if (isNumber(ch) || ch == '/') { // 若当前字符是数字
                temp.append(ch); // 加入到数字缓存中
            } else { // 非数字的情况
                String tempStr = temp.toString(); // 将数字缓存转为字符串
                if (!tempStr.isEmpty()) {
                    //long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
                    numberStack.push(tempStr); // 将数字压栈
                    temp = new StringBuffer(); // 重置数字缓存
                }
                // 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
                //comparePri(ch)比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
                while (!comparePri(ch) && !symbolStack.empty()) {
                    String a = numberStack.pop(); // 出栈,取出数字,后进先出
                    String b = numberStack.pop();
  • 注意在算数时符号是有优先级的
 // 符号优先级说明(从高到低):
        // 第1级: (
        // 第2级: * ÷
        // 第3级: + -
        // 第4级: )

        char top = symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
        if (top == '(') {
            return true;
        }
        // 比较优先级
        switch (symbol) {
            case '(': // 优先级最高
                return true;
            case '*': {
                if (top == '+' || top == '-') // 优先级比+和-高
                    return true;
                else
                    return false;
            }
            case '÷': {
                if (top == '+' || top == '-') // 优先级比+和-高
                    return true;
                else
                    return false;
            }
            case '+':
                return false;
            case '-':
                return false;
            case ')': // 优先级最低
                return false;
            case '=': // 结束符
                return false;
            default:
                break;
        }
        return true;
    }
  • 检查算术表达式的基本合法性,符合返回true,否则false
private boolean isStandard(String numStr) {
        if (numStr == null || numStr.isEmpty()) // 表达式不能为空
            return false;
        Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
        boolean b = false; // 用来标记'='符号是否存在多个
        for (int i = 0; i < numStr.length(); i++) {
            char n = numStr.charAt(i);
            // 判断字符是否合法
            if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
                    || "+".equals(n + "") || "-".equals(n + "")
                    || "*".equals(n + "") || "÷".equals(n + "") || "/".equals(n + "")
                    || "=".equals(n + ""))) {
                return false;
            }
            // 将左括号压栈,用来给后面的右括号进行匹配
            if ("(".equals(n + "")) {
                stack.push(n);
            }
            if (")".equals(n + "")) { // 匹配括号
                if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
                    return false;
            }
            // 检查是否有多个'='号
            if ("=".equals(n + "")) {
                if (b)
                    return false;
                b = true;
            }
        }
        // 可能会有缺少右括号的情况
        if (!stack.isEmpty())
            return false;
        // 检查'='号是否不在末尾
        if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
            return false;
        return true;
    }
LinkedHashMap<Integer, String> rightAnswerMap = new LinkedHashMap<Integer, String>();
		LinkedHashMap<Integer, String> exerciseMap = new LinkedHashMap<Integer, String>();
		ArrayList<Integer> rightRecord = new ArrayList<Integer>();
		ArrayList<Integer> wrongRecord = new ArrayList<Integer>();
		CreateExercise ce = new CreateExercise();
		SavaTotxt save = new SavaTotxt();
		ce.setMax_num(max_num);
		for (int i = 1; i <= problems_num; i++) {
			String problem = ce.create();
			exerciseMap.put(i, problem);
			// int i=1;String problem="(2/5-9)/10÷8";
			String ns = problem;// 必要时,修改随机生成的题目的符号方便计算;problem是原始随机生的题目,这是要显示的
			int rightbrackets;// 题目中右括号位置
			int leftbrackets;// 题目中左括号位置
			if (problem.contains(")")) {
				// 因为题目把a/b当成一个数会压入栈,这两个if语句解决随机生成的题目出现(a+b)/c,
				// 会先计算a+b=v,然后把v压入栈,再继续执行程序的时候会把/c当成一个数压入栈,再往后计算会出问题
				rightbrackets = problem.indexOf(")");
				leftbrackets = problem.indexOf("(");
				if (rightbrackets != problem.length() - 1 && problem.charAt(rightbrackets + 1) == '/') {
					StringBuilder sb = new StringBuilder(problem);
					if (leftbrackets - 1 > 0 && problem.charAt(leftbrackets - 1) == '÷')// 这个解决括号前面是÷号要变号
						sb.replace(rightbrackets + 1, rightbrackets + 2, "*");
					else
						sb.replace(rightbrackets + 1, rightbrackets + 2, "÷");
					ns = sb.toString();

5.测试运行

这次项目使用的仅仅是数值上的运算,运算符与数字都随机生成,出错的概率在现如今计算机的体系结构以及算力的基础上应该是非常小的。

我们对题目设计了一个是否做答的选项,可供使用者进行选择,如果使用者选择y(yes)则立即作答,得到的答题结果会存在Grade_date文件里面,并且明确了哪题是正确的,哪题是错误的;选择n(no)则只产生题目,这些题目可以保存下来,当然答案也会一并保存,这样的话就可以由使用者在线下打印出来做题,然后依照答案进行批改。




6.项目小结

成员刘煜小结:和余明同学结对编程是很开心的事情,我其实是惰性比较强的人,但是有他在旁边push,感觉项目整体进展还是比较顺利的,我的java学的不是很扎实,很多地方还是请教了他才得到答案,这种亦师亦友的伙伴使整体进展都有按部就班再走,虽然最后比预计时间超出了不少,但项目完成了还是给予我俩信心和满足感。
成员黎余明小结: 在这次合作中,刘煜同学主动找到我,希望与我共同进行一次java开发,我本身有过一定python开发的经验,对于java开发知识只在以前稍作了解,但因为刘煜同学对于python语言不是很熟悉,所以我们最终决定用java来完成这次项目,首先是计划方面,看了很多师兄的实现方法,最终和刘同学敲定了方案就开始干,基本是我做两天他做两天,然后互相汇报进度,刘煜同学提出可以试一下使用java的一些工具类,于是在这次的项目中也尝试了使用一些java的工具类,本来还想写一个简单地界面,但是时间已经不太够了于是就只好作罢,在项目合作中,最有趣的是审计对方的代码,错误有时候真是千奇百怪哈哈哈。
posted @ 2021-10-26 00:30  5424刘煜  阅读(38)  评论(0编辑  收藏  举报