南昌航空大学BLOG-1

发布时间 2023-04-01 22:10:41作者: 薛之谦冒险历程cloud

一、前言:

通过面向对象程序设计这门课程开展了关于Java这门语言的学习。至今,已经完成了三次PTA 的大作业,这三次大作业主要围绕Java的结构,类的使用,还有一些函数的知识,但主要还是类的使用。三次作业的难度是循序渐进的,作业量也是逐渐增加。以下是对这三次PTA作业的概要分析。

二、设计与分析:

PTA第一次:

在该次作业中共有9道习题,但大多数都为一个C语言向Java过渡的历程,在学习了Java的基本结构都可以完成,因为其中一些知识的运用和C语言相差不大,因此得分也为100分。其中我将主要分析7-8巴比伦法求平方根近似值和7-7判断三角形类型。

 

7-8 巴比伦法求平方根近似值
分数 10
作者 蔡轲
单位 南昌航空大学

巴比伦法求n的近似值可以用以下公式:
nextGuess = (lastGuess+n/lastGuess)/2
程序初始运行时lastGuess可赋予一个最初的猜测值。当由公式求得的nextGuess和lastGuess相差较大时,把nextGuess的值赋给lastGuess,继续以上过程,直至nextGuess和lastGuess几乎相同,此时lastGuess或者nextGuess就是平方根的近似值。
本题要求:nextGuess和lastGuess的差值小于0.00001时认为两者几乎相同

输入格式:

1、两个浮点数,以空格分隔,第一个是n,第二个是lastGuess最初的猜测值。例如:2 1。
2、若输入的两个数中包含负数或者lastGuess初始输入为0,认定为非法输入

输出格式:

1、输出n的平方根近似值:lastGuess。例如:1.4142157
2、非法输入时输出:"Wrong Format"

输入样例:

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

2 1
 

输出样例:

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

1.4142157
 

输入样例1:

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

2 -1
 

输出样例:

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

Wrong Format
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.Scanner;
public class Main
{
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        float n = input.nextFloat();
        float lG = input.nextFloat();
        float nG = (lG+n/lG)/2;
        float c = nG - lG;
        if(n<0||lG<=0)
        {
            System.out.print("Wrong Format");
            return ;
        }
        while(Math.abs(c)>=0.00001)
        {
            lG = nG;
            nG = (lG+n/lG)/2;
            c = nG - lG;
        }
        System.out.print((float)(lG));
    }
}

分析:这道题我的错误点在与一个数据类型的运用。就是float和double之间的差别,这两者的精准度不同,我最开始用double测试多次,发现可能不是方法的错误,应该是定义时没有考虑到题目中这个0.00001的这个精准度,在我更换float型后,通过了测试。

 

7-7 判断三角形类型
分数 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”。

输入样例1:

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

50 50 50.0
 

输出样例1:

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

Equilateral triangle
 

输入样例2:

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

60.2 60.2 80.56
 

输出样例2:

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

Isosceles triangle
 

输入样例3:

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

0.5 20.5 80
 

输出样例3:

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

Wrong Format
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.Scanner;
public class Main
{
    public static void main(String[] args)
    {
      Scanner in = new Scanner(System.in);
      float a = in.nextFloat();
      float b = in.nextFloat();
      float c = in.nextFloat();
      if((a<1||b<1||c<1)||(a>200||b>200||c>200))//非法数值
      {
          System.out.println("Wrong Format");
          return ;
      }
         else if((a+b>c)&&(a+c>b)&&(c+b>a))
        {
              if(a==b&&a==c)
            {
            System.out.println("Equilateral triangle");
             return ;
            }
           else if((a==b)&&(Math.pow(a,2)+Math.pow(b,2)-Math.pow(c,2)<0.00001))
            {
                System.out.println("Isosceles right-angled triangle");
                return ;
            }
             else if((a==c)&&(Math.pow(a,2)+Math.pow(c,2)-Math.pow(b,2)<0.00001))
             {
                 System.out.println("Isosceles right-angled triangle");
                return ;
             }
             else if((b==c)&&(Math.pow(b,2)+Math.pow(c,2)-Math.pow(a,2)<0.00001))
             {
                 System.out.println("Isosceles right-angled triangle");
                return ;
             }
             else if(a==b||a==c||c==b)
             {
                 System.out.println("Isosceles triangle");
                 return ;
             }
             else if(Math.pow(a,2)+Math.pow(c,2)-Math.pow(b,2)<0.00001)
             {
                 System.out.println("Right-angled triangle");
                 return ;
             }
             else if(Math.pow(a,2)+Math.pow(b,2)-Math.pow(c,2)<0.00001)
             {
                 System.out.println("Right-angled triangle");
                 return ;
             }
             else if(Math.pow(b,2)+Math.pow(c,2)-Math.pow(a,2)<0.00001)
             {
                 System.out.println("Right-angled triangle");
                 return ;
             }
             System.out.println("General triangle");
             return ;
        }
        else 
            System.out.println("Not a triangle");
    }
}

 

