北航OO第一单元总结:表达式的解析-程序员宅基地

技术标签: java  intellij-idea  

第一单元总结:表达式的解析

第一单元的三次迭代终于完成,在三周时间的代码训练中,我初步掌握了表达式解析的有关方法,对解析时所常用的架构有了更深的了解,

本单元作业中具体如下:

目标简介

作业一:通过正则表达式或递归下降方式,识别表达式、项、因子,因子包括常数、幂函数、表达式,因而进一步去除括号。

作业二:同样去除表达式括号,但是输入正式的表达式前先读入n个自定义函数(fgh),并且引入exp指数函数,指数函数类似幂函数的结构,也可带指数。

作业三:支持求导操作,新增求导算子,同时作业函数表达式中支持调用其他“已定义的”函数.

个人具体构建过程

分析维度

用MetricReloaded分析方法和类复杂度时,几个维度含义如下

CogC :关于理解方面

着重从阅读的角度来看,将一段代码复杂程度估算成一个具体数字,多次的重复遍历和嵌套将提升复杂度。

ev(G) :关于结构方面

是基本复杂度,来衡量程序非结构化程度,非结构成分降低了程序的质量,增加了代码的维护难度,同时也导致debug难度上升

iv(G):关于模块方面

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

v(G) : 关于测试方面

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

类的复杂度:

OCavg :平均操作复杂度

OCmax:最大操作复杂度

WMC : 加权方法复杂度

第一次作业

主要思路
储存数据类

第一作业框架的构建十分困难,关键是从何入手。再纠结不知多久之后,根据题目引导的架构

在这里插入图片描述

本人首先先建立表达式、项、因子三个类,将因子类设为虚类,并使表达式类继续继承因子类。这样就构建好了具体实现的存储类,每个对象中存放对应的数据。

解析类

之后就要考虑这些类实现的方法。首先应当选用递归下降进行解析,因为根据本人理解来看,递归下降更为灵活(虽然本次不要求括号嵌套,但是在后续迭代中,如果继续使用正则表达式匹配将非常棘手)

递归下降时,解析表达式就是向表达式类中添加各个项的过程,而解析项就是向项类中添加各个因子的过程。表达式的建立是一个动态的过程,每添加一个项就产生一个静态的表达式。

括号化简方法

化简应当伴于添加左右,即一边添加因子或项一边化简。

在表达式中添加项之时,可分两种情况讨论

  • 添加的是无表达式项,则直接添加,同类项则合并
  • 添加的是有表达式的项,则先将项中的每个表达式相乘,得到的表达式再与项中其他的因子相乘展开,得到一个项的hashset,再将每个项依次加入,同类项则合并

在项中添加因子就较简单了,若为数字则系数相乘,若为幂函数则与已有幂函数指数相加

细节问题

主要的细节问题出现在提高性能分方面,总结来说有以下几点

表达式中

  • 首项若是正项则不显示加号
  • 项若是0则不显示

项中

  • 系数为1则不显示
  • 系数为-1则直接加负号

另外还有同学说如果有正项优先把正项放第一个,有时能省一个正号

bug分析

第一次作业遇到的bug不多,且多为疏忽笔误导致,最后强测没有出问题。

印象最深的错误是添加项或因子时把原来的对象加进去了,要注意深拷贝一个对象再加入,否则会出现各种奇奇怪怪的错误()

hack方面

本次作业hack并未成功,在尝试hack中会尽量考虑边界值的特殊情况,例如00,x8等

类图

由如上说明构成类图

数据存储类:

在这里插入图片描述

解析类和预处理类:
在这里插入图片描述

复杂度

在这里插入图片描述
在这里插入图片描述

可以看到add相关即添加因子或项以及化简相关方法较为复杂,这几个方法具有很多多层嵌套循环,在处理中不断相互递归调用,因而复杂度比较高
在这里插入图片描述
可以看到parse和Term中复杂度较高,主要因为parse是解析类,因而集成了递归下降算法的核心。Term中作为将Factor与Expr相连接的类,本人将很多处理及化简Term中因子的方法加到了Term中,又分了很多种情况讨论处理,最后导致Term类较为臃肿,可以考虑将化简等方法单独拎出构成新的类,降低复杂度

第二次作业

主要思路
存储数据类
  • 对于自定义函数,新增Definefunc类,存储每个自定义函数的名字、函数体、变量,其中变量和函数体都用String类存储,便于之后调用实参处理
  • 对于指数函数,新增Pow类,专门存储指数函数因子。其中变量用Factor存储,在存入时首先为Expr,之后再判断是否能化简,转化为数字或幂函数,这样可以省一个括号。
