南昌航空大学Java大作业分析blog
一、前言
本次博客是针对第四次作业和第五次作业以及期中考试所做的总结。这两次作业难度较大,代码量也比较多。Pta作业已经写了五次,除了第一次题目难度比较平缓,后面的数次难度激增,我也只有第一次全部写完pta的所有题目,后面就没有拿到过满分。总体来说,最近两次pta的主要知识点还是在设计类和学习java语言,以及用面向对象的思维方式。对只接触过一点java语言的我们还是很有挑战的。最近两次pta作业虽然题类似,但是难度很大,两次作业都有菜单的设计,有很多类的调用,十分复杂,还需要使用很多函数,要有继承和传参,对我们来说确实十分困难。通过这两次次作业,我对Java的一些基本语法有了一些了解,对于面向对象的过程的思想有了一些掌握,但是还有美中不足的地方,以下是我的反思以及对这两次作业的理解。
二、设计与分析
第四次题目集
1.7-1
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"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类:
class Dish { String name;//菜品名称 int unit_price; //单价 int getPrice(int portion) { if (portion == 1) return unit_price; else if (portion == 2) return (int)(unit_price + unit_price / 2.0+0.5); else return unit_price * 2; } }
menu类:
class Menu { ArrayList<Dish> dishes = new ArrayList<Dish>(); //= new Dish[4] ;//菜品数组,保存所有菜品信息 Dish searchDish(String dishName){ for (Dish dish : dishes) { if (dish.name.equals(dishName)) { return dish; } } return null; } Dish addDish(String dishName,int unit_price){ Dish dish = new Dish(); dish.name = dishName; dish.unit_price = unit_price; return dish; } }
record类:
class Record { int sum=0; int orderNum; Dish d;//菜品 int portion;//份额(1/2/3代表小/中/大份) int getPrice(){ return d.getPrice(portion)*sum; }//计价,计算本条记录的价格 }
order类:
class Order { ArrayList<Record> records = new ArrayList<>(); int getTotalPrice(){ int totalPrice = 0; for (Record record : records) { if (record != null) { totalPrice += record.getPrice(); } } return totalPrice; }//计算订单的总价 Record addARecord(int orderNum,Menu menu, String dishName, int portion,int sum) { Dish dish = menu.searchDish(dishName); if (dish != null) { Record record = new Record(); record.sum = sum; record.orderNum = orderNum; record.d = dish; record.portion = portion; records.add(record); System.out.println(record.orderNum + " " + record.d.name + " " + record.getPrice()); return record; } else { System.out.println(dishName + " does not exist"); return null; } } // 添加一条菜品信息到订单中。 void delARecordByOrderNum(int orderNum){ int count=0; for(int i=0;i<records.size();i++){ if(records.get(i).orderNum==orderNum){ count=1; records.remove(records.get(i)); } } if(count==0) System.out.println("delete error;"); } }
类图:
复杂度分析:
踩坑心得:
1,价格的算法出错,注意特色菜的价格算法以及打折的时间。
2,同一桌菜名、份额相同的点菜记录要合并成一条进行计算,否则可能会出现四舍五入的误差。
3. 在输入菜单订号时我给的判断是(line.matches("[1-9]* [\\S]* [1-3] [1-9]*"))然而0也行
第五次题目集
1.7-1
本次课题比菜单计价系列-3增加的异常情况:
1、菜谱信息与订单信息混合,应忽略夹在订单信息中的菜谱信息。输出:"invalid dish"
2、桌号所带时间格式合法(格式见输入格式部分说明,其中年必须是4位数字,月、日、时、分、秒可以是1位或2位数),数据非法,比如:2023/15/16 ,输出桌号+" date error"
3、同一桌菜名、份额相同的点菜记录要合并成一条进行计算,否则可能会出现四舍五入的误差。
4、重复删除,重复的删除记录输出"deduplication :"+序号。
5、代点菜时,桌号不存在,输出"Table number :"+被点菜桌号+" does not exist";本次作业不考虑两桌记录时间不匹配的情况。
6、菜谱信息中出现重复的菜品名,以最后一条记录为准。
7、如果有重复的桌号信息,如果两条信息的时间不在同一时间段,(时段的认定:周一到周五的中午或晚上是同一时段,或者周末时间间隔1小时(不含一小时整,精确到秒)以内算统一时段),此时输出结果按不同的记录分别计价。
8、重复的桌号信息如果两条信息的时间在同一时间段,此时输出结果时合并点菜记录统一计价。前提:两个的桌号信息的时间都在有效时间段以内。计算每一桌总价要先合并符合本条件的饭桌的点菜记录,统一计价输出。
9、份额超出范围(1、2、3)输出:序号+" portion out of range "+份额,份额不能超过1位,否则为非法格式,参照第13条输出。
10、份数超出范围,每桌不超过15份,超出范围输出:序号+" num out of range "+份数。份数必须为数值,最高位不能为0,否则按非法格式参照第16条输出。
11、桌号超出范围[1,55]。输出:桌号 +" table num out of range",桌号必须为1位或多位数值,最高位不能为0,否则按非法格式参照第16条输出。
12、菜谱信息中菜价超出范围(区间(0,300)),输出:菜品名+" price out of range "+价格,菜价必须为数值,最高位不能为0,否则按非法格式参照第16条输出。
13、时间输入有效但超出范围[2022.1.1-2023.12.31],输出:"not a valid time period"
14、一条点菜记录中若格式正确,但数据出现问题,如:菜名不存在、份额超出范围、份数超出范围,按记录中从左到右的次序优先级由高到低,输出时只提示优先级最高的那个错误。
15、每桌的点菜记录的序号必须按从小到大的顺序排列(可以不连续,也可以不从1开始),未按序排列序号的输出:"record serial number sequence error"。当前记录忽略。(代点菜信息的序号除外)
16、所有记录其它非法格式输入,统一输出"wrong format"
17、如果记录以“table”开头,对应记录的格式或者数据不符合桌号的要求,那一桌下面定义的所有信息无论正确或错误均忽略,不做处理。如果记录不是以“table”开头,比如“tab le 55 2023/3/2 12/00/00”,该条记录认为是错误记录,后面所有的信息并入上一桌一起计算。
本次作业比菜单计价系列-3增加的功能:
菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+基础价格+"T"
例如:麻婆豆腐 9 T
菜价的计算方法:
周一至周五 7折, 周末全价。
注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:
计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。
最后将所有记录的菜价累加得到整桌菜的价格。
dish类:
menu类:
record类:
order类:
class Order { ArrayList<Record> records = new ArrayList<>(); public int a; int getTotalPrice(){ int totalPrice = 0; for (Record record : records) { if (record != null) { totalPrice += record.getPrice(); } } return totalPrice; }//计算订单的总价 Record addARecord(int orderNum,Menu menu, String dishName, int portion,int sum) { Dish dish = menu.searchDish(dishName); if (dish == null) { System.out.println(dishName + " does not exist"); return null; } else if(portion>3) { System.out.println(orderNum+" portion out of range "+portion); return null; } else if(sum>=15) { System.out.println( orderNum+" num out of range "+sum); return null; } else if(a>orderNum) { System.out.println("record serial number sequence error"); return null; } else { a=orderNum; Record record = new Record(); record.sum = sum; record.orderNum = orderNum; record.d = dish; record.portion = portion; records.add(record); System.out.println(record.orderNum + " " + record.d.name + " " + record.getPrice()); return record; } } // 添加一条菜品信息到订单中。 void delARecordByOrderNum(int orderNum){ int count=0; for(int i=0;i<records.size();i++){ if(records.get(i).orderNum==orderNum){ count=1; records.remove(records.get(i)); } } if(count==0) System.out.println("delete error;"); } }
类图:
复杂度分析:
踩坑心得:
1,数据类型转换错误,string类和int类转换和输出问题。
2,再写点菜单号时我刚开始的是(line.matches("[1-9]* [\\S]* [1-9] [1-9]*"))后面发现单号为0时也行,不过要输出wrong format。
3,不同的四舍五入顺序可能会造成误差。
第五次题目集
1.7-1
本次课题相比菜单计价系列-3新增要求如下:
1、菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+口味类型+英文空格+基础价格+"T"
例如:麻婆豆腐 川菜 9 T
菜价的计算方法:
周一至周五 7折, 周末全价。
特色菜的口味类型:川菜、晋菜、浙菜
川菜增加辣度值:辣度0-5级;对应辣度水平为:不辣、微辣、稍辣、辣、很辣、爆辣;
晋菜增加酸度值,酸度0-4级;对应酸度水平为:不酸、微酸、稍酸、酸、很酸;
浙菜增加甜度值,甜度0-3级;对应酸度水平为:不甜、微甜、稍甜、甜;
例如:麻婆豆腐 川菜 9 T
输入订单记录时如果是特色菜,添加口味度(辣/酸/甜度)值,格式为:序号+英文空格+菜名+英文空格+口味度值+英文空格+份额+英文空格+份数
例如:1 麻婆豆腐 4 1 9
单条信息在处理时,如果口味度超过正常范围,输出"spicy/acidity/sweetness num out of range : "+口味度值,spicy/acidity/sweetness(辣度/酸度/甜度)根据菜品类型择一输出,例如:
acidity num out of range : 5
输出一桌的信息时,按辣、酸、甜度的顺序依次输出本桌菜各种口味的口味度水平,如果没有某个类型的菜,对应的口味(辣/酸/甜)度不输出,只输出已点的菜的口味度。口味度水平由口味度平均值确定,口味度平均值只综合对应口味菜系的菜计算,不做所有菜的平均。比如,某桌菜点了3份川菜,辣度分别是1、3、5;还有4份晋菜,酸度分别是,1、1、2、2,辣度平均值为3、酸度平均值四舍五入为2,甜度没有,不输出。
一桌信息的输出格式:table+英文空格+桌号+:+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价+英文空格+"川菜"+数量+辣度+英文空格+"晋菜"+数量+酸度+英文空格+"浙菜"+数量+甜度。
如果整桌菜没有特色菜,则只输出table的基本信息,格式如下,注意最后加一个英文空格:
table+英文空格+桌号+:+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价+英文空格
例如:table 1: 60 36 川菜 2 爆辣 浙菜 1 微甜
计算口味度时要累计本桌各类菜系所有记录的口味度总和(每条记录的口味度乘以菜的份数),再除以对应菜系菜的总份数,最后四舍五入。
注:本题要考虑代点菜的情况,当前桌点的菜要加上被其他桌代点的菜综合计算口味度平均值。
2、考虑客户订多桌菜的情况,输入时桌号时,增加用户的信息:
格式:table+英文空格+桌号+英文空格+":"+英文空格+客户姓名+英文空格+手机号+日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
例如:table 1 : tom 13670008181 2023/5/1 21/30/00
约束条件:客户姓名不超过10个字符,手机号11位,前三位必须是180、181、189、133、135、136其中之一。
输出结果时,先按要求输出每一桌的信息,最后按字母顺序依次输出每位客户需要支付的金额。不考虑各桌时间段的问题,同一个客户的所有table金额都要累加。
输出用户支付金额格式:
用户姓名+英文空格+手机号+英文空格+支付金额
dish类:
class Dish { String name;//菜品名称 String taste;//类型 String level; int unit_price; //单价 boolean isT; int getPrice(int portion) { if (portion == 1) return unit_price; else if (portion == 2) return (int)(unit_price + unit_price / 2.0+0.5); else return unit_price * 2; } }
menu类:
class Menu { ArrayList<Dish> dishes = new ArrayList<Dish>(); //= new Dish[4] ;//菜品数组,保存所有菜品信息 Dish searchDish(String dishName){ for (Dish dish : dishes) { if (dish.name.equals(dishName)) { return dish; } } return null; } Dish addDish(String dishName,String taste,int unit_price,boolean isT,String level){ Dish dish = new Dish(); dish.name = dishName; dish.unit_price = unit_price; dish.isT=isT; dish.taste=taste; dish.level=level; return dish; } }
record类:
class Record { int sum=0; int orderNum; Dish d;//菜品 int portion;//份额(1/2/3代表小/中/大份) int getPrice(){ return d.getPrice(portion)*sum; }//计价,计算本条记录的价格 }
order类:
class Order { ArrayList<Record> records = new ArrayList<>(); int getTotalPrice(){ int totalPrice = 0; for (Record record : records) { if (record != null) { totalPrice += record.getPrice(); } } return totalPrice; }//计算订单的总价 Record addARecord(int orderNum,Menu menu, String dishName, int portion,int sum) { Dish dish = menu.searchDish(dishName); if (dish != null) { Record record = new Record(); record.sum = sum; record.orderNum = orderNum; record.d = dish; record.portion = portion; records.add(record); System.out.println(record.orderNum + " " + record.d.name + " " + record.getPrice()); return record; } else { System.out.println(dishName + " does not exist"); return null; } } // 添加一条菜品信息到订单中。 void delARecordByOrderNum(int orderNum){ int count=0; for(int i=0;i<records.size();i++){ if(records.get(i).orderNum==orderNum){ count=1; records.remove(records.get(i)); } } if(count==0) System.out.println("delete error;"); } }
类图:
复杂度分析:
踩坑心得:
1,数据类型转换错误,string类和int类转换和输出问题。
2,辣度的计算值为每道菜的辣度乘上份数的总和在除以总该口味菜份数
3,不同的四舍五入顺序可能会造成误差。
4.在匹配菜单时,当没有单价或者是特色菜没有“T”时要输出"wrong format"
5.特色菜在周末时不打折
第五次题目集
1.7-1圆类设计
类图:
复杂度
1.7-2类结构设计
类图:
复杂度:
1.7-3继承与多态
类图:
复杂度:
1.7-4抽象类与接口
类图:
复杂度:
四,改进建议:
1,pta部分题目运行时间超时,要优化代码的算法,很多时候不是你的方法不行,而是有优化的地方没有优化,导致程序运行的时间加长导致超时,现在争取把每个小步骤都优化,以后的大作业程序才能不断的节省时间。
2,pta部分题目非零返回,自己的代码有问题才会导致的,要检查自己的程序逻辑。
3,对继承的方法使用不熟练,对传参的方法也不太熟练,会用但是容易出错,要多使用,防止以后出错。
4,对类的设计要更细节和具体,每个类包含的属性和方法,以及不同类之间的关系。
5.、在PTA训练集05中的7-1 菜单计价程序-4题目中,所使用的if...else...语句过多,或许可以换个思路来减少一些if...else...语句,增强代码可读性和可修改性;
五、总结
这两次的作业总体来说难度大,题目量虽然也不多,但是有些题目还是需要静下心来思考才能做好。期中考试的难度不算很高,前三题还是比较好作对的,第四题的接口我还没有掌握,没能拿下分。通过这数次的PTA作业,我也基本能够掌握java语言中类的作用。这段时间的作业,也让我发现了自己最大的问题,那就是思维比较固化,写的很多程序的思路大多都是按部就班的那种,所以我的思维能力还是很需要培养的。在编写复杂又长的代码时,需要有个较为完整且清晰的思路才能开始,而不是边敲边想,最终导致的结果可能就是必须全部推倒之前所写的所有代码重来;还需要不断地努力,遇到再难的题,都不能畏惧,而是秉着能解决多少就解决多少的态度去解决问题,并且要虚心向别人请教和查阅资料;