分析:

这题主要是一个思路的清晰度,因为判断三角形类型包括先判断是否还是直接判断类型,这个思路理清楚就没有问题。当然这其中还有Math类的一些使用。

 

PTA第二次:

第二次中共有四道题目,虽然数量不达第一次的一半,但需要去真正的在作业中运用类、方法等的使用,难度也比第一次上升了一倍不止。但是在这次作业中,我对类、方法等这些的理解使用并不理想,因此本次的分数险过及格线。接下来我会比较详细分析7-1 菜单计价程序-1、7-2 菜单计价程序-2、7-3 jmu-java-日期类的基本使用。第四题主要是一个算法的计算,就不在这展开分析了。

 

7-3 jmu-java-日期类的基本使用
分数 15
作者 郑如滨
单位 集美大学
  1. 给定一个日期,判定是否为合法日期。如果合法,判断该年是否闰年,该日期是当年第几天、当月第几天、当周第几天、。
  2. 给定起始日期与结束日期,判定日期是否合法且结束日期是否早于起始日期。如果均合法,输出结束日期与起始日期之间的相差的天数、月数、念书。

输入格式:

第一行输入一个日期字符串,格式为"YYYY-MM-dd"
第二行输入两个日期字符串,中间使用空格隔开。分别代表开始日期与结束日期。

输出格式:

如果第一行日期字符串非法,输出自定义的错误信息。
如果第一行日期有效,输出相关信息,如果是闰年要输出是闰年。
如果第二行两个日期,只要有一个无效。就输出相关错误信息。
如果第二行两个日期有效且结束日期不早于开始日期,输出相关信息。

输入样例1:

第一行日期非法、第二行有日期非法

2020-02-30
2020-02-30 2020-01-02
 

输出样例1:

2020-02-30无效!
2020-02-30或2020-01-02中有不合法的日期.
 

输入样例2:

均有效且合法

2021-02-28
2019-08-01 2020-01-02
 

输出样例2:

2021-02-28是当年第59天,当月第28天,当周第7天.
2020-01-02与2019-08-01之间相差154天,所在月份相差-7,所在年份相差1.
 

输入样例3:

日期均有效,但结束日期早于开始日期

2020-02-28
2020-02-02 2020-02-01
 

输出样例3:

2020-02-28是闰年.
2020-02-28是当年第59天,当月第28天,当周第5天.
2020-02-01早于2020-02-02,不合法!
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
 
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Scanner;

public class Main {

public interface DateValidator { boolean isValid(String dateStr); } public static class DateValidatorUsingDateFormat implements DateValidator { private String dateFormat; public DateValidatorUsingDateFormat(String dateFormat) { this.dateFormat = dateFormat; } public boolean isValid(String dateStr) { DateFormat sdf = new SimpleDateFormat(this.dateFormat); sdf.setLenient(false); try { sdf.parse(dateStr);
            } catch (ParseException e) {
                return false; 
            }
            return true;
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in); 
        String inputDate = in.nextLine(); 

        DateValidator validator = new DateValidatorUsingDateFormat("yyyy-MM-dd");、

        if (validator.isValid(inputDate)) { 
            LocalDate date = LocalDate.parse(inputDate, DateTimeFormatter.ISO_LOCAL_DATE); 

            boolean isLeapYear = date.isLeapYear(); 
            if (isLeapYear) {
                System.out.println(inputDate + "是闰年."); 
            }
           
            int dayOfYear = date.getDayOfYear(); 
            int dayOfMonth = date.getDayOfMonth();
            int dayOfWeek = date.getDayOfWeek().getValue(); 
            System.out.println(inputDate+"是当年第"+dayOfYear+"天,当月第"+dayOfMonth+"天,当周第"+dayOfWeek+"天.");

        } else {
            System.out.println(inputDate + "无效!"); 
        }
        String inputDates = in.nextLine(); 