解析类

大体框架改的不多,主要新增对函数因子和指数因子的判断

函数调用方法

首先将形参对应转化为“a-c“,以为了防止之后替换实参时错误替换,再将”a-c"转化为实参,注意在两边加括号,其中exp符号单独转化,防止x也被替换

细节问题
指数函数的优化

个人认为这是本次作业最能体现代码层次结构清晰度的地方,我的优化方案总体如下

term中加指数函数时:

  • 如果碰到原本已有相同指数的指数函数,则将内部变量相加合并
  • 如果碰到原本已有相同变量的指数函数,则将指数相加合并

Expr中加term时:

  • 新增equal函数以便于判断是否是同类项,equal函数时Factor的重写方法,可以递归判断两个Term中的Exp、Pow是否相等,如果都相等则判断为同类项,可以系数相加合并

还有个人没有实现的部分,判断exp内部是否有共同Number因子,可以提出来放到指数上,当数字很大时可以省很多空间。

bug分析

强测惨不忍睹,最后改完发现有多达四个地方有问题。

  1. toString方法的重写,导致程序在运行和调试时出现不一样的情况。
  2. 在exp解析内部变量时,采用的是parseFactor,这样导致之后转化为字符串化简时如果为带幂次的Expr,则幂次打印不出来,应该保险改为parseExpr。
  3. 判断两个项是否为同类项时,只判断了第一个项中的Exp和Pow在第二个项中有就直接判为相等,导致合并同类项错误,应该遵循相等的如下原则:第一个有的第二个有,第二个有的第一个也有。
  4. 还是对象克隆的问题,在添加新的exp时,应当新建一个对象

原因感觉还是粗心导致,另外应当充分利用java的clone类,否则自己每次手动构造一个新的类难免会忘记或者出问题

类图

由如上说明生成类图

数据存储类:
在这里插入图片描述

解析类和预处理类:
在这里插入图片描述

而由预处理得到自定义函数类的一个Hashset,,funcset:

在这里插入图片描述

复杂度

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
除了第一次作业化简相关方法复杂度较高以外,对函数因子传递的parseFuncFactor方法也较为复杂,因为需要分别处理读入实参等数据,处理起来比较冗长。

此外用于equal方法如上述所说是为了判断是否为同类项,递归的调用导致系统有额外的开销,属于是牺牲性能换性能分()。
在这里插入图片描述

依旧是熟悉的parse、Term,此外由于判断同类项的出现,Expr中每出现一个新Term就需要嵌套循环每个Term及其每个因子,实现起来比较复杂。

第三次作业

主要思路

这次作业要添加的不算多,只要新增一个Derivator类,用于返回一个表达式求导的结果即可。

求导方法

从底层开始

  • 对Factor求导这里不会出现Expr的Factor,所以直接套用公式就行
  • 对Term求导时,遍历Factor,对其中一个求导再乘上其他Factor构成一个新的Term,最终返回的应该是一个Expr
  • 对Expr求导时,遍历Term,将每个Term求导的结果合并得到一个新的Expr

如此一来通过遍历可较为清晰展现

bug分析

竟然是之前遗留下来的bug,对自定义函数的每个实参进行解析时,用的是parseFactor,和第二次作业exp内部解析bug是同个问题,应当改为parseExpr(),而且之前的强测也没测出来。

原因还是自己数据构造不够充分,甚至没有考虑到实参中有带幂次的表达式因子的情况。
在这里插入图片描述

hack方面

因为这次作业不同于以往的只是求导和函数定义时的调用,因此测试时多考虑有三个函数的调用定义情况

而由于求导因子存在的位置比较多,可以尝试在函数实参内、exp变量内出现,并且求导的表达式可以涵盖多个表达式因子、幂函数、指数函数混合的情况。

类图

在这里插入图片描述

数据存储类相同,解析类中只多加一个Derivator,具体在上文已说明:
在这里插入图片描述

复杂度

在这里插入图片描述
在这里插入图片描述

因为其他类与方法与第二次作业基本无区别,在这里只给出Derivator相关复杂度。

由于其本身又是以嵌套调用为基本方法的类,因而每个方法并不复杂,但是对于求导时调用的整个类的方法来说依然较为复杂。

心得体会

