经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
OOP作业总结(一)
来源:cnblogs  作者:impJ  时间:2021/4/6 10:20:30  对本文有异议

关于OOP第一阶段的作业总结

阅读提示:本文目录导航,PC端页面位于文章右侧,移动端点击文章标题右侧小图标,需下滑后(顶部图片消失)目录才完全显示,可根据目录跳转文章位置。

点击跳转至本文唯一价值 也可能没有价值(雾 其他的都是在完成学校任务,基本语法没什么好总结的

一、前言

以下题目来源PTA题目集1-3,基本为Java的基本语法及一点面向对象的思想。

  • 知识点:Java基本语法(没什么好讲的)正则表达式
  • 题量:适中
  • 难度:除题目集7-3 一元多项式求导 无

二、设计与分析

1. 题目集一

7-8 判断三角形类型(20 分)

输入三角形三条边,判断该三角形为什么类型的三角形。

输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。

输出格式:
(1)如果输入数据非法,则输出“Wrong Format”; (2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”; (3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”; (3)如果输入数据合法且能够成等腰直角三角形,则输出“Isosceles right-angled triangle”; (5)如果输入数据合法且能够成等腰三角形,则输出“Isosceles triangle”; (6)如果输入数据合法且能够成直角三角形,则输出“Right-angled triangle”; (7)如果输入数据合法且能够成一般三角形,则输出“General triangle”。

分析与心得: 先给输入的三条边排好序,可以减少很多判断。 使用\(x^2 + y^2 = z^2\)判断直角三角形时,若为浮点数会出现浮点误差无法相等。如\(\sqrt2\), 则差在精度范围内即可认为相等。

核心代码:

        Arrays.sort(arr);
        final double EPS = 1e-5;//写-8 不行 这精度卡的。。。
        if (arr[0] < 1 || arr[2] > 200)
            System.out.print("Wrong Format");
        else if (arr[0] + arr[1] <= arr[2]) 
            System.out.print("Not a triangle");//wow 看错题了,还以为和上一行输出一样
        else if (arr[0] == arr[1] && arr[1] == arr[2])
            System.out.print("Equilateral triangle");
        else if (arr[0] == arr[1] || arr[1] == arr[2]) {
            if (Math.abs(arr[0] * arr[0] + arr[1] * arr[1] - arr[2] * arr[2]) <= EPS)//卡精度??????
                System.out.print("Isosceles right-angled triangle");
            else
                System.out.print("Isosceles triangle");
        } else if (Math.abs(arr[0] * arr[0] + arr[1] * arr[1] - arr[2] * arr[2]) <= EPS)
            System.out.print("Right-angled triangle");
        else
            System.out.print("General triangle");

2. 题目集二

7-4 求下一天 (30 分)
输入年月日的值(均为整型数),输出该日期的下一天。 其中:年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法。

要求:Main类中必须含有如下方法,签名如下:

public static void main(String[] args);//主方法 
public static boolean isLeapYear(int year) ;//判断year是否为闰年,返回boolean类型 
public static boolean checkInputValidity(int year,int month,int day);//判断输入日期是否合法,返回布尔值
public static void nextDate(int year,int month,int day) ; //求输入日期的下一天

输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。

输出格式:
当输入数据非法及输入日期不存在时,输出“Wrong Format”;
当输入日期合法,输出下一天,格式如下:Next date is:年-月-日
分析与心得: 注意各月的天数需严格符合实际,求下一天时注意边界进制。
核心代码:

public static void nextDate() {
        int[] monthDay = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        if (isLeapYear(year))
            monthDay[2]++;
        if (day < monthDay[month])
            day++;
        else if (day == monthDay[month] && month < 12) {
            month++;
            day = 1;
        } else if (day == monthDay[month] && month == 12) {
            year++;
            month = 1;
            day = 1;
        }
    }

7-5 求前N天 (30 分)
输入年月日的值(均为整型数),同时输入一个取值范围在[-10,10] 之间的整型数n,输出该日期的前n天(当n > 0时)、该日期的后n天(当n<0时)。 其中年份取值范围为 [1820,2020] ,月份取值范围为[1,12] ,日期取值范围为[1,31] 。 注意:不允许使用Java中任何与日期有关的类或方法。

输入格式:
在一行中输入年月日的值以及n的值,可以用一个或多个空格或回车分隔。

输出格式:
当输入的年、月、日以及n的值非法时,输出“Wrong Format”;
当输入数据合法时,输出“n days ago is:年-月-日”
分析与心得: 注意各月的天数需严格符合实际,求前n天时注意边界进制,跨月。
核心代码:

public static void beforeDate(int n) {
        int[] monthDay = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        if (isLeapYear(year))
            monthDay[2]++;
        if ((day - n) <= monthDay[month] && (day - n) >= 1) {
            day = day - n;
        } else if ((day - n) > monthDay[month] && month < 12) {
            day = day - n - monthDay[month];
            month++;
        } else if ((day - n) < 1 && month > 1) {
            month--;
            day = day - n + monthDay[month];
        } else if ((day - n) > monthDay[month] && month == 12) {
            day = day - n - monthDay[month];
            month = 1;
            year++;
        } else if ((day - n) < 1 && month == 1) {
            month = 12;
            day = day - n + monthDay[month];
            year--;
        }
    }

3. 题目集三

7-2 定义日期类 (28 分)
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。 注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。

要求:Date类结构如下图所示:
类图

输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。

输出格式:
当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
当输入日期合法,输出下一天,格式如下:Next day is:年-月-日

分析与心得: 注意类的设计,开始有一点面向对象了。同样需要注意边界控制和进制处理。
核心代码:

class Date {
    private int year;
    private int month;
    private int day;
    private int[] mon_maxnum = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

    Date() {

    }

    Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public boolean isLeapYear(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
            return true;
        else
            return false;
    }

    public boolean checkInputValidity() {
        if (year < 1900 || year > 2000 || month < 1 || month > 12 || day < 1 || day > 31) {
            return false;
        }
        if (month == 2) {
            if (isLeapYear(year) && day > 29) {
                return false;
            }
            else if(!isLeapYear(year) && day > 28)
                return false;
        }
        if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) {
            return false;
        }
        return true;
    }

    public void getNextDate() {
        if (isLeapYear(year))
            mon_maxnum[2]++;
        if (day < mon_maxnum[month])
            day++;
        else if (day == mon_maxnum[month] && month < 12) {
            month++;
            day = 1;
        } else if (day == mon_maxnum[month] && month == 12) {
            year++;
            month = 1;
            day = 1;
        }
    }
}

本文唯一价值。


7-3 一元多项式求导(类设计) (50 分)
编写程序性,实现对简单多项式的导函数进行求解。详见作业指导书。

OO作业3-3题目说明.pdf
输入格式:
在一行内输入一个待计算导函数的表达式,以回车符结束。

输出格式:
如果输入表达式不符合上述表达式基本规则,则输出“Wrong Format”。
如果输入合法,则在一行内正常输出该表达式的导函数,注意以下几点: 结果不需要排序,也不需要化简;
当某一项为“0”时,则该项不需要显示,但如果整个导函数结果为“0”时,则显示为“0”;
当输出结果第一项系数符号为“+”时,不输出“+”;
当指数符号为“+”时,不输出“+”;
当指数值为“0”时,则不需要输出“x^0”,只需要输出其系数即可。
输出格式见输入输出示例。

输入样例1:
在这里给出一组输入。例如:

-2*      x^-2+  5*x^12-4*x+       12

输出样例1:
在这里给出相应的输出。例如:

4*x^-3+60*x^11-4

输入样例2:
在这里给出一组输入。例如:

2*x^6-0*x^7+5

输出样例2:
在这里给出相应的输出。例如:

Wrong Format

分析与心得:

本题前置知识正则表达式了解个大概的基础语法就行

求导大家高中都学过,对于幂函数(本题只有幂函数及常数),无非就三个部分,系数,底数,指数。(博客园的\(\LaTeX\)支持还行)

\[\begin{cases} 新系数 = 旧系数 \times 旧指数\新指数 = 旧指数 - 1\\ \end{cases} \]

所以,我们对于表达式的每一项提取出该项的系数和指数。
根据系数和指数的位置改进正则表达式如下:(当时我正则表达式调了挺久)

先把字符串内的空格都去了:
String express = initExpress.replaceAll("\\s", "");

当指数和系数都存在(指不为 1 的其他数字 下同):
[+-]?[0-9]+\\*x\\^[+-]?[0-9]+ 这种表达式能匹配上诸如 -5*x^15 类型。

兼容无前导0,就是数字不能0开头,(这个pdf说明内有要求,但我看有些同学没考虑这也过了,建议加强测试数据):
[+-]?[1-9][0-9]*\\*x\\^[+-]?[1-9][0-9]* 诸如09*x^02 就无法匹配上。

兼容系数不存在:
([+-]?[1-9][0-9]*)?\\*?x\\^[+-]?[1-9][0-9]*-x^5

兼容指数不存在:
([+-]?[1-9][0-9]*)?\\*?x(\\^[+-]?[1-9][0-9]*)?-x

兼容常数项:
([+-]?[1-9][0-9]*)?(\\*?x(\\^[+-]?[1-9][0-9]*)?)? 如445544

给指数部分加上()方便提取:
([+-]?[1-9][0-9]*)?(\\*?x(\\^([+-]?[1-9][0-9]*))?)?

提取使用group(index),index为第几个括号
如group(1)得到的就是系数部分,即匹配([+-]?[1-9][0-9]*)的部分。
group(4)得到指数部分,即匹配([+-]?[1-9][0-9]*)的部分。

有大数数据类型要使用BigInteger

完整的用来匹配项的正则表达式:
String termExpress = "([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?";

那么多项表达式(表达式由项组成)及
String wholeExpress = "(([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?)+";
能匹配则表达式合法:

public boolean check() {
        return Pattern.matches(wholeExpress, express);
}

hack数据及其他详见踩坑心得

deadline驱动,未经检查,欢迎指正错误。

完整代码:

//并非AC代码,测试点测试数据有误,AC需第88行(如果没修正的话)。
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String initExpress = input.nextLine();
        String express = initExpress.replaceAll("\\s", "");
        Express textExpress = new Express(express);
        if (textExpress.check())
            textExpress.show();
        else
            System.out.println("Wrong Format");
    }
}