        String[] dates = inputDates.split(" "); 

        String startDateStr = dates[0]; 
        String endDateStr = dates[1];

        if (validator.isValid(startDateStr) && validator.isValid(endDateStr)) { 
            LocalDate startDate = LocalDate.parse(startDateStr, DateTimeFormatter.ISO_LOCAL_DATE); 
            LocalDate endDate = LocalDate.parse(endDateStr, DateTimeFormatter.ISO_LOCAL_DATE); 
            if (endDate.isBefore(startDate)) { 
                System.out.println(endDateStr + "早于" + startDateStr + ",不合法!");
                return;
            }
            long days = ChronoUnit.DAYS.between(startDate, endDate);
            long months = ChronoUnit.MONTHS.between(startDate, endDate);
            long years = ChronoUnit.YEARS.between(startDate, endDate);
            System.out.println(endDateStr + "与" + startDateStr + "之间相差" + days + "天,所在月份相差" + (months-12) + ",所在年份相差" + years + "."); 

        } else {
            System.out.println(startDateStr + "或" + endDateStr + "中有不合法的日期."); 
        }

        in.close();
    }
}

 

 

分析:

首先先说明一下第三题。这道题我得了三分,测试是有答案错误,非零返回,运行超时这三个错误。因为在运行测试时能够获取到对应的输出,因此答案错误和运行超时出乎我意料的错误。运行超时在我这道题中的原因大概有两个,一个是:程序中存在死循环,无限递归这种;另外一个是:程序设计问题:程序设计不合理,算法复杂度过高,导致程序运行缓慢或超时。然后观察我的代码,就是简单的东西复杂化了,答案错误是由于部分方法的顺序出现了问题。非零返回:非零返回通常表示方法执行出错或异常,

  1. 方法执行出错,例如参数错误、空指针异常等;
  2. 方法执行过程中发生异常,例如数组下标越界、文件读取错误等;
  3. 方法执行被中断,例如线程被强制终止等;
  4. 方法返回非零值是为了表明某种特定的状态或结果,例如某些系统调用返回值为非零表示执行成功。 

在根据原因去调试后。我在eclipse也运行出了答案。

 

7-1 菜单计价程序-1
分数 30
作者 蔡轲
单位 南昌航空大学

某饭店提供4种菜,每种菜品的基础价格如下:
西红柿炒蛋 15
清炒土豆丝 12
麻婆豆腐 12
油淋生菜 9

设计点菜计价程序,根据输入的订单,计算并输出总价格。
订单由一条或多条点菜记录组成,每条记录一行,最后以"end"结束
每条点菜记录包含:菜名、份额两个信息。
份额可选项包括:1、2、3,分别代表小、中、大份)

不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格
2。
如果计算出现小数,按四舍五入的规则进行处理。

参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
}

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
}

点菜记录类:保存订单上的一道菜品记录
Record {
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格
}

订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(String dishName,int portion)
//添加一条菜品信息到订单中。
}

输入格式:

每条点菜记录的格式:
菜名+空格(英文)+份额
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
最后一条记录以“end”结束。

输出格式:

订单上所有菜品的总价(整数数值),每份菜
如果订单中包含不能识别的菜名,则在总价之前输出“** does not exist”,**是不能识别的菜名

输入样例:

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

麻婆豆腐 2
西红柿炒蛋 3
end
 

输出样例:

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

48
 

输入样例1:

订单中包含不存在的菜品记录。例如:

麻婆豆腐 2
炒脆肚 2
西红柿炒蛋 3
end
 

输出样例1:

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

炒脆肚 does not exist
48
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 M
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Order order = new Order(); 
        Scanner sc = new Scanner(System.in); 
        String line = sc.nextLine(); 
        while (!line.equals("end")) { 
            String[] parts = line.split(" "); 
            if (parts.length == 2) {
                String dishName = parts[0]; 
                int portion = Integer.parseInt(parts[1]); 
                order.addARecord(dishName, portion); 
            } else { 
                System.out.println("Invalid input");
            }
            line = sc.nextLine();
        }
        sc.close(); 

        int totalPrice = order.getTotalPrice(); 
        System.out.println(totalPrice); 

    }
}