这个单元的三次作业做得很艰难,遇到的bug也很多,但正是因为这样的困难也让我对面向对象编程的思维方式逐渐熟练起来,主要体会有以下几点:

  1. 一个好的架构永远是第一位的。在第一周时碰到全新的需求和问题时完全就是一脸茫然,刚开始的设计是最难的,也必须要为之后两次作业的扩展做好铺垫。而未经思考的下手往往会导致之后不必要的重构,因此为了设计的可扩展性,必须先有对整体的思考,然后再在构造时不断优化,如此才能提高效率。

  2. 写完代码后要充分进行测试,可以搭建评测机加快测试。例如个人第二次的bug中,关于合并同类项时判断错误的问题,如果能测试到位完全不用到了强测之后才得以被发现。

  3. 要充分利用讨论区,有好的思路应该分享,并及时发现讨论区中优秀的想法或者架构,必要时可以参考而进行重构

到全新的需求和问题时完全就是一脸茫然,刚开始的设计是最难的,也必须要为之后两次作业的扩展做好铺垫。而未经思考的下手往往会导致之后不必要的重构,因此为了设计的可扩展性,必须先有对整体的思考,然后再在构造时不断优化,如此才能提高效率。

  1. 写完代码后要充分进行测试,可以搭建评测机加快测试。例如个人第二次的bug中,关于合并同类项时判断错误的问题,如果能测试到位完全不用到了强测之后才得以被发现。

  2. 要充分利用讨论区,有好的思路应该分享,并及时发现讨论区中优秀的想法或者架构,必要时可以参考而进行重构

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Jinhua1121/article/details/136875007

智能推荐

如何配置DNS服务的正反向解析_dns反向解析-程序员宅基地

文章浏览阅读3k次,点赞3次,收藏13次。root@server ~]# vim /etc/named.rfc1912.zones #添加如下内容,也可直接更改模板。[root@server ~]# vim /etc/named.conf #打开主配置文件,将如下两处地方修改为。注意:ip地址必须反向书写,这里文件名需要和反向解析数据文件名相同。新建或者拷贝一份进行修改。nslookup命令。_dns反向解析

设置PWM占空比中TIM_SetCompare1,TIM_SetCompare2,TIM_SetCompare3,TIM_SetCompare4分别对应引脚和ADC通道对应引脚-程序员宅基地

文章浏览阅读2.5w次,点赞16次,收藏103次。这个函数TIM_SetCompare1,这个函数有四个,分别是TIM_SetCompare1,TIM_SetCompare2,TIM_SetCompare3,TIM_SetCompare4。位于CH1那一行的GPIO口使用TIM_SetCompare1这个函数,位于CH2那一行的GPIO口使用TIM_SetCompare2这个函数。使用stm32f103的除了tim6和tim7没有PWM..._tim_setcompare1

多线程_进程和线程,并发与并行,线程优先级,守护线程,实现线程的四种方式,线程周期;线程同步,线程中的锁,Lock类,死锁,生产者和消费者案例-程序员宅基地

文章浏览阅读950次,点赞33次,收藏19次。多线程_进程和线程,并发与并行,线程优先级,守护线程,实现线程的四种方式,线程周期;线程同步,线程中的锁,Lock类,死锁,生产者和消费者案例

在 Linux 系统的用户目录下安装 ifort 和 MKL 库并配置_在linux系统的用户目录下安装ifort和mkl库并配置-程序员宅基地

文章浏览阅读2.9k次。ifort 编译器的安装ifort 编译器可以在 intel 官网上下载。打开https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/fortran-compiler.html#gs.7iqrsm点击网页中下方处的 Download, 选择 Intel Fortran Compiler Classic and Intel Fortran Compiler(Beta) 下方对应的版本。我选择的是 l_在linux系统的用户目录下安装ifort和mkl库并配置

使用ftl文件生成图片中图片展示无样式,不显示_ftl格式pdf的样式调整-程序员宅基地

文章浏览阅读689次,点赞7次,收藏8次。些项目时需要一个生成图片的方法,我在网上找到比较方便且适合我去设置一些样式的生成方式之一就是使用Freemarker,在对应位置上先写好一个html格式的ftl文件,在对应位置用${参数名}填写上。还记得当时为了解决图片大小设置不上,搜索了好久资料,不记得是在哪看到的需要在里面使用width与height直接设置,而我当时用style去设置,怎么都不对。找不到,自己测试链接,准备将所有含有中文的图片链接复制一份,在服务器上存储一份不带中文的文件。突然发现就算无中文,有的链接也是打不开的。_ftl格式pdf的样式调整

orin Ubuntu 20.04 配置 Realsense-ROS_opt/ros/noetic/lib/nodelet/nodelet: symbol lookup -程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏12次。拉取librealsense。_opt/ros/noetic/lib/nodelet/nodelet: symbol lookup error: /home/admin07/reals

