第一次Blog作业
前言
前三次题目集的情况
由于在开学前已经提前上过面向对象程序设计课程了,三次题目集的难度都在可接受范围内。对比三次题目集,可以看出来每次的题量在减少,但是每道题的难度在增加,总体而言难度也是不断增加的。伴随着难度增加,代码量也随之增加。
第一次题目集
对于第一次题目集,其实和上学期的C语言作业没什么区别,只不过换成java写而已,目的应该是让我们能从上学期的内容到这学期的内容有个过渡。题目所涉及的知识点基本是程序设计的基本语法和java所带类中的一些方法的使用。题量虽多,但是难度不大,基本没有涉及到面向对象的内容。
第二次题目集
相较于第一次题目集,第二次题目集开始有面向对象特有的内容了,对类和对象做出了考察。巧合的是,有几道题的需求是和日期的计算有关的,而在寒假里我做的C语言的课程设计就是日期工具,因此我在算法设计方面有我的课设供以借鉴。而且题目的需求并不高,对很小一段范围里的日期做出操作,我的课设计算的范围可以从公元1年到9999年,而题目只需要1820年到2020年范围内的计算,即使不允许用java中与日期有关的类或方法,难度也不大。由于设计类和方法来将代码模块化,并且java中有许多已经实现的方法可供使用,相对于面向过程的C语言,我能明显感觉到java在编程中更加地便利。
第三次题目集
第三次题目集题目比之前的更少,只有三道题,最难的是第三道题,也是花时间最长的。这次的题目明显是在考验我们对类的设计,是要求我们掌握类之间关系,和按不同类型来设计类。前两道题因为之前写过(第二道题基本上是题目集二的迭代,在上次日期计算的基础上以类来实现),所以比较轻松。而第三道题需要正则表达式的知识,还要从多项式表达式的字符串里提取出每一项,比较困难。很遗憾,代码的测试结果有一项不知为什么过不了,因此第三次题目集只拿了95分。
设计与分析
题目集一
7-7 对多个整数进行排序
类图

圈复杂度

7-8 判断三角形类型
类图

圈复杂度

只有一个主类一个主方法,一点都不面向对象=-=。
因为第一次题目集比较简单,而且当时也没有形成面向对象程序设计的思维,所以写出来的代码可能比较糟糕了。
题目集二
7-4 求下一天
类图

圈复杂度

因为不能允许用Java中和日期相关的类和方法,因此自己写了一个Date类。求下一天的大致思路就是先加一天份数,若大于当月最大天数就进位,以此类推,不是很难。在写题目时还没有圈复杂度的概念,判断每一年的天数就像以前一样用switch语句来判断,甚至还没有单独写成一个方法,代码的复用率低。判断日期是否合法也是通过if嵌套写的,因此圈复杂度较高。在了解到圈复杂度这个概念后,可以用数组来存储不同条件下的结果,简化代码的结构。
7-5 求前N天
类图

圈复杂度

这道题只是拓展了前一道题的功能,推算的天数不仅仅是一天了。思路也差不多,天份数减去N(-10 ≤ N ≤ 10) ,然后判断是否进位或者补一位。
题目集三
7-2 定义日期类
类图

圈复杂度

和上一次题目集第二题差不多,由于上一次我已经写了一个Date类,所以根据题目的要求改一改就拿过来用了。正好利用数组优化了一下代码的结构,相较于上次的圈复杂度有所降低。
7-3 一元多项式求导(类设计)
类图

圈复杂度

设计思路:利用正则表达式验证和处理多项式表达式,然后把每一项拆分开,提取出系数和指数,最后分别求导输出。
这次的代码相较于之前结构更清晰,根据类的类型设计了实体类:Expression(表达式),Term(多项式的项)以及业务类:Translation(提取表达式中的项)。
踩坑心得
比较两个浮点数
在第一次题目集 7-8 需要判断三角形三条边是否满足勾股定理,以此来判断是否为直角三角形。最开始我是用如下语句来判断是否满足:
if (a * a + b * b == c * c)
但是一直有一个测试点过不去,测试了半天也没找到问题,直到有一次输入了一组直角三角形的数据才将问题锁定在了这个判断条件上,这才想起浮点数的运算可能会产生误差,用 == 比较是会出现问题的,因此需要改成如下语句:
Math.abs(a * a + b * b - c * c) < 0.0001
符号右边的数字控制精度,但是题目中并没有给出精度,我认为题目还存在一些缺陷。
输入
在分别读入以换行符为分隔的一个整型数和一段字符串时,如果仅用如下代码:
1 import java.util.Scanner; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Scanner input = new Scanner(System.in); 7 int a = 0; 8 String str; 9 10 System.out.print("输入一个数字:"); 11 a = input.nextInt(); 12 System.out.print("输入一个字符串:"); 13 str = input.nextLine(); 14 15 System.out.println(); 16 System.out.println("a = " + a); 17 System.out.println("str = " + str); 18 } 19 20 }
我们输入一个数并按回车后再输入一个字符串,得到如下结果:

好吧,其实还没有输入字符串就出结果了。
可以看出str中实际上什么都没有。但是如果在c语言中写类似的语句:
1 #include <stdio.h> 2 3 int main () { 4 int a = 0; 5 char ch[1000] = ""; 6 7 scanf ("%d", &a); 8 scanf ("%s", ch); 9 10 printf("a = %d \nb = %s", a, ch); 11 12 return 0; 13 }
结果却是正常的:

正是因为之前c语言的习惯,导致出现这个问题时我是一脸懵逼的。随后去网上查阅相关问题时才发现,原来在读取整型数时结束的标志是空白符,但是不会读掉这个空白符而是将它留在缓冲区,而用nextLine()读取字符串时结束的标志是\r(回车)并且会读掉这个回车符,因此才出现了这样的问题。
于是我们可以想办法把回车符读掉:
1 import java.util.Scanner; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Scanner input = new Scanner(System.in); 7 int a = 0; 8 String str1, str2; 9 10 System.out.print("输入一个数字:"); 11 a = input.nextInt(); 12 input.nextLine(); 13 System.out.print("输入一个字符串:"); 14 str1 = input.nextLine(); 15 System.out.print("输入一个字符串:"); 16 str2 = input.nextLine(); 17 18 System.out.println(); 19 System.out.println("a = " + a); 20 System.out.println("str1 = " + str1 + ";"); 21 System.out.println("str2 = " + str2); 22 } 23 24 }
得到正常结果:

改进方法
以面向对象程序设计思维来设计程序
第一次题目集的代码都很不面向对象,不过好在题目简单。而在第三次题目集时题目难度增大,再用原来的老方法是很难行得通的,因此要利用面向对象程序设计思维来将代码,增强代码的可读性和维护性。
降低圈复杂度
从两次日期计算题目的代码可以看出,圈复杂度其实也能在一定程度上反映出代码的可读性。
改进前:

改进后:(功能不全相同, mon_maxnum[]数组保存每月的天数)

总结
从前三次题目集中其实我学到了许多,虽然我曾是一名oier(长达两个月...),可以很轻松应付上个学期程序设计基础的学习,但是面向对象程序设计确实我未曾接触过的全新领域。之前虽有所了解,可是只有真正动手去实践才能发现其中的奥妙,现在回去看寒假里c语言课设的代码能明显感受到还是现在的写代码看着舒服。
java作为一个功能齐全的语言,确实给编程来了了极大的便利。比如正则表达式,只需一段表达式就能完成我之前费大力气才实现的字符串匹配功能,以及foreach循环能够方便便利数组,还有许多自带的方法可以提高编程的效率。

浙公网安备 33010602011771号