class Dish{
    String name;
    int unit_price;

    public Dish(String name, int unit_price) {
        this.name = name;
        this.unit_price = unit_price;
    }

    int getPrice(int portion){
        switch (portion){
            case 1:{
                return unit_price;
            }
            case 2:{
                return (int) Math.round(unit_price * 1.5);
            }
            case 3:{
                return unit_price*2;
            }
        }
        return 0;
    }
}

class Menu{
    Dish[] dishs;

    public Menu() {
        dishs=new Dish[4];
        Dish dish1 = new Dish("西红柿炒蛋", 15);
        Dish dish2 = new Dish("清炒土豆丝", 12);
        Dish dish3 = new Dish("麻婆豆腐", 12);
        Dish dish4 = new Dish("油淋生菜", 9);
        dishs[0]=dish1;
        dishs[1]=dish2;
        dishs[2]=dish3;
        dishs[3]=dish4;
    }

    public Dish searchDish(String dishName){
        for (Dish dish : dishs) {
            if (dish.name.equals(dishName))
                return dish;
        }
        return null;
    }
}

class Record{
    Dish d;
    int portion;
    public Record(Dish d, int portion) {
        this.d = d;
        this.portion = portion;
    }
    public int getPrice(){
        return d.getPrice(portion);
    }
}

class Order{
    Record[] records;
    int size;

    public Order() {
        records=new Record[10];
        size=0;
    }

    int getTotalPrice(){
        int total=0;
        for (int i = 0; i < size; i++) {
            total+=records[i].getPrice();
        }
        return total;
    }
    Record addARecord(String dishName,int portion){
        Menu menu = new Menu();
        Dish dish = menu.searchDish(dishName);
        if(dish != null){
            Record record = new Record(dish,portion);
            records[size++] = record;
            return record;
        }else{
            System.out.println(dishName + " does not exist");
            return null;
        }
    }
}

 

 

分析:最开始,因为类、方法这些我个人的能力问题,所以最开始使用了面向过程的方法(博客中展示的是后面改进的面向对象的代码),在我从面向过程到面向对象,主要就是类在代码中的运用,包括分成Dish{},Mune{},Record{},Order{}这些。我倾向于理解为拆分的一个过程,但其实有些主要的算法其实在这道题里差别不是很大,主要都是输入选择的判断和一个equals()的使用。在写出这个题目大概对类的使用更熟悉包括使用这个equals()这个函数的使用去了解这个函数的用法。

 

7-2 菜单计价程序-2
分数 40
作者 蔡轲
单位 南昌航空大学

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。


订单分:点菜记录和删除信息。每一类信息都可包含一条或多条记录,每条记录一行。
点菜记录包含:序号、菜名、份额、份数。
份额可选项包括:1、2、3,分别代表小、中、大份。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格
2。
如果计算出现小数,按四舍五入的规则进行处理。

参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。

Dish {    
   String name;//菜品名称    
   int unit_price;    //单价    
   int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)    }
 

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

 
Menu {
   Dish[] dishs ;//菜品数组,保存所有菜品信息
   Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
   Dish addDish(String dishName,int unit_price)//添加一道菜品信息
}
 

点菜记录类:保存订单上的一道菜品记录

 
Record {
   int orderNum;//序号\
   Dish d;//菜品\
   int portion;//份额(1/2/3代表小/中/大份)\
   int getPrice()//计价,计算本条记录的价格\
}
 

订单类:保存用户点的所有菜的信息。

Order {
   Record[] records;//保存订单上每一道的记录
   int getTotalPrice()//计算订单的总价
   Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
   delARecordByOrderNum(int orderNum)//根据序号删除一条记录
   findRecordByNum(int orderNum)//根据序号查找一条记录
}
 

输入格式:

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:
序号+英文空格+菜名+英文空格+份额+英文空格+份数
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete


最后一条记录以“end”结束。

输出格式:

按顺序输出每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。
如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后输出订单上所有菜品的总价(整数数值),

本次题目不考虑其他错误情况,如:菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的下一次作业中会做要求。

输入样例:

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

麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
end
 

输出样例:

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

1 麻婆豆腐 36
2 油淋生菜 27
63
 

输入样例1:

订单中包含删除记录。例如:

麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
 

输出样例1:

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

1 麻婆豆腐 36
2 油淋生菜 27
27
 

输入样例2:

订单中包含不存在的菜品记录。例如:

麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
end
 

输出样例2:

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

1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
63
 

输入样例3:

订单中包含删除信息以及不存在的菜品记录。例如:

麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
1 delete
7 delete
end
 

输出样例3:

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

1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
27
 

输入样例4:

订单中包含删除信息以及不存在的菜品记录。例如:

麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
5 delete
7 delete
end
 

输出样例4:

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

1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
delete error;
63
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Menu menu=new Menu();
        Order order=new Order();
        String line = sc.nextLine(); //读取一行输入
        while (!line.equals("end")) { //如果输入不是"end"
            String[] parts = line.split(" "); //按空格分割输入
            if(parts.length==4){
                order.addARecord(Integer.parseInt(parts[0]),parts[1],Integer.parseInt(parts[2]),Integer.parseInt(parts[3]),menu);
            }
            if(parts.length==2){
                if(Character.isDigit(parts[0].toCharArray()[0])){
                    order.delARecordByOrderNum(Integer.parseInt(parts[0]));
                }else {
                    menu.addDish(parts[0],Integer.parseInt(parts[1]));
                }
            }
            line = sc.nextLine(); //读取下一行输入
        }
        order.print();
        int totalPrice = order.getTotalPrice(); //计算订单总价
        System.out.println(totalPrice); //输出总价
    }
}
class Dish {
    String name;
    int unit_price;

    public Dish(String name, int unit_price) {
        this.name = name;
        this.unit_price = unit_price;
    }

    public int getPrice(int portion) {
        if (portion == 1) return unit_price;
        else if (portion == 2) return (int) Math.round(unit_price * 1.5);
        else return unit_price * 2;
    }
}

class Menu {
    Dish[] dishs;
    int cnt = 0;

    public Menu() {
        dishs = new Dish[100];
    }
    public Dish searchDish(String dishName) {
        for (int i = 0; i < cnt; i++) {
            if (dishs[i].name.equals(dishName)) return dishs[i];
        }
        return null;
    }

    public void addDish(String dishName, int unit_price) {
        dishs[cnt++] = new Dish(dishName, unit_price);
    }
}

class Record {
    int orderNum;
    Dish d;
    int portion;
    int num;

    @Override
    public String toString() {
        return "Record{" +
                "orderNum=" + orderNum +
                ", d=" + d +
                ", portion=" + portion +
                ", num=" + num +
                '}';
    }

    public Record(int orderNum, Dish d, int portion, int num) {
        this.orderNum = orderNum;
        this.d = d;
        this.portion = portion;
        this.num=num;
    }

    public int getPrice() {
        return d.getPrice(portion)*num;
    }
}

class Order {
    Record[] records = new Record[100];
    int cnt = 0;

    Record addARecord(int orderNum,String dishName,int portion,int num,Menu menu){
        Dish dish = menu.searchDish(dishName);//根据输入的dishName在Menu中查找对应的Dish对象
        if(dish != null){//如果存在该Dish对象
            Record record = new Record(orderNum,dish,portion,num);//创建一个新的Record对象
            records[cnt++] = record;//将Record对象添加到records数组中,并更新size值
            return record;
        }else{//如果不存在该Dish对象
            System.out.println(dishName + " does not exist");//输出提示信息
            return null;
        }
    }

    public void delARecordByOrderNum(int orderNum){
        int flag=cnt;
        for(int i=0;i<cnt;i++){
            if(records[i].orderNum==orderNum){
                for (int j = i; j <records.length-1 ; j++) {
                    records[i]=records[i+1];
                }
                cnt--;
                break;
            }
        }
        if(flag==cnt){
            System.out.println("delete error");
        }
    }

    public Record findRecordByOrderNum(int orderNum){
        for(int i=0;i<cnt;i++){
            if(records[i].orderNum==orderNum)return records[i];
        }
        return null;
    }

    public void print(){
        for(int i=0;i<cnt;i++){
            System.out.println(records[i].orderNum+" "+records[i].d.name+" "+records[i].getPrice());
        }
    }

    public int getTotalPrice(){
        int res=0;
        for(int i=0;i<cnt;i++){
            res+=records[i].getPrice();
        }
        return res;
    }
}

 

 