class Express {
    private String express;
    private String term;
    private String ratStr;// 系数部分
    private String indexStr;// 指数部分
    private BigInteger rat;
    private BigInteger index;
    private ArrayList<String> containTerm = new ArrayList<>();

    public Express(String express) {
        this.express = express;
    }

    String termExpress = "([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?";
    String wholeExpress = "(([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?)+";
    String constNum = "[+-]?[0-9]+";
    public boolean check() {
        return Pattern.matches(wholeExpress, express);
    }

    public void show() {
        if (Pattern.matches(constNum, express)) {
            System.out.println("0");
            System.exit(0);
        }
        Pattern p = Pattern.compile(termExpress);
        Matcher m = p.matcher(express);
        int flag = 0;
        while (m.find()) {
            //System.out.println(m.group(2));
            ratStr = m.group(1);
            indexStr = m.group(4);
            if (ratStr != null) {
                rat = new BigInteger(ratStr);
                if (m.group(2) != null && m.group(2).startsWith("-")) {
                    rat = BigInteger.valueOf(-1);
                    //System.out.println(rat);
                }
                else if (m.group(2) != null && m.group(2).startsWith("+")) {
                    rat = BigInteger.valueOf(1);
                    //System.out.println(rat);
                }
            } else {
                rat = BigInteger.valueOf(1);
                if (m.group() != null && m.group().startsWith("-")) {
                    rat = BigInteger.valueOf(-1);
                    //System.out.println(rat);
                }
                else if (m.group() != null && m.group().startsWith("+")) {
                    rat = BigInteger.valueOf(1);
                    //System.out.println(rat);
                }
            }
            if (indexStr != null) {
                index = new BigInteger(indexStr);
                rat = rat.multiply(index);
                index = index.subtract(new BigInteger("1"));
                if (rat.compareTo(new BigInteger("0")) > 0 && flag == 1)
                    System.out.print("+" + (rat.equals(new BigInteger("-1")) ? "-x" : rat + "*x") + (index.equals(new BigInteger("1")) ? "" : ("^" + index)));
                else {
                    flag = 1;
                    System.out.print((rat.equals(new BigInteger("-1")) ? "-x" : rat + "*x") + (index.equals(new BigInteger("1")) ? "" : ("^" + index)));
                }
            } else if (m.group(2) != null) {
                if(flag == 1 && rat.compareTo(new BigInteger("0")) > 0)
                    System.out.print("+"+rat);
                    ////emmmmmmmmmmmmmmmmmmmmmmm
                    //测试点数据错误........................................
                    //System.out.print(rat);
                else{
                    flag = 1;
                    System.out.print(rat);
                }
            }
        }
    }
}

