程序设计结构分析

类图分析

  • 第一次作业

    由于第一次作业完成的功能比较简单,而且出于对面向对象设计理念不熟悉(其实现在也不是很熟悉,逃),整个程序设计的非常简单。通过类图(见下)可以看出,程序只有两个类:PolyCal 包含 main 方法,充当表达式类的功能,并且完成对输入的解析;Poly 充当项类,管理一个项内的因子,并向 PolyCal 提供服务。

  • 第二次作业

    这次作业虽然较上一次而言,划分出了很多类,但其实与第三次作业助教提示的设计架构仍有较大的差距,面向过程的意味仍然非常明显。PolyCal 仍然是充当表达式类,包含 main 方法,并且自己解析输入,完成求导并化简等诸多功能,剩下的其他类都是充当它的辅助,可以看出 PolyCal 类的功能过于复杂,不可取。

  • 第三次作业

    借由助教的提示,这次将 Main 单列成一个类,而且完成逻辑业务的框架由三个大类组成,表达式、项类、因子类。Main 类负责创建并维护一个 Expression 类的实例,将初步处理过的输入交给表达式类解析,表达式类的解析则是表达式创建项类将输入交给他们解析。不过,这个架构也有不足之处,第一,我把优化输出即去掉多余括号的大多数工作交给了 toString() 方法,这直接导致了后面遇到了未知的 TLE bug,调式时没法查看当前变量,因为查看会调用 toString() 方法,而 toString() 出了 bug;第二,对于输入解析的处理仍然非常暴力,直接导致了 Poly 类复杂度爆炸。

复杂度分析

由于方法复杂度的截图过长(方法数太多了,严重影响阅读体验),所以这里只挑我发现的重点问题说。三次作业方法复杂度超标比例为 1:3/12;2:5/28;3:17/53,类复杂度如下图。





  • 分析总结
  1. 由于方法中使用了大量的 if-else 控制语句,导致三次作业的部分方法圈复杂度比较高
  2. 由于并未将解析表达式的功能单列出来,导致了第一、二次作业 PolyCal 与第三次作业 Poly 类复杂度偏高
  3. 由于将优化放在了表达式类中,导致后两次作业的 PolyCal, Expression 类的复杂度偏高

自己程序的bug -- 优化 bug

后两次作业强测中挂掉的数据点,最后发现都是由于自己优化的锅,在这里检讨一下。

  • 第二次作业

    • 第二次作业主要是三角函数的优化,当时我采用的是数学公式硬优化,从 sin(x)^2 + cos(x)^2 = 1 开始推导,得到了在一定前提条件的情况下,能够实现三角函数化简。但是最后写代码的时候把 if 条件语句的前提条件写错了。仔细想一下,虽然这只是由于一个失误造成的 bug,但是这种单靠数学公式推导的方式来进行化简的思路,本身就是足够复杂的,不能算得上比较好优化方法。
    • 这里分享一下研讨课上听到某位大佬介绍的优化方法 -- 启发式算法

    一个基于直观或经验构造的算法,在可接受的花费(指计算时间和空间)下给出待解决组合优化问题每一个实例的一个可行解

    • 本次作业的优化,就是基于 sin(x)^2 + cos(x)^2 = 1 这条经验,通过迭代循环优化来实现的。起始,将未优化表达式放入 TreeMap 中,每次迭代循环过程中,将 TreeMap 中最短的表达式取出,随机选择其中一项将其中的 cos(x)^2 或 sin(x)^2 化成 1 - sin(x)^2 或 1 - cos(x)^2,再去合并同类项,将新的表达式放入 TreeMap 中。这样做,虽然并不能保证一定能优化出优于原解的表达式,但其执行时间可控,可以在一定程度上避免自己的程序因为优化而造成 TLE
    • 关于更多启发式算法,这里推荐一篇帖子
  • 第三次作业

    第三次作业,我想采取的优化也仅仅是去掉多余的括号,如果项中含有一个因子为 0(或 sin(0) 等)那么整个项 toString 返回一个空串,以及如果表达式因子仅含有一个项,那么输出它的时候,就去掉括号,以及尽可能的合并同类项。现在回顾看来,这些优化的实现方法都存在问题,下面分享一下心得体会。

    1. 表达是因子的去括号的操作应该交给字符串输入解析类来完成,即通过栈来检查括号匹配,查看是否首尾括号恰好内嵌一对括号。
    2. 注意 ArrayList.addAll() 是浅拷贝,意味着,它只是把索引赋了过来,若后面对索引对象进行了值修改,会导致本不想修改的原对象也被修改了。这里建议以后尽量采用不可变对象,任何修改值的方法都是返回一个新的对象。
    3. 不应该将优化操作放在 toString() 方法内部

互测发现别人的 bug

由于后面两次作业优化都出了巨大 bug,所以被分到了 bug 较多的 C 组,所以检查别人 bug 难度相对较低,我采取的是,先把所有人的代码文件夹集中到一个目录下,先通过 javac 编译,然后就可以用 .sh 文件快乐的,一次测所有人的代码了。除此之外,还用 python 的 Xeger 和 sympy 包,搭了一个简易的自动对拍器,但遗憾的是,正则表达式没法生成嵌套,所以第三次作业并没能很好的自测到自己的 bug。

