题目集 1~3 的总结性 Blog

发布时间 2023-05-21 16:41:42作者: 诳语05号机

前言:

题目集 1~3 的知识点、题量、难度等情况如下:

  • 知识点:JAVA基础,基础算法,面向对象程序设计

  • 题量:共计 3 道题目

  • 难度:题目从易到难,分为三个层次,分别为入门、中等和高级

设计与分析:

本次 Blog 重点分析菜单计价系列题目,即题目集 2 的 7-1、7-2 以及题目集 3 的 7-1。这三个题目都具有典型的菜单计价特征,需要对菜单进行设计并实现相应的计价算法。

  • 7-1:给出多个订单,计算指定菜品的组合总价。该题目主要是考察类的创建,输入数据格式的判断,以及方法的构造。该题目只需要构造两个类和一个方法便可以实现

     1 static class Dish {
     2         String name;
     3         int unit_price;
     4     }
     5 
     6 static class Record {
     7         int orderNum;
     8         Dish d;
     9         int portion;
    10         int quota;
    11 
    12         int getPrice () {
    13             if (portion == 2) {
    14                 return (int) Math.round (1.5 * d.unit_price) * quota;
    15             }
    16             else if (portion == 3) {
    17                 return 2 * d.unit_price * quota;
    18             }
    19             else {
    20                 return d.unit_price * quota;
    21             }
    22         }
    23     }
    24 

     

     

  • 7-2:给出一个菜单和多个订单,计算订单中菜品的组合总价。该题目主要是考察对类对象的访问以及成员变量的存储。在实现过程中,需要区分菜单信息和订单信息格式上的不同,以免发生方法调用上的错误。在7-1的基础上,本题需要设计方法来手动输入菜单信息,我选择构造一个新的类来实现这些方法
    static class Menu {
            Dish[] dishs = new Dish[20];
    
            int searchDish () {
            //TO-DO
            }
    
            Dish addDish () {
            //TO-DO
            }
        }

    其次,本题新增了对订单类的删改信息,同样,也是构造新的方法来实现这些功能

     1     static class Order {
     2         Record[] records = new Record[20];
     3 
     4         Record addARecord () {
     5             //TO-DO12         }
    13 
    14         boolean delARecordByOrderNum () {
    15            //TO-DO29         }
    30     }

     

  • 7-1:给出一个菜单和多个桌号信息,每个桌号包含多个订单信息,计算每桌订单中菜品的组合总价。该题目主要是考察类和方法的创建和使用,对变量的存储和访问。在实现过程中,需要区分菜单信息、桌号信息和订单信息格式上的不同,以免发生数据丢失。相比于上一次菜单题目,本次题目增添了table类,其中包含结账和增添新订单等操作(实际就是之前的Order类新增一些内部成员变量,但是写的时候没注意到就胡乱的增添了一个类)
     1 static class Table {
     2         Order order = new Order ();
     3         int num;
     4         int order_count = 0;
     5         LocalDateTime time;
     6         long sum = 0;
     7 
     8         void od (Menu menu, int menu_count, String str1, String str2, int portion, int quota) {
     9             if (str2.equals ("delete")) {
    10                 if (order.delARecordByOrderNum (Integer.parseInt (str1), order_count)) {
    11                     order_count--;
    12                 }
    13             }
    14             else {
    15                 if (menu.searchDish (str2, menu_count) != -1) {
    16                     order.records[order_count] = new Record ();
    17                     order.records[order_count] = order.addARecord (Integer.parseInt (str1), str2, portion, quota, menu_count, menu);
    18                     order_count++;
    19                 }
    20                 else {
    21                     System.out.println (str2 + " does not exist");
    22                 }
    23             }
    24         }
    25 
    26         void getSum () {
    27             int weekday = time.getDayOfWeek ().getValue ();
    28             for (int i = 0; i < order_count; i++) {
    29                 sum += order.records[i].getPrice ();
    30             }
    31             if (weekday > 0 && weekday < 6) {
    32                 if (time.getHour () >= 17 && time.getHour () < 20) sum = Math.round (sum * 0.8);
    33                 if (time.getHour () == 20) {
    34                     if (time.getMinute () <= 30) sum = Math.round (sum * 0.8);
    35                 }
    36                 if (time.getHour () >= 10 && time.getHour () < 14) sum = Math.round (sum * 0.6);
    37                 if (time.getHour () == 14) {
    38                     if (time.getMinute () <= 30) sum = Math.round (sum * 0.6);
    39                 }
    40             }
    41         }
    42 
    43         boolean isOpen () {
    44             int weekday = time.getDayOfWeek ().getValue ();
    45             if (weekday > 0 && weekday < 6) {
    46                 if (time.getHour () >= 17 && time.getHour () < 20) return true;
    47                 if (time.getHour () == 20) {
    48                     if (time.getMinute () <= 30) return true;
    49                 }
    50                 if (time.getHour () > 10 && time.getHour () < 14) return true;
    51                 if (time.getHour () == 10) {
    52                     if (time.getMinute () >= 30) return true;
    53                 }
    54                 if (time.getHour () == 14) {
    55                     if (time.getMinute () <= 30) return true;
    56                 }
    57             }
    58             else {
    59                 if (time.getHour () > 9 && time.getHour () < 21) return true;
    60                 if (time.getHour () == 9) {
    61                     if (time.getMinute () >= 30) return true;
    62                 }
    63                 if (time.getHour () == 21) {
    64                     if (time.getMinute () <= 30) return true;
    65                 }
    66             }
    67             return false;
    68 
    69         }
    70     }

     

采坑心得:

在提交源码的过程中,我遇到了很多问题,总结如下:

  • 对格式错误的数据的处理问题:在读入并判断输入数据格式时,要注意对错误格式的信息进行忽略并报错,否则会导致程序崩溃。
  • 数组下标越界问题:在删除订单信息时,要注意数组下标是否越界,否则会导致程序崩溃。
  • 对不同格式信息的区分问题:在读入数据后,格式的判断一定要严谨,否则会导致数据的丢失。
  • 类的结构过于混乱:在编写程序时一定要注意程序的结构是否可拓展和可读,避免后期维护产生问题。

主要困难以及改进建议:

在解题过程中,我遇到了以下主要困难:

  • 对时间类的使用不够熟练:在解决储存每桌对应的时间时,我发现测试样例中时间的格式不统一,时而是单数时而是双数,导致使用SimpleDataFormat(yyyy/MM/dd HH/mm/ss)
    的时候出现报错。
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH/mm/ss");
    Date date = new Date();
    date= sdf.parse(time);

     

  • 算法的实现不够高效:对于多桌菜的情况,处理大量数据时因为循环结构过多导致耗时很长,无法达到预期结果。
  • 编码能力有待提高:在解题过程中,我发现自己编码能力还有待提高,主要体现在代码的可读性和可维护性上,难以在原有的结构基础上拓展新的功能。因此,需要加强对编码技巧的掌握,提高代码的可读性和可维护性。

改进建议:

  • 对于时间类需要有更多的理解,在寻找上述中提到的时间格式问题的解决方法时,我在网络上领教到了一种较为方便的解决方法:

     将data类转化为Instant类,再由时区转换为LocalDateTime类,这样就可以避免因为输入格式的不统一造成的错误了。

    1 Date date = new Date();
    2             date= sdf.parse(time);
    3             Instant instant = date.toInstant();
    4             ZoneId zone = ZoneId.systemDefault();
    5             tables[table_count].time= LocalDateTime.ofInstant(instant, zone);

     

  • 对于提高代码可拓展性上,我将原本的很多功能重构成了方法,也增加了类的使用频率,让代码整体的结构更加紧密和可拓展。
  • 对于格式的判断,我率先想到的就是判断数据的某个元素是否可以转化为数字,以将不同的数据分割开处理,因此,我构造了isNumeric方法来判断是否可以转化成数字
    1     public static boolean isNumeric (String string) {
    2         int intValue;
    3         try {
    4             intValue = Integer.parseInt (string);
    5             return true;
    6         } catch (NumberFormatException e) {
    7             return false;
    8         }
    9     }

    当然,这个方法并不是很好,一方面每个数据都要判断一遍导致运行速度大大降低,另一方面可扩展性不高,后期添加新的功能时需要大量改动原有代码。但当时不会更加高效的判断方法,也是无奈之举。

  • 针对删除订单信息的方法中出现的数组越界问题,我引用了新的计数变量count,来记录数组的长度,从而防止数组下标越界的问题(其实可以直接调用数组的lenth方法,只是当时脑抽了)
     1 boolean delARecordByOrderNum(int orderNum,int count){
     2             int i=0,j=0,flag=0;
     3             for(i=0;i<count;i++){
     4                 if(records[i].orderNum==orderNum){
     5                     for(j=i;j<count-1;j++){
     6                         records[j]=records[j+1];
     7                     }
     8                     flag++;
     9                 }
    10             }
    11             if(flag==0){System.out.println("delete error;");return false;}
    12             return true;
    13         }

     

  • 多参与讨论和交流:多参与讨论和交流,向其他同学和老师学习,拓宽自己的思路和知识面。

仍未解决的问题:

  • 即使优化了代码的结构,代码的运行效率依旧达不到预期的水准,个人猜测是由于判断输入数据格式的方法太过笨拙。
  • 使用不可拓展容器来储存变量,有超出容器容量的风险,应当换用ArrayList等容器。这样不仅解决了容器大小的问题,又可以让数据的增删改查更加方便。
  • 由于胡乱的增加类,导致类与类的关系变得混乱,应当将Table类与Order类结合起来,可以增加代码的可读性。

总结:

现在回顾这一系列题目感觉难度并不是很大,思路相对来说还算比较清晰,各种方法实现起来还算比较简单。但对于当时第一次接触两百行以上的项目的我来说无疑是个大挑战,我很庆幸自己可以突破这个难关,虽然使用的方法并不好,用了许多“笨方法”,代码的结构也不够清晰,可读性也比较差,不过通过这次综合性训练我学到了很多新知识。在此之前我从未接触过parse方法,也不知道LocalDateTime的使用方法。总体而言,这套菜单系统让我学到了很多新知识,并且使我对代码结构的理解更加深刻,意识到了代码可拓展性的重要。