我设计的类图
java
复杂度分析图
正则表达式
老师建议类图
算法
我设计了两个类来进行多项式的计算,类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;并且存储多项式加减式子的时候也开了大数组将全部数据装进去,一次性进行计算,这样也浪费了大量的空间。
参考了大佬的代码,学习了一下如何管理多项式的存储和加减:eclipse
一、专门设出一个类来存多项式的每一项,包括系数和次数,而后开一个ArrayList<Object>来存储这个类。模块化
二、加减法操做,将全部项加入到原来的ArrayList里面,而后在ArrayList里面对指数相同的项进行合并操做,再进行对指数从小到大的排序,用了sort()函数。函数
s = s.replaceAll("\\s*", "");
一、使用group()捕获组:学习
捕获组是把多个字符当一个单独单元进行处理的方法,它经过对括号内的字符分组来建立。group(0)表明的是整个匹配的表达式,以后每遇到一个左括号,group的索引值加一。测试
返回上次匹配操做(比方说find( ))的group 0(整个匹配)
返回上次匹配操做的某个group。若是匹配成功,可是没能找到group,则返回null。
二、非贪婪匹配:
当“ ?”字符紧随任何其余限定符(*、+、?、{n}、{n,}、{n,m}以后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽量短的字符串,而默认的"贪心的"模式匹配搜索到的、尽量长的字符串。
*、+限定符都是贪婪的,由于它们会尽量多的匹配文字,只有在它们的后面加上一个?就能够实现非贪婪或最小匹配。
三、判断两个字符串内容是否相等
须要用str.equals()的方法判断,而不能使用“==”号。
四、错误的捕捉,使用try-catch和throw
try{ ... ... }catch(IOException e){ //处理IO异常的代码 }catch(NumberFormatException e){ //处理parseInt不能转换时的异常代码 }catch(StringIndexOutOfBoundsException e){ //处理数组越界的异常代码 }catch(Exception e) { //总异常(父类) }
也能够自定义异常,若是不知足某项条件则抛出异常
if(!m.find()){ throw new PolynomialError(); }
五、结束进程
System.exit(0);
六、能够重写toString()的方法返回多项式的值。
一、正则表达式太长,在数据压力大的时候可能会爆栈
我将整个多项式加减法的式子用正则表达式一次性匹配检查格式是否正确,但因为表达式太长,数据压力大而爆栈。应该逐个多项式进行匹配,逐个向后查找。
二、系数相加的时候容易超出范围
使用java异常处理语句进行异常的捕捉
三、输出多项式的时候没有判断是不是输出第一个大括号,致使前面出现逗号。
加入第一次进入输出循环的判断。
四、在本题目的多项式匹配当中,可以使用 **(^|\\+|-)(\\{.*?\\})**来匹配其中加减的操做项。
可是若是两个加减项之间出现了非法字符,正则表达式会自动跳过非法字符去匹配下一项,要怎么解决这个问题呢?我想到三种方法:
(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的范围。
设置工做空间(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>
默认状况下 Eclipse 字符集为 GBK,但如今不少项目采用的是 UTF-8,这是咱们就须要设置咱们的 Eclipse 开发环境字符集为 UTF-8, 设置步骤以下:
在菜单栏选择Window -> Preferences -> General -> Workspace -> Text file encoding ,在 Text file encoding 中点击 Other,选择 UTF-8。
F11――进入DEBUG视图
F5——进入:移动到下一个步骤,若是当前行有一个方法调用,该控件将会跳转到被调用方法的第一行执行。
F6——跳出:移动到下一行。若是在当前行有方法调用,那么会直接移动到下一行执行。不会进入被调用方法体里面。
F7——返回:从当前方法中跳出,继续往下执行。
F8——移动到下一个断点处执行。
逻辑结构图:
类图:
设计建议类图:
复杂度分析图:
本次做业的设计要点是多个类进行协同,同时使用队列进行调度。我将请求加入到请求队列当中,由调度器从请求队列中读取请求对电梯类进行调度和操做,楼层类我没有实际用上,这也是设计上的不均衡。其余几个类职责比较分明,调度逻辑清晰。
能够看到个人RequestQueue类的复杂度较高,由于我在里面大量用if语句来判断出现的不一样格式错误来输出错误提示,致使复杂度升高。
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循环遍历。
我使用了LinkedList()来存储请求,每次执行一次请求会遍历链表看看有没有同质请求,有的话进行删除。可是删除之后链表的总长度会改变,因此删除之后要将索引值减一。在debug的过程当中找出了这个错误,后来在公测的时候顺利经过了。
我测试的同窗没有用正则表达式,所有用if-else判断,程序容错能力过差,致使公测所有没有过。
类图:
复杂度分析:
老师推荐设计:
在第二次做业的基础上,我用Scheduler类继承了Dispatcher类,建立了电梯移动的接口。
我顺路捎带的思路是找到主请求,而后遍历队列后面能够被捎带的请求,找到离主请求最近的请求执行,若超出主请求的执行时间,便执行主请求,而后选择捎带的第一条消息做为主请求。可是这个设计思路遇到了不少问题,后来参考了别人的思路。能够将每次所能找到捎带方向上的最高楼层做为目标楼层,而后停靠中间的楼层,这样的思路简洁清晰,也省去了不少判断的步骤。
能够看到个人Scheduler类复杂度十分高,由于我思路的问题,致使在这个类里面有不少判断条件的语句,整个程序十分冗杂。
(1)类的继承
使用继承机制,增长一个子类来重写第二次做业中的schedule方法,须要注意子类不能继承父类的构造器,可是父类的构造器带有参数的,则必须在子类的构造器中显式地经过super关键字调用父类的构造器并配以适当的参数列表。 若是父类有无参构造器,则在子类的构造器中用super调用父类构造器不是必须的,若是没有使用super关键字,系统会自动调用父类的无参构造器。
(2)使用interface来概括电梯的运动方法。
(3)重写toString()方法来得到电梯运行状态和时刻的观察。
在此次的做业中,因为我每次都是找到可捎带请求的最小请求,可是在主请求更换的时候,我将主请求设为了可捎带的最小请求,而可捎带的最小请求在前一条捎带请求的后面发出,这就形成了后发出的指令先执行了。参考了其余同窗的捎带思路,即找到当前方向上可捎带的最高楼层进行停靠,能够简化此问题。
其次就是输出错误格式的问题,INVALID的输出的是原请求,而我将请求的括号换掉了,致使不少bug。
一开始我是根据错误分支树来构造测试用例,后来的做业中,我根据别人的代码结构来构造测试用例,发现代码中的逻辑错误和bug。
做为刚接触面向对象的小白,第一次做业布置下来,就开始两天速成Java,正则表达式,不少资料看得一脸懵逼,期间老是去打扰大佬,问一些十分基础的问题。但在后面两次做业中,对整个编写流程开始熟练起来,也开始理解面向对象的编程思想。每次做业作完之后,也会参考一下别人的代码,和本身的作一下对比,看看那些地方能更加简洁的表达,更高效的处理,同时也感谢能将代码分享给个人同窗~ 还有就是必定要仔细阅读指导书,我就是由于指导书没有好好看,致使程序出了不少bug,第一次做业因为输出提示没有#提示,挂满了错误分支树,能够说仍是很绝望的。第三次的指导书和第二次的差很少,我又很粗浅地看了,差点漏掉了重要信息,第一条指令有限制。后来是在看讨论区的讨论才发现了这个问题。 前期的逻辑结构设计必定要清晰,不然无脑开始写代码真的会遇到特别多问题。 转系以后感受本身真的特别菜,改bug常常改到绝望,但仍是真心感谢一些可以和我交流的小伙伴。