作业一、多项式的加减运算

1、设计要点与自我分析

我设计的类图

复杂度分析图



老师建议类图

我设计了两个类来进行多项式的计算,类Polynomial进行多项式的存储和输入输出,第二个类进行多项式加减运算。而加减运算的类里面只有方法,而且都是静态方法,没有存储变量,感觉这个设计还是有些问题。之后我也参考了一下别人的代码。

在Method Metrics中可以看到ev, iv, v这三栏,分别代指基本复杂度(Essential Complexity (ev(G))、模块设计复杂度(Module Design Complexity (iv(G)))、Cyclomatic Complexity (v(G))圈复杂度。

ev(G)基本复杂度是用来衡量程序非结构化程度的,非结构成分降低了程序的质量,增加了代码的维护难度,使程序难于理解。因此,基本复杂度高意味着非结构化程度高,难以模块化和维护。实际上,消除了一个错误有时会引起其他的错误。

Iv(G)模块设计复杂度是用来衡量模块判定结构,即模块和其他模块的调用关系。软件模块设计复杂度高意味模块耦合度高,这将导致模块难于隔离、维护和复用。模块设计复杂度是从模块流程图中移去那些不包含调用子模块的判定和循环结构后得出的圈复杂度,因此模块设计复杂度不能大于圈复杂度,通常是远小于圈复杂度。

v(G)是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数,即合理的预防错误所需测试的最少路径条数,圈复杂度大说明程序代码可能质量低且难于测试和维护,经验表明,程序的可能错误和高的圈复杂度有着很大关系。

Class metrics中两栏分别为Ocavg(Average Operation Complexity)和WMC(Weighed method complexity)

在main函数中,我的基本复杂度较大较大,我定义了一个output的函数方法用于输出结果,不过模块化程度还算可以。

  • 多项式的存储:

    我用的是一维数组来存储多项式,下标代表的是多项式的次数,数组存储的是多项式的系数,这种存储方法对于多项式加减法的操作很方便,但是浪费的空间大,因为很多系数是0;而且存储多项式加减式子的时候也开了大数组将所有数据装进去,一次性进行计算,这样也浪费了大量的空间。

    参考了大佬的代码,学习了一下如何管理多项式的存储和加减:

    1、专门设出一个类来存多项式的每一项,包括系数和次数,然后开一个ArrayList<Object>来存储这个类。

    2、加减法操作,将所有项加入到原来的ArrayList里面,然后在ArrayList里面对指数相同的项进行合并操作,再进行对指数从小到大的排序,用了sort()函数。

2、所用知识

1. 去除空白字符
s = s.replaceAll("\\s*", "");
2. 正则表达式的使用

1、使用group()捕获组:

捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。group(0)代表的是整个匹配的表达式,之后每遇到一个左括号,group的索引值加一。

  • public String group( )

返回上次匹配操作(比方说find( ))的group 0(整个匹配)

  • public String group(int i)

返回上次匹配操作的某个group。如果匹配成功,但是没能找到group,则返回null。

2、非贪婪匹配:

当“ ?”字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m}之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。

*、+限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。

3、判断两个字符串内容是否相等

需要用str.equals()的方法判断,而不能使用“==”号。

4、错误的捕捉,使用try-catch和throw

try{
... ...
}catch(IOException e){
//处理IO异常的代码
}catch(NumberFormatException e){
//处理parseInt不能转换时的异常代码
}catch(StringIndexOutOfBoundsException e){
//处理数组越界的异常代码
}catch(Exception e) {
//总异常(父类)
}

也可以自定义异常,如果不满足某项条件则抛出异常

if(!m.find()){
throw new PolynomialError();
}

5、结束进程

System.exit(0);

6、可以重写toString()的方法返回多项式的值。

3、遇见BUG以及改正方法

1、正则表达式太长,在数据压力大的时候可能会爆栈

我将整个多项式加减法的式子用正则表达式一次性匹配检查格式是否正确,但由于表达式太长,数据压力大而爆栈。应该逐个多项式进行匹配,逐个向后查找。

2、系数相加的时候容易超出范围

使用java异常处理语句进行异常的捕捉

3、输出多项式的时候没有判断是否是输出第一个大括号,导致前面出现逗号。

加入第一次进入输出循环的判断。