三、踩坑心得

题目集7-3 一元多项式求导

踩坑完善过程部分可见 设计与分析

特殊数据考虑不完善

hack数据1:

\(5-x\)

正确输出:

\(-1\)

hack数据2:

2-x^2

正确输出:

\(-2x\)

hack数据3:

-x^

正确输出:

\(Wrong \quad Format\)

hack数据4:

-x ^-1

正确输出:

x^-2

一直没满分,一直捏数据hack自己,确实完善了一些特殊情况。

\(\frac{写题时间}{hack时间} = \frac{2}{8}\)

提交记录

但一直过不了最后一个点。

结果发现是最后一个测试点的测试数据有误。

求完导后,如果答案项系数为+ 且不是第一项应该在前面输出 + 号。

如5*x^4+4*x^5

带+
答案: 20x^3+20x^4

不带+
答案: 20x^320x^4

对于+是否输出
该测试点: \(输出× \quad 不输出√\) ??

具体请见上文完整代码第85行和第88行(测试点85行错 88行对)

四、改进建议

对于题目集三一元多项式求导,仍有太多面向过程的做法,冗余代码过多,复用性低,不利于后期跟进维护。

优化:设计项类,将表达式分解成项,对项进行处理,使用 HashMap建立映射关系,利于运算,利于合并同类项(本题降低了难度并未涉及),降低程序耦合度。

五、总结

学到了什么:通过本阶段的学习,练习了Java的基本语法,了解了面向对象的思想,练习了正则表达式的使用。
进一步学习:不停留在基本语法,开始了解各种开发框架和管理工具。
课程建议:课程自由度高,给学生充分的自学时间,作业循序渐进,梯度适中,无需要改进的地方。
另:关于题目集三最后一题<一元多项式求导>最后一个测试点测试数据有误,望修改,建议加强测试数据,详见测试数据出锅分析
分析与设计

原文链接:http://www.cnblogs.com/impJ/p/OOP01.html

 友情链接: NPS