应用工厂模式解析输入字符串

因为观察到,由项来实现对字符串的解析取出每一个因子然后生成对应的因子对象,导致项类的复杂度过高;而且不同种类的因子生成都非常类似,找到对应的字符串,传递给构造器即可。所以可以创建一个工厂接口,为每位因子实现一个工厂生成方法,在项类仅需要通过正则表达式判断一下当前需要解析的因子是哪一种的,然后就可以通过工厂接口变量实例化对应的工厂方法,来生成对应的因子,减轻项类的工作负担。

public interface ParseFactor{
public ArrayList<Object> parse(String input);
// 因为我不仅需要返回新建的因子对象而且需要返回解析过剩下的字符串
}

OOP 第一章作业总结的更多相关文章

  1. OOP第一章总结

    经过了三周的OO,尽管过程不太轻松,但是有所得还是值得欣慰的事! (1)程序结构 第一次作业: UML类图如下,第一次作业在结构上并没有太多面向对象的思想,只是简单的分类,一个运行类,两个对象类,预处 ...

  2. OOP 第二章作业总结

    实现策略 这里结合一下我画的第三次作业的时序图(可能有画的不好的地方)来叙述一下我的实现逻辑.最开始主线程负责创建必要的线程(输入.调度线程)与请求队列类实例:输入线程负责与人进行交互,将获取到的请求 ...

  3. Java OOP——第一章 对象和封装

    1.软件出现的目的: 用计算机的语言描述现实世界 用计算机解决现实世界的问题   ◆面向对象设计和开发程序的好处:    交流更加流畅    提高设计和开发效率 计算机语言的发展向接近人的思维方式演变 ...

  4. linux系统管理第一章作业

    上机作业: 1.请用命令查出ifconfig命令程序的绝对路径 [root@localhost ~]# which ifconfig /usr/sbin/ifconfig 2.请用命令展示以下命令哪些 ...

  5. Metasploit魔鬼训练营第一章作业

    1, Samba服务 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共 ...

  6. 《Metasploit魔鬼训练营》第一章实践作业

    <Metasploit魔鬼训练营>第一章实践作业 1.搜集Samba服务usermap_script安全漏洞的相关信息,画出该安全漏洞的生命周期图,标注各个重要事件点的日期,并提供详细描述 ...

  7. 第一章 C++简介

    第一章  C++简介 1.1  C++特点 C++融合了3种不同的编程方式:C语言代表的过程性语言,C++在C语言基础上添加的类代表的面向对象语言,C++模板支持的泛型编程. 1.2  C语言及其编程 ...

  8. SQL 第二章 作业

    /*第二章 作业*/ create table S ( sno char(2) NOT NULL UNIQUE, sname char(3), city char(2) ); alter table ...

  9. 第一章ASP.NET SignalR简介

    第一章ASP.NET SignalR简介 1.1概述: ASP.NET SignalR是微软新开发的类库,为的是帮助ASP.NET开发人员很方便地开发实时网络功能. SignalR允许服务器端和客户端 ...

随机推荐

  1. repo搭建

    [root@op-yum01]# cat /home/work/yumdata/rsync-reposync.sh #!/bin/bash #Purpose: Sync centos7 repos v ...

  2. “全栈2019”Java第七十四章:内部类与静态内部类相互嵌套

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. [ActionScript 3.0] 绘制扇形方法

    /** * 绘制扇形 * @param mc 承载扇形的对象 * @param x 圆心角x * @param y 圆心角y * @param r 半径 * @param angle 绘制角度 * @ ...

  4. 1、Caffe数据层及参数

    要运行Caffe,需要先创建一个模型(model),每个模型由许多个层(layer)组成,每个层又都有自己的参数, 而网络模型和参数配置的文件分别是:caffe.prototxt,caffe.solv ...

  5. kaggle kernel使用指南

    有几个要注意的地方: 1.可以选择CPU或GPU,但是机器学习模型一般的CPU就够了,最近(2019.04)使用GPU的话一小时后总是会断开连接,这时候要跑久一点的cell就凉了. 2.导入文件:支持 ...

  6. python update()

    Python 字典 update() 函数把字典参数 dict2 的 key/value(键/值) 对更新到字典 dict 里. dict.update(dict2) 如果dict2里的键和dict1 ...

  7. QRegExp

    这段代码会越界,百思不得七姐(过了N久时间 之后^^)原来是把i写成了1  --! //#if 0 QRegExp re1("AT+CGATT?"); QRegExp re2(&q ...

  8. HTML 标记大全参考手册

    1.文件结构 文件类型 <HTML></HTML> (放在文档的开头与结尾) 文件主题 <TITLE></TITLE> (必须放在「文头」区块内) 文头 ...

  9. jquery-ui Datepicker 创建 销毁

    控件选项defaultDate 设置日期控件的默认日期(高亮显示的日期),如果没有设置该选项,那么就使用当前日期,这一选项只适用于input元素没有设置value属性的情况altField 额外自定一 ...

  10. Emma姐