4、在本题目的多项式匹配当中,可使用 (^|\\+|-)(\\{.*?\\})来匹配其中加减的操作项。

但是如果两个加减项之间出现了非法字符,正则表达式会自动跳过非法字符去匹配下一项,要怎么解决这个问题呢?我想到三种方法:

(1)将匹配成功的字符串删除以后,用^从头开始匹配。代码如下:

	String pattern = "^(^|\\+|-)(\\{.*?\\})";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(line);
while (m.find()) {
System.out.println("Found value: " + m.group());
line = line.replace(m.group(),"");
m = r.matcher(line);
}

(2)每次记录匹配字符串的长度,然后依次累加,如果发现累加得到的字符串长度和读到的m.start(0)索引值不一致,则中间有非法字符。

(3)用region(start,end)重设m的范围。

4、Eclipse的使用总结

1. 导入工程
  • 设置工作空间(Workspace)有明显的层次结构。 项目在最顶级,项目里头可以有文件和文件夹。插件可以通过资源插件提供的API来管理工作空间的资源。

  • 首先打开eclipse软件,找到左上角File然后点击,然后我们选择Import,点击Import

  • 点击Import后,会弹出Import窗口,然后找到General,点击General左边小三角,然后选择Existing Projects into Workspace

  • 有时候点导入文件会出现提示

    **Project is not a Java project. **

    有几种情况:

    • package名字不相符:右键项目->Build Path来更改source folder的设置

    • eclipse 工程没有build path,则在项目.project文件中添加

    <buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
  • JDK版本不对: 项目右键 -->properties-->Java Build Path-->Libraries 然后将JDK换成你当前的JDK版本
2、修改字符集

默认情况下 Eclipse 字符集为 GBK,但现在很多项目采用的是 UTF-8,这是我们就需要设置我们的 Eclipse 开发环境字符集为 UTF-8, 设置步骤如下:

在菜单栏选择**Window -> Preferences -> General -> Workspace -> Text file encoding **,在 Text file encoding 中点击 Other,选择 UTF-8。

3、调试快捷键

F11――进入DEBUG视图

F5——进入:移动到下一个步骤,如果当前行有一个方法调用,该控件将会跳转到被调用方法的第一行执行。

F6——跳出:移动到下一行。如果在当前行有方法调用,那么会直接移动到下一行执行。不会进入被调用方法体里面。

F7——返回:从当前方法中跳出,继续往下执行。

F8——移动到下一个断点处执行。

作业二、电梯的简单调度

1、设计要点与自我分析

逻辑结构图:

类图:

设计建议类图:

复杂度分析图:

本次作业的设计要点是多个类进行协同,同时使用队列进行调度。我将请求加入到请求队列当中,由调度器从请求队列中读取请求对电梯类进行调度和操作,楼层类我没有实际用上,这也是设计上的不均衡。其他几个类职责比较分明,调度逻辑清晰。

可以看到我的RequestQueue类的复杂度较高,因为我在里面大量用if语句来判断出现的不同格式错误来输出错误提示,导致复杂度升高。

2、所用知识

LinkedList的使用,由于本电梯使用的是队列的结构,使用了如下几种方法:

(1)q.offer(e) 在链表尾部插入元素

(2)q.peek() 获取第一个元素

(3)q.remove(e) 删除一个元素

(4)q.poll(e) 查询并移除第一个元素

(5)遍历链表:

//for循环遍历
for(int i = 0; i < linkedList.size(); i++){
linkedList.get(i);
}
//Foreach遍历
for(Integer i : linkedList);
//迭代器遍历
Iterator<Integer> iterator = linkedList.iterator();
while(iterator.hasNext()){
iterator.next();
}

但是迭代器遍历和foreach遍历的时候因为是动态删除链表会发生线程错误,所以我用了for循环遍历。

3、遇见BUG以及改正方法

我使用了LinkedList()来存储请求,每次执行一次请求会遍历链表看看有没有同质请求,有的话进行删除。但是删除以后链表的总长度会改变,所以删除以后要将索引值减一。在debug的过程中找出了这个错误,后来在公测的时候顺利通过了。

我测试的同学没有用正则表达式,全部用if-else判断,程序容错能力过差,导致公测全部没有过。