分析:这题最开始我直接用一提交了一下,发现过了一个测试点----菜单那个一分。我提交的时候没能实现那个删除功能,这也还是类的一个使用,但是也需要去学会使用像split(),Integer.parseInt9()这些方法,比如说Integer.parseInt() 是一个 Java 方法,用于将字符串转换为整数
如果字符串 str 无法转换为整数,会抛出 NumberFormatException 异常.这里提一下 @Override  这个的使用,

@Override是Java中的一个注解,在方法或类上使用,表示该方法或类是覆盖或实现父类或接口的方法或类。在使用@Override时,必须确保以下几点:

  1. 该方法或类必须是继承或实现自父类或接口中的方法或类。

  2. 方法名、参数列表和返回值类型必须与父类或接口中的方法或类相同。

  3. 方法的访问修饰符不能比父类中的方法更严格。

  4. 方法不能抛出比父类中方法更多的异常。

在使用@Override时,可以帮助我们更好地理解代码,减少代码的冗余和错误。同时,也可以增加代码的可读性和可维护性。

但是这个在菜单二中使用与否其实并没有很大差别(当时在论坛上看到了解了一下)。

然后就是这个删除,我考虑的是当读取到于前面已经点单的菜品序号相同时,如果后面的字符为delete,其实也就是根据序号删除,再选择结果是删除还是输出“delete error”。一和二就是一个慢慢往前爬的一个过程,包括功能的增加。

 

PTA第三次:

该次共有七道题,这里我只列举7-1 菜单计价程序-3和7-7 判断两个日期的先后,计算间隔天数、周数、7-6 GPS测绘中度分秒转换这三题。

其他四题就在这只用文字说明一下,首先是7-2 有重复的数据,这个最开始我使用一个循环的嵌套去实现检查重复,虽然运行测试没问题,但是提交就全错,运行超时,非零返回,(这两个原因前面讲过),改了很多次去精简,最后询问了蔡老师,说尝试减少循环,使用Set<Integer> set = new HashSet<>()

创建一个整数类型的集合,7-3 去掉重复的数据和2大同小异(个人认为3比2还要简单一点)。第四题最开始我存在一个输出都是小写的问题(因为最开始都转换为小写来比较大小),后面更改了一下还是可以了。第五题主要是关于封装性private等一些知识的使用。
 
7-1 菜单计价程序-3
分数 30
作者 蔡轲
单位 南昌航空大学

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。

菜单由一条或多条菜品记录组成,每条记录一行

每条菜品记录包含:菜名、基础价格 两个信息。

订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。

桌号标识独占一行,包含两个信息:桌号、时间。

桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。

点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。

不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。

删除记录格式:序号 delete

标识删除对应序号的那条点菜记录。

如果序号不对,输出"delete error"

代点菜信息包含:桌号 序号 菜品名称 份额 分数

代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。

程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。

每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。

折扣的计算方法(注:以下时间段均按闭区间计算):

周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。

周末全价,营业时间:9:30-21:30

如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"

参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。

Dish {

String name;//菜品名称

int unit_price; //单价

int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }

菜谱类:对应菜谱,包含饭店提供的所有菜的信息。

Menu {

Dish\[\] dishs ;//菜品数组,保存所有菜品信息

Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。

Dish addDish(String dishName,int unit_price)//添加一道菜品信息

}

点菜记录类:保存订单上的一道菜品记录

Record {

int orderNum;//序号\\

Dish d;//菜品\\

int portion;//份额(1/2/3代表小/中/大份)\\

int getPrice()//计价,计算本条记录的价格\\

}

订单类:保存用户点的所有菜的信息。

Order {

Record\[\] records;//保存订单上每一道的记录

int getTotalPrice()//计算订单的总价

Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。

delARecordByOrderNum(int orderNum)//根据序号删除一条记录

findRecordByNum(int orderNum)//根据序号查找一条记录

}

### 输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

### 输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+”:”

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

输入格式:

桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

菜品记录格式:

菜名+英文空格+基础价格

如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。

点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。

删除记录格式:序号 +英文空格+delete

代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数

最后一条记录以“end”结束。

输出格式:

按输入顺序输出每一桌的订单记录处理信息,包括:

1、桌号,格式:table+英文空格+桌号+“:”

