一、前言
本次博客是针对面向对象程序设计课程布置的PTA第4、5、6次作业以及期中考试的编程题而写的总结分析,重点分析了菜单计价系列题目、期中考试的编程题等具有一定难度和特色的问题。
二、PTA第四次作业
这次作业有四道题目,其中难度最大且分值最高的题目就是菜单计价程序-3,该题在菜单计价程序-2的基础上添加了时间折扣,判断代点菜信息等功能。
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"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+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
我的代码如下:
package num1; import java.util.Calendar; import java.util.Scanner; class Dish { String name;//菜品名称 int unit_price; //单价 //int num; int getPrice(int portion) { int peic = 0; if (portion == 1) { peic = unit_price ; } else if (portion == 2) { peic = Math.round((float) (unit_price * 1.5)) ; } else if (portion == 3) { peic = (unit_price * 2) ; } return peic;//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) } } class Menu { Dish[] dishs = new Dish[10];//菜品数组,保存所有菜品信息 int count = 0; Dish searthDish(String dishName){ Dish temd = null; for(int i=count-1;i>=0;i--){ if(dishName.equals(dishs[i].name)){ temd = dishs[i]; break; } } if(temd==null){ System.out.println(dishName+" does not exist"); } return temd; }//根据菜名在菜谱中查找菜品信息,返回Dish对象。 Dish addDish(String dishName,int unit_price){ Dish dh = new Dish(); dh.name = dishName; dh.unit_price = unit_price; count++; return dh; }//添加一道菜品信息 } class Record { int orderNum;//序号\ //int AntherOrderNum; Dish d = new Dish();//菜品\ int num = 0; int portion;//份额(1/2/3代表小/中/大份)\ //int exist = 1; int getPrice(){ return d.getPrice(portion)*num; }//计价,计算本条记录的价格\ } class Order { Record[] records = new Record[10];//保存订单上每一道的记录 int count = 0;//订单数量 //int forcount = 0;//代点菜的数量 /*int getTotalPrice(){ int sum=0; for(int i=0;i<count;i++){ if(records[i].exist==0) continue; sum=sum+records[i].getPrice(); } return sum; }//计算订单的总价*/ void addARecord(int orderNum,String dishName,int portion,int num){ records[count] = new Record(); records[count].d.name = dishName; records[count].orderNum = orderNum; records[count].portion = portion; records[count].num = num; count++; }//添加一条菜品信息到订单中。 /*Record TakeOdfor(int AnotherNUm,int orderNum,String dishName,int portion,int num){ Record rd2 = new Record(); rd2.d.name = dishName; rd2.orderNum = orderNum; rd2.portion = portion; rd2.d.num = num; rd2.AntherOrderNum = AnotherNUm; //forcount++; return rd2; }*/ int delARecordByOrderNum(int orderNum){ if(orderNum>count||orderNum<=0){ System.out.println("delete error;"); return 0; }else { return records[orderNum - 1].getPrice(); } }//根据序号删除一条记录 } class Table { int tableNum; String tableDtime; int year,month,day,week,hh,mm,ss; int sum = 0;//一桌价格 ; // boolean f = true; Order odt = new Order(); //Order odre = new Order(); float discnt = -1; void Gettottalprice(){ if(discnt>0){ sum = Math.round(sum*discnt); System.out.println("table " + tableNum + ": " + sum); }else { System.out.println("table " + tableNum + " out of opening hours"); } } void AheadProcess(String tableDtime){ this.tableDtime = tableDtime; processTime(); discount(); //CheckAtime(); } void processTime(){//处理时间 String[] temp = tableDtime.split(" "); tableNum = Integer.parseInt(temp[1]); String[] temp1 = temp[2].split("/"); String[] temp2 = temp[3].split("/"); year = Integer.parseInt(temp1[0]); month = Integer.parseInt(temp1[1]); day = Integer.parseInt(temp1[2]); Calendar c = Calendar.getInstance(); c.set(year, (month-1), day); week = c.get(Calendar.DAY_OF_WEEK); if(week==1) week = 7; else week--; hh = Integer.parseInt(temp2[0]); mm = Integer.parseInt(temp2[1]); ss = Integer.parseInt(temp2[2]); } //void CheckAtime(){ // f= !(discnt < 0); // } void discount(){ if(week>=1&&week<=5) { if(hh>=17&&hh<20) discnt=0.8F; else if(hh==20&&mm<30) discnt=0.8F; else if(hh==20&&mm==30&&ss==0) discnt=0.8F; else if(hh>=11&&hh<=13||hh==10&&mm>=30) discnt=0.6F; else if(hh==14&&mm<30) discnt=0.6F; else if(hh==14&&mm==30&&ss==0) discnt=0.6F; } else { if(hh>=10&&hh<=20) discnt= 1.0F; else if(hh==9&&mm>=30) discnt= 1.0F; else if(hh==21&&mm<30||hh==21&&mm==30&&ss==0) discnt= 1.0F; } } } public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); Menu mu = new Menu(); Table[] tablemes = new Table[10]; int j = 0;//菜单数 int l = 0;//订单数 int k = 0;//代点菜数 Dish tt; //int sum = 0; int cntTable = 0;//桌号 int count; String[] temp; int a1,a2,a3,a4,a5; while (true) { String st = sc.nextLine(); temp = st.split(" "); if(st.equals("end")) break; count = temp.length; if (count == 2) {//一个空格 //String[] temp1 = st.split(" "); if (temp[1].equals("delete")) {//第二个为delete a1 = Integer.parseInt(temp[0]); int c = tablemes[cntTable].odt.delARecordByOrderNum(a1); tablemes[cntTable].sum-=c; } else {//菜单添加 a2 = Integer.parseInt(temp[1]); mu.dishs[j] = mu.addDish(temp[0], a2); j++; } //continue; } else if (count == 4) {//三个空格 //String[] temp2 = st.split(" "); if (temp[0].equals("table")) {//桌号 cntTable++;//跳过0; l = 0; tablemes[cntTable] = new Table(); //tablemes[cntTable].tableDtime = st; tablemes[cntTable].AheadProcess(st); System.out.println("table " + cntTable + ": "); } else {//增加订单的情况; a3 =Integer.parseInt(temp[0]); a4 = Integer.parseInt(temp[2]); a5=Integer.parseInt(temp[3]); tablemes[cntTable].odt.addARecord(a3, temp[1],a4 , a5); tt = mu.searthDish(temp[1]); if (tt != null) { tablemes[cntTable].odt.records[l].d = tt; int a = tablemes[cntTable].odt.records[l].getPrice(); System.out.println(tablemes[cntTable].odt.records[l].orderNum + " " + tt.name + " " +a ); tablemes[cntTable].sum +=a; } l++; } //continue; } else if (count == 5) {//代点菜 //String[] temp3 = st.split(" "); a1 = Integer.parseInt(temp[1]); a2 = Integer.parseInt(temp[3]); a3 = Integer.parseInt(temp[4]); tablemes[cntTable].odt.addARecord( a1, temp[2], a2, a3); tt = mu.searthDish(temp[2]); if (tt != null) { tablemes[cntTable].odt.records[l].d.unit_price = tt.unit_price; int b = tablemes[cntTable].odt.records[l].getPrice(); System.out.println(temp[1] + " table " + tablemes[cntTable].tableNum + " pay for table " + temp[0] + " " + b); tablemes[cntTable].sum += b; } l++; } //st = sc.nextLine(); } for (int i = 1; i < cntTable + 1; i++) { tablemes[i].Gettottalprice(); } } }
Dish
类表示菜品,包含菜品名称和单价,并提供计算菜品价格的方法。Menu
类用于管理菜单,包含菜品数组和菜品数量,提供查找菜品和添加菜品的方法。Record
类表示订单中的记录,包含序号、菜品信息、数量和份额,并提供计算记录价格的方法。Order
类用于管理订单,包含记录数组和订单数量,提供添加记录和删除记录的方法。Table
类表示餐桌,包含桌号、时间信息、总价格和订单对象,提供计算总价格和处理时间的方法。Main
类是程序的入口点,通过命令行输入来模拟添加菜品、点菜、删除订单等操作。
对该代码进行类图分析和复杂度分析如下,结果如下:
sourcemonitor代码分析结果如下:
这次题目对于对java语言及面向对象思想不太熟悉的我来说颇具挑战,在一个星期的时间内,我不断调试和优化,还是没能通过全部测试点。
三、PTA第五次作业
本次作业只有一道题目即菜单计价程序-4,通过对菜单计价程序-3的优化和检错,主要针对错误输入的检测和抛出,来显示相应的信息。
本次课题比菜单计价系列-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折, 周末全价。
注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:
计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。
最后将所有记录的菜价累加得到整桌菜的价格。
我的代码如下:
class Worn { void worninput(String[]a,int num,int[]b) { for(int i=0;i<num;i++) { String[] arr=a[i].split(" "); boolean flag=false; //麻婆豆腐 12 if(arr.length>5) { b[i]=1; } if(a[i].matches("^[\u4e00-\u9fa5]{1,} ([1-9][0-9]{0,2})$")==true)//普通菜存入 { flag=true; } //油淋生菜 9 T else if(a[i].matches("^[\u4e00-\u9fa5]{1,4} ([1-9][0-9]{0,2}) [T]$")==true)//特色菜存入 { flag=true; } //table 31 2023/2/1 14/20/00 else if(arr[0].equals("table")==true)//桌 { int blank=0; for(int bk=0;bk<a[i].length();bk++) { if(a[i].charAt(bk)==' ') { blank++; } } if(arr[1].matches("^([1-9][0-9]{0,})$")&&blank==3) flag=true; //int blank=0; } //1 麻婆豆腐 1 16 else if(a[i].matches("^[1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true) { flag=true; } //1 1 麻婆豆腐 1 16 else if(a[i].matches("^([1-9][0-9]{0,1}) [1-9][0-9]{0,2} [\u4e00-\u9fa5]{1,} [1-9] ([1-9][0-9]{0,1})$")==true) { flag=true; } //2 delete else if(a[i].matches("^([1-9][0-9]{0,1}) delete$")==true) { flag=true; } else if(a[i].matches("^end$")==true) { flag=true; } if(flag==false) { b[i]=1; } } } } public class Main { public static void main(String[] args) { try (Scanner in = new Scanner(System.in)) { String[] a=new String[50]; int[]b=new int[50]; Library li = new Library(); Menu c=new Menu(); table[] t=new table[50]; Dish g=new Dish(); int i=0;//桌号 int j=0;//菜数 int p=0;//当前处理桌号 int lastdish=0; int dc1=0,dc2=0,dc3=0,dd1=0,dd2=0,dd3=0,dd4=0; int inputnum=0,h; a[0] = in.nextLine(); b[0] = 0; while (!a[inputnum].equals("end")) { inputnum++; a[inputnum] = in.nextLine(); b[inputnum] = 0; } Worn w=new Worn(); w.worninput(a,inputnum,b); for(h=0;h<inputnum;h++) { if (a[h].isEmpty()) { System.out.println("wrong format"); } else { boolean flagerror = false; //分割字符 String[] arr = a[h].split(" "); if (arr.length == 4 || arr[0].charAt(0) == 't') { if (arr[0].equals("table"))//加桌 { flagerror = true; lastdish = 0; table x = new table(); x.input(a[h], b[h]); if (i != 0) p = t[i - 1].searchtime(t, x, i); if (p == i)//加新桌 { t[i] = new table(); t[p] = x; i++; lastdish = 0;//初始化 if (t[p].flag) System.out.println("table " + t[p].tablenum + ": "); } else { if (t[p].flag) System.out.println("table " + t[p].tablenum + ": "); lastdish = 0; } } else if (arr[0].matches("^[1-9][0-9]{0,1}$"))//自己点菜 { if (b[h] == 1) { flagerror = true; if (i != 0 && t[p].flag) { System.out.println("wrong format"); } continue; } dc1 = Integer.parseInt(arr[0]); dc2 = Integer.parseInt(arr[2]); dc3 = Integer.parseInt(arr[3]); if (i != 0 && t[p].flag) { if (i != 0) { if (dc1 <= lastdish) { System.out.println("record serial number sequence error"); } else { t[p].selforder.addARecord(0, dc1, arr[1], dc2, dc3, true); g = c.searthDish(arr[1]); if (g != null && t[p].flag) { if (dc2 > 3 && dc2 < 10 || dc2 <= 0 && dc2 > -10)//情况9 { //序号+" portion out of range "+份额 System.out.println(dc1 + " portion out of range " + dc2); } else if (dc3 > 15) { System.out.println(dc1 + " num out of range " + dc3); } else { t[p].selforder.records[t[p].k].d = g; //System.out.println(t[p].selforder.records[]); int x = t[p].selforder.records[t[p].k].getPrice(); //2 油淋生菜 27 lastdish = dc1; System.out.println(dc1 + " " + arr[1] + " " + x); } } t[p].k++; } } } } else { System.out.println("wrong format"); flagerror = true; } } else if (arr.length == 5) { if (b[h] == 1) { flagerror = true; if (i != 0 && t[p].flag) { System.out.println("wrong format"); } continue; } dd1 = Integer.parseInt(arr[0]); dd2 = Integer.parseInt(arr[1]); dd3 = Integer.parseInt(arr[3]); dd4 = Integer.parseInt(arr[4]); if (t[p].searthtable(t, dd1, p) == true) { t[p].selforder.addARecord(dd2, dd1, arr[2], dd3, dd4, false); g = c.searthDish(arr[2]); if (g != null) { t[p].selforder.records[t[p].k].d = g; int x = t[p].selforder.records[t[p].k].getPrice(); System.out.println(dd2 + " table " + t[p].tablenum + " pay for table " + dd1 + " " + x); } //k++; t[p].k++; } } else if (arr.length == 2) { if (arr[1].equals("delete")) { if (i != 0) { if (b[h] == 1) { flagerror = true; if (i != 0) { System.out.println("wrong format"); } continue; } if (t[p].flag) t[p].selforder.delARecordByOrderNum(Integer.parseInt(arr[0]), t[p]); } } else//加菜 { if (b[h] == 1) { flagerror = true; System.out.println("wrong format"); continue; } if (i != 0 && t[p].flag)//情况1 { System.out.println("invalid dish"); } else { if (Integer.parseInt(arr[1]) > 0 && Integer.parseInt(arr[1]) < 300) { c.addDish(arr[0], Integer.parseInt(arr[1]), false); j++; } else { System.out.println(arr[0] + " price out of range " + arr[1]); } } } } else if (arr.length == 3) { if (b[h] == 1) { flagerror = true; System.out.println("wrong format"); continue; } if (i != 0 && t[p].flag) { System.out.println("invalid dish"); } else { if (arr[2].equals("T")) { if (Integer.parseInt(arr[1]) > 0 && Integer.parseInt(arr[1]) < 300) { c.addDish(arr[0], Integer.parseInt(arr[1]), true); j++; } else { System.out.println(arr[0] + " price out of range " + arr[1]); } } } } } } for(int l=0;l<i;l++) { t[l].getTotalPrice(); } } catch (NumberFormatException e) { e.printStackTrace(); } } }
因代码过长,在此只截取了新增的wron类以及MAIN类的代码,try
块中包含了主要的代码逻辑,用于接收用户的输入并进行处理。catch
块用于捕获NumberFormatException
异常,该异常通常在将字符串转换为数字时发生,例如使用Integer.parseInt()
方法时。
在 catch
块中,异常对象 e
被打印出来,以便调试和定位错误。
该代码的类图以及代码复杂度分析如下:
这次题目我成功的完成了所有功能,通过所有测试点。
四、PTA第六次作业
这次作业是菜单计价程序5,菜单计价系列的最后一道题目。
以上为菜单计价系列-3的题目要求,加粗的部分是有调整的内容。本次课题相比菜单计价系列-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金额都要累加。
输出用户支付金额格式:
用户姓名+英文空格+手机号+英文空格+支付金额
注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:
计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。
将所有记录的菜价累加得到整桌菜的价本次题目的代码可根据菜单计价程序3的代码来修改,加上口味特色菜等功能,我在菜单计价程序3的代码基础上进行了优化,使得最后的代码行数很少。
在这里贴出我的代码的Main部分:
public class Main { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); Dish[] dishes = new Dish[20]; int x = 0; int y = 0 ; int z = 0 ; int z1 = 0 ; int p = 0; SpecialDish[] specialDishes = new SpecialDish[20]; ArrayList<Table> tables = new ArrayList<>(); Table table = new Table(); int tableNum; int dishNum ; int portion ; int num ; int unit_price ; int deleteNum ; int tasteNum; Record[] records = new Record[20]; PersonPay[] personPays = new PersonPay[10]; Order order = new Order(); Menu menu = new Menu(); lastPrint print = new lastPrint(); String menuName ; String dayTime ; int Output=0; String hourTime ; String name ; String tableName ; String telephoneNum ; String taste; int totalprice1; boolean isHaveTable = false ; boolean forOther = false; while(true){ String input = in.readLine(); if(input.equals("end")){ if(x!=0){ table.order = order; tables.add(x-1 , table); Output ++; } print.tables = tables; print.personPays = personPays; print.print(); print.payPrint(); break; } String[] getInput = input.split(" "); if(input.matches("^(table)( )([1-9][0-9]*)( )(:)( )(\\S+)( )((136|133|135|180|181|189)[0-9]{8})( )([0-9]{4})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})( )([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})(/)([0-9]|[0-9]{2})$")) { if(x != 0) { table.order = order; tables.add(x-1 , table); Output ++; table = new Table(); y = 0; } isHaveTable = true; tableNum = Integer.parseInt(getInput[1]); tableName = getInput[3]; telephoneNum = getInput[4]; dayTime = getInput[5]; hourTime = getInput[6]; Output ++; table.tableNum = tableNum; table.tableName = tableName; table.telephoneNum = telephoneNum; table.mainTime = dayTime; table.remainTime = hourTime; if (table.timeJudgement1()) { Output ++; } else { isHaveTable = false; System.out.println("table " + table.tableNum + " out of opening hours"); continue; } order = new Order(); records = new Record[10]; if(x==0){ personPays[p] = new PersonPay(); personPays[p].name = tableName; personPays[p].telephoneNum = telephoneNum; p++; Output++; print.p = p; for(int v=0;v<10;v++){ Output=Output-1; } } else{ boolean found = false; int i; for (i = 0; i < p; i++) { if (personPays[i].name.equals(tableName) && personPays[i].telephoneNum.equals(telephoneNum)) { found = true; for(int v=0;v<10;v++){ Output=Output-1; } break; } } if (i == p && !found) { personPays[p] = new PersonPay(); personPays[p].name = tableName; personPays[p].telephoneNum = telephoneNum; for(int v=0;v<10;v++){ Output=Output-1; } p++; print.p = p; } } System.out.println("table "+tableNum+": "); x++; } else if(input.matches("^(\\S+)( )([1-9][0-9]*)$")){ int i = 0; menuName = getInput[0]; unit_price = Integer.parseInt(getInput[1]); for(int v=0;v<10;v++){ Output=Output-1; } if(z == 0) { dishes[0] = menu.addDish(menuName , unit_price); z++; } else{ boolean found = false; for (; i < z; i++) { if (menuName.equalsIgnoreCase(dishes[i].name)) { dishes[i].unit_price = unit_price; found = true; break; } } } if(i == z){ dishes[z] = menu.addDish(menuName , unit_price); z++; } menu.dishes = dishes; menu.dishNum = z; } else if(input.matches("^(\\S+)( )(\\S+)( )([1-9][0-9]*)( )(T)$")){ int i = 0; menuName = getInput[0]; taste = getInput[1]; unit_price = Integer.parseInt(getInput[2]); if(z1 == 0){ specialDishes[0] = menu.addSpecialDish(menuName , unit_price , taste); z1++; for(int v=0;v<10;v++){ Output=Output-1; } } else{ for(;i < z1 ; i++) { if(menuName.equalsIgnoreCase(specialDishes[i].name)) { specialDishes[i].unit_price = unit_price; break; } } } if(i == z1){ specialDishes[z1] = menu.addSpecialDish(menuName , unit_price , taste); z1++; } menu.specialDishes = specialDishes; menu.dishNum1 = z1; } else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){ if(!isHaveTable) continue; dishNum = Integer.parseInt(getInput[0]); name = getInput[1]; portion = Integer.parseInt(getInput[2]); num = Integer.parseInt(getInput[3]); Dish searchedDish = menu.searthDish(name); if (searchedDish != null) { records[y] = order.addARecord(dishNum, name, portion, num, menu); records[y].isSpecialDish = false; System.out.println(records[y].orderNum + " " + records[y].d.name + " " + records[y].getPrice()); y++; for(int v=0;v<10;v++){ Output=Output-1; } order.records = records; order.dishNum = y; } else { System.out.println(name + " does not exist"); } } else if(input.matches("^([1-9][0-9]*)( )(\\S+)( )([0-9]+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")){ if(!isHaveTable) continue; dishNum = Integer.parseInt(getInput[0]); name = getInput[1]; tasteNum = Integer.parseInt(getInput[2]); portion = Integer.parseInt(getInput[3]); num = Integer.parseInt(getInput[4]); if(menu.searthSpecialDish(name) != null) { if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 0 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晋菜") && tasteNum>=0 && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum>=0 && tasteNum <= 3))){ records[y] = new Record(); records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , forOther); records[y].isSpecialDish = true; System.out.println(records[y].orderNum+" "+records[y].d.name+" "+records[y].getPrice()); y++; order.records = records; order.dishNum = y; } } else{ System.out.println(name+" does not exist"); continue; } SpecialDish specialDish = menu.searthSpecialDish(name); if (specialDish != null) { switch (specialDish.taste) { case "川菜": if (tasteNum < 0 || tasteNum > 5) { System.out.println("spicy num out of range: " + tasteNum); } break; case "晋菜": if (tasteNum < 0 || tasteNum > 4) { System.out.println("acidity num out of range: " + tasteNum); } break; case "浙菜": if (tasteNum < 0 || tasteNum > 3) { System.out.println("sweetness num out of range: " + tasteNum); } break; default: break; } } } else if(input.matches("([1-9][0-9]*)( )(delete)")) { if(!isHaveTable) continue; deleteNum = Integer.parseInt(getInput[0]); if(order.findRecordByNum(deleteNum) == 1){ order.delARecordByOrderNum(deleteNum); } else System.out.println("delete error;"); } else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) { if(!isHaveTable) continue; int t = Integer.parseInt(getInput[0]); dishNum = Integer.parseInt(getInput[1]); name = getInput[2]; portion = Integer.parseInt(getInput[3]); num = Integer.parseInt(getInput[4]); for(int i = 0;i<x-1;i++){ if(tables.get(i).tableNum == t){ if(menu.searthDish(name) != null) { records[y] = new Record(); records[y] = order.addARecord(dishNum , name , portion , num , menu); records[y].isSpecialDish = false; System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice()); y++; order.records = records; order.dishNum = y; } break; } } } else if(input.matches("^([1-9][0-9]*)( )([1-9][0-9]*)( )(\\S+)( )([0-9]*)( )([1-9][0-9]*)( )([1-9][0-9]*)$")) { if(!isHaveTable) continue; int t = Integer.parseInt(getInput[0]); dishNum = Integer.parseInt(getInput[1]); name = getInput[2]; tasteNum = Integer.parseInt(getInput[3]); portion = Integer.parseInt(getInput[4]); num = Integer.parseInt(getInput[5]); for(int i = 0;i<x-1;i++){ if(tables.get(i).tableNum == t){ if(menu.searthSpecialDish(name) != null) { if(((menu.searthSpecialDish(name).taste.equals("川菜") && tasteNum >= 1 && tasteNum <= 5) || (menu.searthSpecialDish(name).taste.equals("晋菜") && tasteNum <= 4) || (menu.searthSpecialDish(name).taste.equals("浙菜") && tasteNum <= 3))){ records[y] = new Record(); records[y] = order.addASpecialRecord(dishNum , name , portion , num , menu , tasteNum , !forOther); records[y].isSpecialDish = true; System.out.println(dishNum+" table "+table.tableNum+" pay for table "+t+" "+records[y].getPrice()); tables.get(i).giveTaste(name,num,tasteNum,menu); y++; order.records = records; order.dishNum = y; } } break; } } } else { System.out.println("wrong format"); } } } public String judgeTriangleType(double side1, double side2, double side3) { if (side1 <= 0 || side2 <= 0 || side3 <= 0) { return "does not exist"; } if (side1 + side2 <= side3 || side1 + side3 <= side2 || side2 + side3 <= side1) { return "spicy num out of range:"; } if (side1 == side2 && side2 == side3) { return "acidity num out of range:"; } else if (side1 == side2 || side1 == side3 || side2 == side3) { return "pay for table"; } else { return "sweetness num out of range"; } } }
改后的部分类图及代码复杂度报图分析如下:
六、期中考试题目分析
本次期中考试的编程题目为圆形和矩形的类结构设计及其图形类的继承、多态和接口。
前三题较为简单,我想着重介绍一下第四题,
在测验3的题目基础上,重构类设计,实现列表内图形的排序功能(按照图形的面积进行排序)。
提示:题目中Shape类要实现Comparable接口。
其中,Main类源码如下(可直接拷贝使用):
public class Main {
public static void main(String\[\] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
ArrayList<Shape> list = new ArrayList<>();
int choice = input.nextInt();
while(choice != 0) {
switch(choice) {
case 1://Circle
double radiums = input.nextDouble();
Shape circle = new Circle(radiums);
list.add(circle);
break;
case 2://Rectangle
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();
Point leftTopPoint = new Point(x1,y1);
Point lowerRightPoint = new Point(x2,y2);
Rectangle rectangle = new Rectangle(leftTopPoint,lowerRightPoint);
list.add(rectangle);
break;
}
choice = input.nextInt();
}
list.sort(Comparator.naturalOrder());//正向排序
for(int i = 0; i < list.size(); i++) {
System.out.print(String.format("%.2f", list.get(i).getArea()) + " ");
}
}
}
我的代码如下:
import java.util.Scanner; import java.util.ArrayList; import java.util.Comparator; abstract class Shape implements Comparable<Shape> { public abstract double calculateArea(); @Override public int compareTo(Shape s) { if (this.calculateArea() < s.calculateArea()) { return -1; } else if (this.calculateArea() > s.calculateArea()) { return 1; } else { return 0; } } } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } @Override public double calculateArea() { return Math.PI * radius * radius; } } class Rectangle extends Shape { private Point topLeft; private Point bottomRight; public Rectangle(Point topLeft, Point bottomRight) { this.topLeft = topLeft; this.bottomRight = bottomRight; } @Override public double calculateArea() { double width = Math.abs(bottomRight.getX() - topLeft.getX()); double height = Math.abs(topLeft.getY() - bottomRight.getY()); return width * height; } } class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); ArrayList<Shape> shapes = new ArrayList<>(); int choice = input.nextInt(); while (choice != 0) { switch (choice) { case 1: // Circle double radius = input.nextDouble(); Shape circle = new Circle(radius); shapes.add(circle); break; case 2: // Rectangle double x1 = input.nextDouble(); double y1 = input.nextDouble(); double x2 = input.nextDouble(); double y2 = input.nextDouble(); Point topLeft = new Point(x1, y1); Point bottomRight = new Point(x2, y2); Shape rectangle = new Rectangle(topLeft, bottomRight); shapes.add(rectangle); break; } choice = input.nextInt(); } shapes.sort(Comparator.naturalOrder()); for (Shape shape : shapes) { System.out.print(String.format("%.2f", shape.calculateArea()) + " "); } } }
在抽象类shape中设计了一个comprable的接口,定义图形比较方法,通过圆形类和矩形类继承该抽象类,分别重写计算面积的方法,在Main中,用该接口的比较方法对给出参数的图形进行自然排序并输出。
该代码复杂度及行数不多,在这里不赘述其这方面的分析图报表。
六、问题分析
① 一开始在写菜单计价程序3时,对类的多态和面向对象思想不太了解,导致在new一个新的record或者dish对象时,不能准确的传出或传入参数,导致最后的代码依然存在问题。
② 菜单计价程序4、5代码复杂度较高,可读性较差且代码的逻辑较为混乱,只顾着完成而未注意其代码运存及圈复杂度。
七、总结
这几次的作业让我对面向对象的思想和好处有了更深一步的了解,通过这几周的学习,我进一步掌握了java语言的语法以及面向对象编程,为我接下来的学习和生活打下了良好的基础,让我受益良多。