作业三、具有捎带功能的电梯调度

1、设计要点与自我分析

  • 提高资源利用率是调度算法设计的核心目标
  • “顺路捎带”:在去响应一个请求的路途中可以把资源共享给顺路可完成的请求

类图:

复杂度分析:

老师推荐设计:

在第二次作业的基础上,我用Scheduler类继承了Dispatcher类,创建了电梯移动的接口。

我顺路捎带的思路是找到主请求,然后遍历队列后面可以被捎带的请求,找到离主请求最近的请求执行,若超出主请求的执行时间,便执行主请求,然后选择捎带的第一条消息作为主请求。但是这个设计思路遇到了很多问题,后来参考了别人的思路。可以将每次所能找到捎带方向上的最高楼层作为目标楼层,然后停靠中间的楼层,这样的思路简洁清晰,也省去了很多判断的步骤。

可以看到我的Scheduler类复杂度十分高,因为我思路的问题,导致在这个类里面有很多判断条件的语句,整个程序十分冗杂。

2、所用知识

(1)类的继承

使用继承机制,增加一个子类来重写第二次作业中的schedule方法,需要注意子类不能继承父类的构造器,但是父类的构造器带有参数的,则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表。 如果父类有无参构造器,则在子类的构造器中用super调用父类构造器不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器。

(2)使用interface来归纳电梯的运动方法。

(3)重写toString()方法来获得电梯运行状态和时刻的观察。

3、遇见BUG以及改正方法

在这次的作业中,由于我每次都是找到可捎带请求的最小请求,但是在主请求更换的时候,我将主请求设为了可捎带的最小请求,而可捎带的最小请求在前一条捎带请求的后面发出,这就造成了后发出的指令先执行了。参考了其他同学的捎带思路,即找到当前方向上可捎带的最高楼层进行停靠,可以简化此问题。

其次就是输出错误格式的问题,INVALID的输出的是原请求,而我将请求的括号换掉了,导致很多bug。

测试策略

一开始我是根据错误分支树来构造测试用例,后来的作业中,我根据别人的代码结构来构造测试用例,发现代码中的逻辑错误和bug。

心得体会

作为刚接触面向对象的小白,第一次作业布置下来,就开始两天速成Java,正则表达式,很多资料看得一脸懵逼,期间总是去打扰大佬,问一些十分基础的问题。但在后面两次作业中,对整个编写流程开始熟练起来,也开始理解面向对象的编程思想。每次作业做完以后,也会参考一下别人的代码,和自己的做一下对比,看看那些地方能更加简洁的表达,更高效的处理,同时也感谢能将代码分享给我的同学~

还有就是一定要仔细阅读指导书,我就是因为指导书没有好好看,导致程序出了很多bug,第一次作业由于输出提示没有#提示,挂满了错误分支树,可以说还是很绝望的。第三次的指导书和第二次的差不多,我又很粗浅地看了,差点漏掉了重要信息,第一条指令有限制。后来是在看讨论区的讨论才发现了这个问题。

前期的逻辑结构设计一定要清晰,否则无脑开始写代码真的会遇到特别多问题。

转系之后感觉自己真的特别菜,改bug经常改到绝望,但还是真心感谢一些能够和我交流的小伙伴。