随便推点

操作系统精选习题——第四章_系统抖动现象的发生由什么引起的-程序员宅基地

文章浏览阅读3.4k次,点赞3次,收藏29次。一.单选题二.填空题三.判断题一.单选题静态链接是在( )进行的。A、编译某段程序时B、装入某段程序时C、紧凑时D、装入程序之前Pentium处理器(32位)最大可寻址的虚拟存储器地址空间为( )。A、由内存的容量而定B、4GC、2GD、1G分页系统中,主存分配的单位是( )。A、字节B、物理块C、作业D、段在段页式存储管理中,当执行一段程序时,至少访问()次内存。A、1B、2C、3D、4在分段管理中,( )。A、以段为单位分配,每._系统抖动现象的发生由什么引起的

UG NX 12零件工程图基础_ug-nx工程图-程序员宅基地

文章浏览阅读2.4k次。在实际的工作生产中,零件的加工制造一般都需要二维工程图来辅助设计。UG NX 的工程图主要是为了满足二维出图需要。在绘制工程图时,需要先确定所绘制图形要表达的内容,然后根据需要并按照视图的选择原则,绘制工程图的主视图、其他视图以及某些特殊视图,最后标注图形的尺寸、技术说明等信息,即可完成工程图的绘制。1.视图选择原则工程图合理的表达方案要综合运用各种表达方法,清晰完整地表达出零件的结构形状,并便于看图。确定工程图表达方案的一般步骤如下:口分析零件结构形状由于零件的结构形状以及加工位置或工作位置的不._ug-nx工程图

智能制造数字化工厂智慧供应链大数据解决方案(PPT)-程序员宅基地

文章浏览阅读920次,点赞29次,收藏18次。原文《智能制造数字化工厂智慧供应链大数据解决方案》PPT格式主要从智能制造数字化工厂智慧供应链大数据解决方案框架图、销量预测+S&OP大数据解决方案、计划统筹大数据解决方案、订单履约大数据解决方案、库存周转大数据解决方案、采购及供应商管理大数据模块、智慧工厂大数据解决方案、设备管理大数据解决方案、质量管理大数据解决方案、仓储物流与网络优化大数据解决方案、供应链决策分析大数据解决方案进行建设。适用于售前项目汇报、项目规划、领导汇报。

网络编程socket accept函数的理解_当在函数 'main' 中调用 'open_socket_accept'时.line: 8. con-程序员宅基地

文章浏览阅读2w次,点赞38次,收藏102次。在服务器端,socket()返回的套接字用于监听(listen)和接受(accept)客户端的连接请求。这个套接字不能用于与客户端之间发送和接收数据。 accept()接受一个客户端的连接请求,并返回一个新的套接字。所谓“新的”就是说这个套接字与socket()返回的用于监听和接受客户端的连接请求的套接字不是同一个套接字。与本次接受的客户端的通信是通过在这个新的套接字上发送和接收数_当在函数 'main' 中调用 'open_socket_accept'时.line: 8. connection request fa

C#对象销毁_c# 销毁对象及其所有引用-程序员宅基地

文章浏览阅读4.3k次。对象销毁对象销毁的标准语法Close和Stop何时销毁对象销毁对象时清除字段对象销毁的标准语法Framework在销毁对象的逻辑方面遵循一套规则,这些规则并不限用于.NET Framework或C#语言;这些规则的目的是定义一套便于使用的协议。这些协议如下:一旦销毁,对象不可恢复。对象不能被再次激活,调用对象的方法或者属性抛出ObjectDisposedException异常重复地调用对象的Disposal方法会导致错误如果一个可销毁对象x 包含或包装或处理另外一个可销毁对象y,那么x的Disp_c# 销毁对象及其所有引用

笔记-中项/高项学习期间的错题笔记1_大型设备可靠性测试可否拆解为几个部分进行测试-程序员宅基地

文章浏览阅读1.1w次。这是记录,在中项、高项过程中的错题笔记;https://www.zenwu.site/post/2b6d.html1. 信息系统的规划工具在制订计划时,可以利用PERT图和甘特图;访谈时,可以应用各种调查表和调查提纲;在确定各部门、各层管理人员的需求,梳理流程时,可以采用会谈和正式会议的方法。为把企业组织结构与企业过程联系起来,说明每个过程与组织的联系,指出过程决策人,可以采用建立过程/组织(Process/Organization,P/O)矩阵的方法。例如,一个简单的P/O矩阵示例,其中._大型设备可靠性测试可否拆解为几个部分进行测试