zoukankan      html  css  js  c++  java
  • 《口算大作战 2》DLC:算法真奇妙

    211614331 王诚荣     211614354 陈斌 --第一次结对作业

    DLC

    DLC:三年级混合运算模块现已更新!现在您可以愉快的使用三年级题库啦。同时您必须拥有本体才能使用此DLC

    单击此处查看本体:《口算大作战 2》标准版

    一、开发时间表

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

    二、用户需求分析

    本次的需求分析,我没有去过多的研究,因为在作业博客中,已经有了明确的需求

    • 运算符在2~4个,至少两个不同的运算符
    • 可以加括号
    • 减法运算的结果不能有负数
    • 除法运算除数不能为0,不能有余数
    • 同时要有一二年级的题库在里面
    • 要分别满足一二三年级运算的需求

    经过分析,我认为,这个程序应当:

    • **一二年级只要符合上次作业的需求即可,不需要再次分析 **
    • 三年级加减乘除中都不能有负数
    • 且在除法中,需要特别关注程序除零时的异常处理

    三、项目设计分析

    1. 设计思路

    这次作业由于是结对作业,因此我们有一些明确的分工。在分析完需求之后,我们发现,四则运算是需要重点攻克的难题,但是如果两个人把全部的时间都放在这个地方的话,那么进度一定会被拖慢,无法正常完成任务。所以我们在经过讨论之后,决定先一起讨论一下四则运算的逻辑和解决办法,然后由我负责三年级四则运算的编码,我的队友则负责完成其他模块功能的实现,以此来满足任务需求。最后再把所有的代码整合在一起,完成此次任务。

    因此,下面我主要介绍的是 “《口算大作战 2》DLC:算法真奇妙 ” 这个部分的具体细节

    • 首先,我要大声的说:一个好的算法是真的很厉害!!! 逆波兰大法好!!!算法真奇妙!!!(ps:至于具体为什么,等下我就吐槽一下我编码时的辛酸史

    • 首先,我和我的队友需要攻克逆波兰表达式的实现方法,以及背后的逻辑

    • 为此我设计了两个类,一个是不断出题并把题目喂给四则运算类,另一个是四则运算类,其中使用了逆波兰和调度场算法来解决四则运算的问题。(我也说一下我们整个程序所用到的类:共有九个类,三年级模块两个类,一二年级四个类,一个运算父类,一个主方法,一个输出类

      设计类图如下

    • 在本次设计中,遇到了一个关键的问题,就是中缀表达式如何转后缀表达式,以及逆波兰算法。在这个地方,我觉得没有什么比两张张动态图更能理清思路了,通过这两张图片,以及博客说明,我理清了逆波兰和调度场的大致思路。图片转自算法表达式求值--逆波兰算法介绍

    • 调度场是用栈的方式来存储遍历的题目结果,并且以特定的规则弹栈和压栈。首先要有两个栈,一个是临时栈,一个是用来存储后缀表达式的栈。然后遍历题目,当为数字时,直接压入后缀栈,遇到符号时,左括号直接进栈,加减乘除要和临时栈顶比较优先级,和是否同级,如果优先级高直接压入临时栈,如果是同级或者优先级低,则临时栈要弹出栈顶--并把栈顶放入后缀栈,以此循环,直到准备进入的符号优先级比栈顶高(此处要注意空栈的情况)。当遇到右括号是,右括号直接抛弃,临时栈开始弹栈--并压入后缀栈,直到临时栈的栈顶为左括号,然后将左括号抛弃

    2. 实现方案

    • 准备工作:先在Github上创建仓库,克隆到本地,在本地新建Pair_211614331_211614354文件夹,在eclipes中创建工程
    • 技术关键点:
      • 逆波兰算法的实现(理解,外加各种空栈异常判断)
      • 随机出题目的逻辑,以及加括号时的逻辑判断

    四、引擎模块

    写在前面的小花絮:

    在一开始,我并没有打算使用调度场和逆波兰算法,我有点想自己尝试着写出四则运算的解决办法。于是我开始了异常艰难的旅程。可以说编码的一大半时间都放在了这里。在当时,我的想法是,既然四则运算,括号优先级最高,那么我是不是可以先遍历题目,找到最里面的一个括号,再调用函数把括号里的值算出来,得到结果后,返回个题目,然后继续遍历,寻找括号。

    沿着这个思路,我就建立了两个类,一个是找呀找呀找括号的类,一个是复制运算不带括号的四则运算类。经过长时间的编码和除bug,我的程序是可以跑起来的,可以正常解题!!!当时还是有点小激动的。这份喜悦直到我开始大量的出题目时被彻底浇灭了,我的这套解题程序,遇到几个题目还好,当遇到了大量题目时,根本反应不过来,处理速度极慢,尤其是到了四百多题的时候,变的越来越慢,越来越慢,最后就是几秒钟才弹出题目和答案......然后我就迷茫了,这时我去看了室友的解决办法,他使用的是调度场和逆波兰哇!真的不敢想象,题目就那样刷的一下,连同答案一起跳出来了!!!这也太快了吧,我的算法是个什么垃圾......

    然后我才乖乖的开始学习逆波兰和调度场,学习效率比我快十几倍的算法。所以说,还是那句话:算法真奇妙!!!

    1. 调试日志

    记录编码调试的日志,请记录下开发过程中的 debug 历程

    • 在使用调度场算法编码的过程中,主要遇到的还是在入栈符号优先级更低,和同级情况下,临时栈弹出后,循环判断时,容易出现空栈的情况。
      • 这个问题我一开始也是没有头绪的,就想到一个,使用do-while进行循环判断,但是一直卡在了循环跳出时的判断,因为跳出时判断有多重情况,一个是弹玩就是空栈,一个是栈顶还是优先级大于等于入栈元素。后来我在do-while语句中间,加了一个判断是否为空的语句,当空就直接break循环,才解决的
    • 还有一个问题就是,括号出现的问题,这里我暂时采用的是定位随机的办法,即我事先规定了十多种括号的出现情况,把他们分别存储在字符串中(取名为括号标准定位码),然后用随机的办法,选择一种括号情况,放入事先出好的题目中。这种办法,并没有真正的随机出现括号,但是因为我不带括号的题目是随机生成的,题目各不相同,因此,在一定情况下,也可以看作是随机生成的带括号的四则运算式子。

    2. 关键代码

    请展示一段程序的关键代码,并解释代码的作用

    switch (order) {
    				case 1:{
    					positionCode="(---)-(---)";    //定位码的几种情况,随机选定后,扫描定位码,发现括号则加入;
    					break;        //一部分情况
    				}
    				case 2:{
    					positionCode="--(---)-(---)";
    					break;
    				}
    				case 3:{
    					positionCode="--((---)--)";
    					break;
    				}
    				case 4:{
    					positionCode="--((---)-(---))";
    					break;
    				}
    				case 5:{
    					positionCode="(-----)";
    

    程序产生括号的代码确实不够优雅,但也能临时解决问题,同时其实是可以不用扫描定位码的,可以换一种形式,比如直接存左右括号的位置,这样加入集合也更加迅速。当然,还有真正正牌的随机办法,但我没有想到......

    if(!shortStack.isEmpty()) {
    						
    
    
    					 if(shortStack.peek().matches("[\+\-\*\/]")) {	// 栈顶为同级或加减
    						 do {
    							 postFixStack.push(shortStack.pop());//栈顶和入栈的同级,或级别更高
    							 if(shortStack.isEmpty())//判断弹玩是否变空
    								 break;//弹玩后,变空
    							 
    						 }while(shortStack.peek().matches("[\+\-\*\/]") );//栈顶还是这些时
    						 shortStack.push(partNumber);	// 把当前元素入栈
    					 }
    					 else
    						 shortStack.push(partNumber);	// 栈顶就是括号的时候,把当前元素入栈	
    				}
    				else
    					shortStack.push(partNumber); //是空直接压栈
    

    中缀转后置表达式很大一部分的报错都是因为弹的是空栈,所以理清楚这个,就算是完成了一大步了。

    3. 代码规范

    请给出本次实验使用的代码规范:

    • 第一条:代码中的命名均不能以下划线或美元符号开始,也不以一下划线或美元符号结束
    • 第二条:代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式
    • 第三条:类名使用UpperCamelCase风格
    • 第四条:方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格
    • 第五条:杜绝完全不规范的缩写,避免忘文不知义,都以英文单词命名
    • 第六条:采用4个空格缩进,禁止使用tab字符
    • 第七条:不同逻辑、不同语义、不同业务的代码之间插入一个空行分割开来以提升可读性。

    4.结对编程

    • 在结对编程中我们在有明确的分工,才尽可能的保证了项目的进度。
    • 同时我们也相互讨论各自所遇到的问题,一开始没有头绪,但双方讨论后,可能就会瞬间想到思路

    五、BUG调试

    请思考并记录你认为必要的测试点,并记录测试用例与测试结果

    六、开发者有话说

    • 好的算法尤其重要,它更轻量也更加高效,在完成我负责的部分里,我们两个都认识到了算法的重要性,真的不一样!!!

    • 同时,当有还要有团队合作的能力,要学会与队友沟通和交流,有时候,思路就是在交流中闪现的,一个人想不到,几个人就会有不一样的思路,俗话说的好,三个臭皮匠,顶个诸葛亮。

    • 当项目越来越大的时候,一个人就很难在规定的时间内完成任务,也就是说,我们在今后一定会经常遇到与他人合作的情况。很大一部分情况中1+1>2,所以在团队中,尽力去做,效果也会翻倍!!!

    • 当然,在沟通时,也要有耐心,同时要想办法把自己的想法表达出来,这点我还是需要学习的。

  • 相关阅读:
    什么是语义化的HTML?有何意义?为什么要做到语义化?
    Doctype作用?严格模式与混杂模式如何区分?它们有何差异?
    js和jq中常见的各种位置距离之offsetLeft和position().left的区别(四)
    js和jq中常见的各种位置距离之offset和offset()的区别(三)
    js和jq中常见的各种位置距离之offset()和position()的区别(二)
    js和jq中常见的各种位置距离之offsetLeft/clientLeft/scrollLeft (一)
    剖析js中的数据类型
    js数组去重几种方法
    SSE and Websocket
    鲜为人知的空元素╮(╯▽╰)╭
  • 原文地址:https://www.cnblogs.com/JQvQJ/p/9672377.html
Copyright © 2011-2022 走看看