OO面向对象课程作业1-3总结的更多相关文章

  1. OO面向对象 课程总结

    测试与正确性论证的效果差差异 测试和正确性论证都是对程序进行可靠性的验证. 测试: IEEE提出了对软件测试的定义:使用人工或者自动的手段来运行或测定某个系统的过程,其目的在于检验它是否满足规定的需求 ...

  2. 【作业4.0】HansBug的第四次面向对象课程思考

    嘛..不知不觉这门课程要结束了,那么就再说点啥以示庆祝呗. 测试vs正确性论证 说到这个,相比很多人对此其实很有疑惑,请让我慢慢分析. 逻辑概览 首先我们来看看两种方式各自的做法和流程是什么样的: 单 ...

  3. THE LAST ONE!! 2017《面向对象程序设计》课程作业八

    THE LAST ONE!! 2017<面向对象程序设计>课程作业八 031602230 卢恺翔 GitHub传送门 题目描述 1.时间匆匆,本学期的博客作业就要结束了,是否有点不舍,是否 ...

  4. Python全栈day24(面向对象编程作业作业_定义学校老师课程班级学生类)

    面向对象作业 作业_定义学校老师课程班级学生类.py #面向对象编程作业,定义学校老师课程班级学生类 #定义几个类,尽可能定义多的数据属性及函数属性 class School: def __init_ ...

  5. OO面向对象第一单元总结

    OO面向对象第一单元总结(表达式求导) 写在前面: 魔鬼课程oo第一单元终于结束,当终究要落笔总结,竟不知从何写起…… 回首再去看第一次的作业,你会满足于那时的幸福,或许,这就是成长吧! 千言万语,一 ...

  6. OO第二次作业总结

    OO~第二次作业总结 连续三周的电梯作业结束了,总的来说这三次作业做的还算平稳,既没有被刀,也没有刀中别人.那么接下来开始谈谈我对这三次作业的认识. 一.设计策略 我三次作业的设计思路基本上是相同的, ...

  7. oo面向对象--规格化设计

    oo面向对象--规格化设计 规格化设计与抽象 要了解规格化设计首先要了解抽象化的程序设计,两者是密不可分的. 抽象化(Abstraction) 抽象化是将数据与程序,用语义呈现他们的外观,但是隐藏起它 ...

  8. OO第一次总结作业

    第一次OO博客作业 前言 面向对象课程已经经过了4周的时间.前三次作业全部是关于多项式求导的相关内容,内容由易到难,同时我也开始逐渐深入感受学习面向对象的各项特征,逐渐将自己的编程风格从C向真正的面向 ...

  9. 【OO学习】OO第一单元作业总结

    OO第一单元作业总结 在第一单元作业中,我们只做了一件事情:求导,对多项式求导,对带三角函数的表达式求导,对有括号嵌套的表达式求导.作业难度依次递增,让我们熟悉面向对象编程方法,开始从面向过程向面向对 ...

随机推荐

  1. CDQ分治嵌套模板:多维偏序问题

    CDQ分治2 CDQ套CDQ:四维偏序问题 题目来源:COGS 2479 偏序 #define LEFT 0 #define RIGHT 1 struct Node{int a,b,c,d,bg;}; ...

  2. [SDOI2015]星际战争

    水题啦 网络流+二分 误差才10^-3,乱搞直接开longlong暴力每个都乘1000,输出时除一下就好了 # include <bits/stdc++.h> # define IL in ...

  3. Windows Developer Day - Adaptive Cards

    概述 Windows Developer Day 在 Modern Application Experience 环节展示了一种可以让开发者以更通用和统一的方式来对卡片对展示和交互的方式,那就是:Ad ...

  4. Handsontable的前端分页与数据库分页

    Handsontable虽然处理速度很快,但当数据量达到10W+的时候很容易导致浏览器内存泄漏,这时候可以用分页来解决.官网提供了前端分页demo,测试后发现也只能处理低于10W的数据,而且调试的时候 ...

  5. SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)

    在平时开发SpringtMVC程序时,在Controller的方法上,通常会传入如Map.HttpServletRequest类型的参数,并且可以方便地向里面添加数据.同时,在Jsp中还可以直接使用r ...

  6. 戴尔R720xd服务器系统安装

    型号:R720xd 开启服务器,Ctrl+R进入raid配置 配置完raid后F2对硬盘进行格式化 保存并重启 F11进入BIOS选项设置U盘启动 选择U盘启动 开始进行系统安装!

  7. Redis数据过期策略

    1.Redis中key的的过期时间 通过EXPIRE key seconds命令来设置数据的过期时间.返回1表明设置成功,返回0表明key不存在或者不能成功设置过期时间.在key上设置了过期时间后ke ...

  8. shiro权限框架(四)

    4.1授权方式 Shiro 支持三种方式的授权 编程式:通过写 if/else 授权代码块完成: Subject = SecurityUtils.getSubject(); if(subject.ha ...

  9. 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;

    package com.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.htt ...

  10. 【Java EE】从零开始写项目【总结】

    从零开发项目概述 最近这一直在复习数据结构和算法,也就是前面发出去的排序算法八大基础排序总结,Java实现单向链表,栈和队列就是这么简单,十道简单算法题等等... 被虐得不要不要的,即使是非常简单有时 ...