项目成员:刘跃群(3116005189)、张凯亮(3116005205)
项目仓库:https://github.com/wean2016/Myapp
PSP2.1表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 45 |
· Estimate | · 估计这个任务需要多少时间 | 60 | 45 |
Development | 开发 | 1420 | 1985 |
· Analysis | · 需求分析 (包括学习新技术) | 100 | 200 |
· Design Spec | · 生成设计文档 | 20 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 100 | 100 |
· Design | · 具体设计 | 50 | 55 |
· Coding | · 具体编码 | 1000 | 1400 |
· Code Review | · 代码复审 | 100 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 30 |
Reporting | 报告 | 80 | 130 |
· Test Report | · 测试报告 | 30 | 32 |
· Size Measurement | · 计算工作量 | 20 | 21 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 77 |
合计 | 1560 | 2260 |
设计实现过程及代码说明
1. 生成表达式树
** * 构造表达式 * @param symbolSum 剩余符号数 * @param bound 表达式钟的数字不大于 bound * @return 生成的节点树的根 */ def createNodeTree(symbolSum:Int, bound:Int):Node = { if (symbolSum == 0){ // 中间节点构造完成,生成叶子节点 Node(Number.randomNumber(bound), null, null, 0, null) }else { val left = Random.nextInt(symbolSum) val right = symbolSum - left - 1 var leftNode = createNodeTree(left,bound) var rightNode = createNodeTree(right,bound) // 本节点的符号 var symbol = Symbol.values()(Random.nextInt(Symbol.values().length)) // 如果是除号且右节点是 0 ,那么重新生成一个不是除号的符号 if (symbol == Symbol.DIV && rightNode.value.a == 0){ while (symbol == Symbol.DIV){ symbol = Symbol.values()(Random.nextInt(Symbol.values().length)) } } // 本节点的结果 var value = Calculate.calc(leftNode.value,rightNode.value,symbol).get if (Number.isNeg(value)) { // 如果运算结果是负数,交换左右节点,并把结果取绝对值 value = Number.abs(value) val tempNode = leftNode leftNode = rightNode rightNode = tempNode } val high = math.max(leftNode.high, rightNode.high) + 1 // 生成本节点 Node(value,leftNode,rightNode,high,symbol) } }
2. 表达式树比较去重
override def equals(obj: Any): Boolean = obj match { case that: Node => if (that.symbol == null) {if (symbol == null ) value.equals(that.value) else false} else if (symbol == null) false else if (left.equals(that.left) && right.equals(that.right) && symbol==that.symbol) true else if ((symbol==Symbol.ADD || symbol==Symbol.MULT) && left.equals(that.right) && right.equals(that.left)) true else false case _ => false } override def hashCode(): Int = { var result = value.hashCode() result = 31 * result + (if(left == null) 0 else left.hashCode()) result = 31 * result + (if(right == null) 0 else right.hashCode()) result = 31 * result + (if(symbol == null) 0 else symbol.hashCode()) result }
3. 打印表达式
def printNode(node: Node):String = { if (node == null) return "" val midValue = if (node.symbol == null) node.value.toString else node.symbol.value // 左右的原始值 var leftValue = printNode(node.left) var rightValue = printNode(node.right) // 判断是否要加括号,如果要,就加上去 if (node.symbol != null && (node.symbol == Symbol.MULT || node.symbol == Symbol.DIV)){ val leftSymbol = node.left.symbol val rightSymbol = node.right.symbol if (leftSymbol != null && (leftSymbol == Symbol.ADD || leftSymbol == Symbol.SUB)) leftValue = Bracket.leftBracket.value + leftValue + Bracket.rightBracket.value if (rightSymbol != null && (rightSymbol == Symbol.ADD || rightSymbol == Symbol.SUB)) rightValue = Bracket.leftBracket.value + rightValue + Bracket.rightBracket.value } leftValue + midValue + rightValue }
4. 从字符串生成表达式树(用于计算成绩时构造表达式树)
def fromString(s:String): Node = { // 克隆输入的字符串,实现函数式编程 var value = new String(s.toCharArray) // 给符号都加上空格 Symbol.values().foreach(symbol => { if (symbol.value.equals("+")){ value = value.replaceAll("\\+", " %s ".format(symbol.value)) }else{ value = value.replaceAll(symbol.value, " %s ".format(symbol.value)) } }) // 给括号都加上空格 Bracket.values().foreach(bracket => value = value.replaceAll("\\" + bracket.value, " %s ".format(bracket.value))) //去空格生成元素数组 val factor = value.split(" ").toStream.map(s => s.trim).filter(s => !s.isEmpty).toList val nodeStack: util.Stack[Node] = new util.Stack[Node] val symbolStack: util.Stack[String] = new util.Stack[String] for (f <- factor) { // 尝试转换成数字 val value = Number.fromString(f) if (value.isDefined) { // 是数字 nodeStack.push(Node(value.get, null, null, 0, null)) } else { // 是符号 var signal = true while (!symbolStack.empty() && !f.equals(Bracket.leftBracket.value) && !((f.equals(Symbol.MULT.value) || f.equals(Symbol.DIV.value)) && (symbolStack.peek().equals(Symbol.ADD.value) || symbolStack.peek().equals(Symbol.SUB.value))) && !(!f.equals(Bracket.rightBracket.value) && symbolStack.peek().equals(Bracket.leftBracket.value)) && signal) { val symbol = symbolStack.pop() if (symbol.equals(Bracket.leftBracket.value) && f.equals(Bracket.rightBracket.value)) { signal = false } else { val rightNode = nodeStack.pop() val leftNode = nodeStack.pop() val sym = symbol match { case "+" => Symbol.ADD case "-" => Symbol.SUB case "×" => Symbol.MULT case "÷" => Symbol.DIV case _ => sys.error("非法运算符!") } val result = Calculate.calc(leftNode.value, rightNode.value, sym) if (result.isEmpty) { sys.error("存在不符合规范的算术表达式!") } val high = math.max(leftNode.high, rightNode.high) + 1 nodeStack.push(Node(result.get, leftNode, rightNode, high, sym)) } } if (!f.equals(Bracket.rightBracket.value)) { symbolStack.push(f) } } } while(!symbolStack.isEmpty){ val symbol = symbolStack.pop() if (!symbol.equals(Bracket.leftBracket.value)){ val rightNode = nodeStack.pop() val leftNode = nodeStack.pop() val sym = symbol match { case "+" => Symbol.ADD case "-" => Symbol.SUB case "×" => Symbol.MULT case "÷" => Symbol.DIV case _ => sys.error("非法运算符!") } val result = Calculate.calc(leftNode.value, rightNode.value, sym) if (result.isEmpty) { sys.error("存在不符合规范的算术表达式!") } val high = math.max(leftNode.high, rightNode.high) + 1 nodeStack.push(Node(result.get, leftNode, rightNode, high, sym)) } } nodeStack.pop() }
测试运行
生成问题
生成答案
生成成绩
把一些题目的答案改成错误
项目小结
通过结对编程,两个人互相修改代码,共同提高了能力,也写出了更好的代码。确实是种不错的写代码方式