2、按顺序输出当前这一桌每条订单记录的处理信息,

每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名

如果删除记录的序号不存在,则输出“delete error”

最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

输入样例:

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

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 12/2/3
1 麻婆豆腐 2 2
2 油淋生菜 1 3
end
 

输出样例:

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

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 38
 

输入样例1:

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

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 17/0/0
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
 

输出样例1:

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

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 22
 

输入样例2:

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

麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 16/59/59
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
 

输出样例2:

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

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
table 1 out of opening hours
 

输入样例3:

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

麻婆豆腐 12
油淋生菜 9
table 1 2022/12/5 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
5 delete
7 delete
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
7 delete
end
 

输出样例3:

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

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
delete error;
table 2: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
table 1 out of opening hours
table 2: 63
 

输入样例4:

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

麻婆豆腐 12
油淋生菜 9
table 1 2022/12/3 19/5/12
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
1 4 麻婆豆腐 1 1
7 delete
end
 

输出样例4:

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

table 1: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
table 2: 
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
4 table 2 pay for table 1 12
delete error;
table 1: 63
table 2: 75
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
分析:第三次菜单因为我在eclipse上还没能完全实现功能,就不在这展示代码以及 类图了,这里主要阐述问题:主要还是删除的问题,还有一个日期判断是否营业或者打折等,还有一个函数或者说方法的调用(这个使用还是很模糊),然后我的菜单三就出现了结构的一些问题。
 
 
7-6 GPS测绘中度分秒转换
分数 10
作者 周永
单位 西南石油大学

在测绘中,获取经度和纬度信息的时候,可以是度分秒格式,也可以是小数点格式。例如一个北纬的纬度信息,30°41′52.37″ ,可以转换为 30.697881。

规则:
(1)度和分都是整数,秒可以含有小数。将用户输入的第一个整数,加上第二个整数除以60,再加上第三个浮点数除以3600,就是最终结果。

(2)在输出结果时,保留6位小数。

(3)题目假定用户输入的数据,一定是合法的数据。

输入格式:

三个数值,数之间用空格分开。

输出格式:

见输出样例。

输入样例:

两个整数后,跟上一个小数。数据之间用空格分开。三个数分别代表度、分、秒。

30 41 52.37
 

输出样例:

输出经纬度信息的小数点格式,保留6位小数。
注意等号的前后有且仅有一个空格,建议复制下面输出到你的代码中,再进行修改。

30°41′52.37″ = 30.697881
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.Scanner;
public class Main
{
    public static void main(String[] args)
    {
        Scanner in = new Scanner(System.in);
        double a,b, c,s;
        a = in.nextDouble();
        b = in.nextDouble();
        c = in.nextDouble();
        s=0;
        if(a==(int)a&&b==(int)b)
        {
            s=a+b/60+c/3600;
            System.out.println((int)a+"°"+(int)b+"′"+c+"″"+" = "+String.format("%.6f",s));
        }
    }
}

分析:这里主要提一下小数点的问题,使用double定义数据,最开始我使用print(),出现输出都是六位小数(但这个需要输入与输出一致),而后我又使用字符串转换来保证输入输出一致,但是增加复杂度,最后发现用format就可以了。

 

7-7 判断两个日期的先后,计算间隔天数、周数
分数 15
作者 吴光生
单位 新余学院

从键盘输入两个日期,格式如:2022-06-18。判断两个日期的先后,并输出它们之间间隔的天数、周数(不足一周按0计算)。

预备知识:通过查询Java API文档,了解Scanner类中nextLine()等方法、String类中split()等方法、Integer类中parseInt()等方法的用法,了解LocalDate类中of()、isAfter()、isBefore()、until()等方法的使用规则,了解ChronoUnit类中DAYS、WEEKS、MONTHS等单位的用法。

输入格式:

输入两行,每行输入一个日期,日期格式如:2022-06-18

输出格式:

第一行输出:第一个日期比第二个日期更早(晚)
第二行输出:两个日期间隔XX天
第三行输出:两个日期间隔XX周

输入样例1:

2000-02-18
2000-03-15
 

输出样例1:

第一个日期比第二个日期更早
两个日期间隔26天
两个日期间隔3周
 

输入样例2:

2022-6-18
2022-6-1
 

输出样例2:

第一个日期比第二个日期更晚
两个日期间隔17天
两个日期间隔2周
 
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
 
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String dateStr1 = scanner.nextLine();
String dateStr2 = scanner.nextLine();

    // 利用字符串的split方法将年月日分离出来
    String[] dateArr1 = dateStr1.split("-");
    String[] dateArr2 = dateStr2.split("-");

    // 将分离出来的年月日转换为整数
    int year1 = Integer.parseInt(dateArr1[0]);
    int month1 = Integer.parseInt(dateArr1[1]);
    int day1 = Integer.parseInt(dateArr1[2]);
    int year2 = Integer.parseInt(dateArr2[0]);
    int month2 = Integer.parseInt(dateArr2[1]);
    int day2 = Integer.parseInt(dateArr2[2]);

    // 利用LocalDate类创建日期对象
    LocalDate date1 = LocalDate.of(year1, month1, day1);
    LocalDate date2 = LocalDate.of(year2, month2, day2);

    // 比较两个日期的先后关系,输出结果
    if (date1.isBefore(date2)) {
        System.out.println("第一个日期比第二个日期更早");
    } else if (date1.isAfter(date2)) {
        System.out.println("第一个日期比第二个日期更晚");
    } else {
        System.out.println("两个日期相同");
    }

    // 计算两个日期间隔的天数和周数
    long days = date1.until(date2, ChronoUnit.DAYS);
    long weeks = date1.until(date2, ChronoUnit.WEEKS);

   

    System.out.printf("两个日期间隔%d天\n", Math.abs(days));
    System.out.printf("两个日期间隔%d周\n", Math.abs(weeks));
}
}

分析:最开始我最开始使用的,但是因为没有考虑到绝对值(Math.abs()),导致输出会出现负数,后面就参照论坛改了,

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String date1Str = in.nextLine();
String date2Str = in.nextLine();
LocalDate date1 = LocalDate.parse(date1Str);
LocalDate date2 = LocalDate.parse(date2Str);
if (date1.isBefore(date2)) {
System.out.println("第一个日期比第二个日期更早");
} else if (date1.isAfter(date2)) {
System.out.println("第一个日期比第二个日期更晚");
} else {
System.out.println("两个日期相同");
}
long days = date1.until(date2, ChronoUnit.DAYS);
System.out.println("两个日期间隔" + days + "天");
long weeks = date1.until(date2, ChronoUnit.WEEKS);
System.out.println("两个日期间隔" + weeks + "周");
}
}

这是快截止时使用的,但是存在一个致命问题,他无法正常读取第二个示例,只能正常读取YY-MM-DD,最后就没交上。

最后和同学邱桑沟通了一下,最后还是需要用数组,也就是我在此次博客中展示的那个,添加了绝对值并且删除了一些没有必要的选择分支,eclipse能够成功运行。

 

 

三:踩坑心得

1.数据的类型定义和小数点输出的细节问题,尤其是floath和double,在计算pta时,有次我把double换成float,计算结果就错误,包括有个输出使用Math.round就通过了,一些细节的问题非常有必要去解决的。

2.输入的一些差异,比如在作业中遇到的next.Line()和next()纯在的差异;

3.对类的使用,就好比日期输入读取的问题,因为最开始对非法示例就无法正常读取,内容再改也无济于事;

4.结构问题,方法的调用,(还有面向过程的这种思想)就是不是很清楚的话,就导致最后出来的结果无法输出,但可能只需要你换一下顺序,也许就能正常输出。

 

四:主要困难以及改进建议

1.对新的类、方法函数的理解和使用,就比如日期那个代码;

2.精简代码的这一个过程,包括嵌套循环但是会出现超时,并且可靠性也存在问题;

3.还是类的一些设计使用的问题,菜单问题就是比较典型错误处(我在这三次作业中);

4.加油。

五:总结

第一是写博客让我们去重新思考并且总结这个作业代码的一个机会;

第二是在这三次作业,我认为理解学会最深的还是Java它的结构和类的使用,还有就是自学能力,因为有一部分其实他和C语言没有大的差异。需要进一步学习的也还是类这个的学习,要逐步去降低这个代码的风险等这些。

第三是Java的学习是线上线下结合的,概念知识一般从线上获取,这保证了一个复习的便利性,线下一般更多的思考和一些课堂的运用,还是很认可这种模式的。暂时没有比较好的建议。

第四是对自己加油。