前言
1.对于前三次作业的总结
(1)对于输入,输出的格式的掌握:
对于第一次作业,并没有什么较为难的掌握的知识,主要就是让我们了解,Java程序中的输入输出的用法也就是Scanner和println之类的用法。
(2)对于类与对象的运用:
在第二次作业中,便用到了Java中的类来对我们的菜单问题进行解答,这也是java中的一大特色,在解答之前,我们需要提前构思,我们需要创建哪些类,可以给我们解题带来哪些帮助,过程中我们该怎么去调用。
(3)对于一些特使的类的使用:
在第三次作业里,对于一些日期问题,运用我们常规的思路去解决对现阶段来说十分困难,因此我们可以去了解一些Java中特殊的类,比如Date类和Calendar类的用法,或者是map的用法。
在这三次作业中,点菜系统就是一个非常大的难题,每一次都会有新的细节的加入,而在我看来,点菜题目并没有太好的算法选择,单纯就是对我们对数据输入的处理,以及对数据输出的处理。
设计与分析
(1).作业2的7-1:菜单计价程序-1
对于点菜一中,并没有特别难懂的问题,也没有特别复杂的思路,在我看来,这单简单的题目并没有过多的体现java的特性,甚至不需要用到在题目中所给到的类,只是单纯的用if和else和if else就可以写出来,因为我就是这么写的,在题目中说到,输入格式应该是菜品+份额(换行),菜品+份额(换行)最后以end结尾,因为我们并不知道我们的题目中一共会输入多少组数据,所以我们并不能限制一共点菜的次数,我们理所当然的会想到我们可以用一个while语句包含这个点菜的过程,用一个字符串接收空格之前的所有字符,然后接收一个数字,然后在while中判断这个字符串所接收的字符是否为end,如果是end,就要结束点菜,进行计算总价,若不是,就进行下一轮点菜。
代码如下:
s=input.next();
while(!s.equals("end"))
{
int a=input.nextInt();
if(s.equals("西红柿炒蛋"))
{
sum+=Math.round(15*price[a-1]);
}
else if(s.equals("清炒土豆丝"))
{
sum+=Math.round(12*price[a-1]);
}
else if(s.equals("麻婆豆腐"))
{
sum+=Math.round(12*price[a-1]);
}
else if(s.equals("油淋生菜"))
{
sum+=Math.round(9*price[a-1]);
}
else
{
System.out.println(s+" does not exist");
}
s=input.next();
}
(在此次点菜中,没有用到题目中所给的类,在以后的题目中会用到)
当我们了解到了该如何设计程序的框架了以后,我们就该考虑该怎么去分别去输入菜名和份额,当s为end的时候,while循环就会结束,若不是end,则循环内还会接收一个数字,这个数字就对应相关的份额(1,2,3),最后用sum数组存起来输出就好了。
(2).作业2的7-2:菜单计价程序-2
我的类图:

在这次点菜中,我们就不能直接用if和else进行答题了,但是我们的因为会有很多细节考虑不到(或许也行,不过我选择改邪归正),所以我们运用到了题目中所给到的类:
class Dish
{
String name;//菜品名称
int unit_price; //单价//总价
int getPrice(int portion)//计算菜品价格的方法
{
double s=0;
switch(portion)
{
case 1:s=unit_price*1;break;
case 2:s=unit_price*1.5;break;
case 3:s=unit_price*2;break;
}
return (int)Math.round(s);
}
}
在Dish类中,我主要进行一个计算的过程,在getPrice方法中传入份额,运用switch选择语句进行计算,最后返回最终金额。
class Menu
{
Dish[] dishs=new Dish[15];
Dish searthDish(String dishName,int k)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
{
for(int i=0;i<k;i++)
{
if(dishName.equals(dishs[i].name))
return dishs[i];
}
return null;
}
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
{
Dish d=new Dish();
d.name=dishName.substring(0);
d.unit_price=unit_price;
return d;
}
}
在Menu类中,定义了DIsh数组,我一共定义了15个(因为我猜他不会超过15个。我猜对了),还有两个重要的方法,searthDIsh中主要是用于在添加菜品信息之前进行确认,要添加的菜品在此之前是否已经添加过了,进行一遍遍历,若没有发现重复的菜品名,就会返回NULL,若发现了相同的菜品名,就会返回此菜品数组,而在addDish方法中,就是进行添加菜品。
class Record
{
int orderNum;//序号\
Dish d;//菜品\
int portion;//份额(1/2/3代表小/中/大份)\
int flag=0;//是否被删除
int num;
int getPrice()//计价,计算本条记录的价格\
{
return (int)Math.round(d.getPrice(portion)*num);
}
}
对于我i定义的Record类,在单独看来并没有什么特别明显的作用,它主要是起到一个连接的作用,其中定义了Dish类,在下面的Order类中也是作为一个数组。
class Order {
Record[] records=new Record[100];//保存订单上每一道的记录
int getTotalPrice(int n)//计算订单的总价
{
int s=0;
for(int i=1;i<=n;i++)
if(records[i].flag==0)
s+=records[i].getPrice();
return s;
}
Record addARecord(int orderNum,Dish d,int portion,int num)//添加一条菜品信息到订单中。
{
Record re=new Record();
re.d=new Dish();
re.orderNum=orderNum;
re.d=d;
re.portion=portion;
re.num=num;
return re;
}
void delete(int orderNum)//根据序号删除一条记录
{
records[orderNum].flag=1;
}
}
在Order类中,定义了Record类数组,大小设置成了100,其实没啥,因为Dish才设置了15,也就是顺手打了上去,设置成15也行,其中定义了三个方法,其中的getTotalPrice是用于计算整个菜单中的总价,遍历数组record的时候先进行判断是否被删除,若没有被删除就把金额加上去。addARecord是添加菜品信息到订单中去,delete就是菜单中的删除点菜的功能,其实就是在每个records里面增加一个标志(flag),一开始将其设置成0,若是想将其删除,就把他的标志变为1,然后在计算菜单总价的时候会进行判断,每个records的flag是否为0,若不为0,就不会将其金额加到总金额里面去。
介绍完了类,接下来就是main函数,因为在输入的时候,我们会先进行添加菜单,然后才会进行点菜,而这些都是在一个输入里面进行的,所以我们中间需要进行判断,我们输入的这段字符串是进行点菜的还是进行菜单的添加的,通过观察发现,添加菜单的时候,字符串的开端就是菜名,而当我们进行点菜的时候,字符串的开端就是数字,这个就是我们区分是否开始点菜的关键,这时我们需要用到一个方法split:运用这个方法,我们可以将一个字符串分成多份,
String[] b=s.split(" ");//分割
这就会把s字符串中以空格为割点,将其分割成多个字符串,同时将其存入数组b中。
这样可以对输入数据进行判断,因为点菜的编号一定是从1开始,所以当b存入了所有的s所分割的字符串的后,就可以对b[0]进行判断是否等于“1”,若是,则就进入了点菜。
因为在一开始的时候,我们是将一整个字符串进行输入的,在分割了以后,也只是变成了若干个字符串,而无论是在点菜还是添加菜品中,除了编号和菜品名,其余的都是将其当作数字进行处理,所以对分割的字符串的数字字符进行转换:
menu.dishs[i]=menu.addDish(b[0],Integer.parseInt(b[1]));
将其转换成数字。
点菜进行时,也会对应输出每个菜品的金额,若没有找到该菜品,就会输出XXX does not exist,点菜结束后,可能我们会进行删除某些菜品的操作,因为一开始我们用b[]来承载被分割的字符串,而前面必然会有编号,所以我们可以对b[1]进行判断,是否为delete,若有delete,就去record里去寻找,将flag=0变为flag=1,若没找到,就会输出delete error。当删除操作也结束了以后,字符串会输入end,while便会结束循环,并输出最终金额。
(3).作业3的7-1:菜单计价程序-3
我的类图:

这次点菜题目相比于上一次点菜题目大致的框架没有太大的变化,最大的区别就是添加了代点菜功能(也就是不在同一张桌子上的人可以帮助其他桌子上的人去点菜)和时间问题(在不同的时间去点菜的结果不同)
因为大致框架大体相同,在点菜二中所列出的细节就不再陈述。
因为点菜三中可能会有多桌点菜,所以在while(s!=“end”)之后,应该再添加一个循环,当添加菜单结束以后,就会进入下一个循环进行多桌的点菜,通过观察发现,点菜之前都需要输入桌号(table),可以对第一个字符串进行判断,若是table就会跳出循环,进行下个循环:
a=in.next();
if(a.equals("end")||a.equals("table"))
break;
首先要完成点菜日期的判断:
首先我引用SimpleDateFormat类,Calendar类,Date类
这些都是Java中,关于时间的类:
void account(String a,String b) {//a接收日期,b接收时间
//计算星期几w
String[] s = a.split("/");
if(s[1].length()==1)
s[1]="0"+s[1];
if(s[2].length()==1)
s[2]="0"+s[2];
a = s[0]+"-"+s[1]+"-"+s[2];
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal=Calendar.getInstance();
Date date=null;
try {
date = format.parse(a);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
cal.setTime(date);
int w=cal.get(Calendar.DAY_OF_WEEK)-1;
if(w<=0)
w=7;
//处理时间
String[] time = b.split("/");
int h=Integer.parseInt(time[0]);
int m=Integer.parseInt(time[1]);
if(w>=1&&w<=5) {
if(h>=17&&(h<20||(h==20&&m<30)))
acc=0.8f;
else if((h>10||(h==10&&m>=30))&&(h<14||(h==14&&m<30)))
acc=0.6f;
}
else if((h>9||(h==9&&m>=30))&&(h<21||(h==21&&m<30)))
acc=1;
}
在Order类中,新添加了account方法,用于判断输入的时间的时期(周几),因为周一到周五有折扣,而周末没有,最后将Order类中的acc改为应该享有的折扣。
现在就需要解决代点菜问题,通过观察输入发现,当是给自己的桌子点菜的时候,通过split分割空格以后会分割成四分,而如果是代点菜的话,就会分割成五份,所以每次进行点菜前,可以对数组b的个数进行判断,若是5份,则就是进行代点菜,若是四份,就是进行点菜。
if(p.length==5) {
//为别桌点菜
int orderNum = Integer.parseInt(p[1]);
String dishName = p[2];
int portion = Integer.parseInt(p[3]);
int num = Integer.parseInt(p[4]);
//查找是否有此菜名
d = menu.searthDish(dishName);//接受菜品
if(d==null)//未找到,说明没有该菜品
System.out.println(dishName+" does not exist");
else {//找到了,添加订单
Record r = order.addARecord(orderNum, dishName, portion, num);
System.out.println(orderNum+" table "+table
+" pay for table "+a+" "+r.getPrice());
}
}
踩坑心得
1.作业一的第七题:
巴比伦法求平方根近似值
输入格式:
1、两个浮点数,以空格分隔,第一个是n,第二个是lastGuess最初的猜测值。例如:2 1。
2、若输入的两个数中包含负数或者lastGuess初始输入为0,认定为非法输入
输出格式:
1、输出n的平方根近似值:lastGuess。例如:1.4142157
2、非法输入时输出:"Wrong Format" }
在上学期 的时候,有人告诉我,遇事不决用double,确实适用于绝大多是场景,但是如果这道题用的还是double的话,就会出现很多测试点过不去的情况:

但是若把格式改为float,所有的测试点都会过去:

2.作业三的第五题:
面向对象编程(封装性)
在写这道题的时候,我自己是有着思路的,我也按照我的思路在eclipse中把代码敲了出来,代码也成功的运行出了我想要的结果,但是当我将代码复制到pta里面的时候,就会给我报错:

后来请教完同学后明白,不仅仅需要把自己敲的代码复制上去,还需要把题目中所给的代码复制到最前面才行。
完善后终于过去了。
主要困难以及改进建议
在这三次作业集中,毋庸置疑,三次点菜确实是一个大的难题,除了点菜以外,最让我觉得难以处理的就是习题集三中的部分题目,其中第二第三题主要让我们去除重复元素,这种题目正常来写就是对一整个数组中的元素进行遍历,若发现相同的元素,就删除,但是按照这种常规的写法,很容易就会超时,测试点也一直过不去,经过查阅资料后我选择运用HasMap进行解题,但是也会有一个问题,就是当把所有的数据存到HashMap中去,当它输出的时候,元素没有问题,就是会在起始位置加上中括号,并且每个元素之间都会有逗号,后面经过再次查阅资料,发现使用LinkedHashSet后,元素不会自动排序,而且也不会有逗号和中括号,就很nice!
总结
1.在这三次题目集中,我觉得我算是对Java有了初步的认知,大致了解了一些java有关的语法知识内容,了解到了面向对象的概念,更好的理解的面向对象的编程思路,懂得程序设计的可用性以及代码编写的规范性,也算是初步的入门了。
2.但是也就像我所说,我也仅仅只是刚刚入门,了解到的东西还是很皮毛,就比如Map类在我看来就可以深入研究下去,肯定会有很多的收获,又比如常用的ArrayList类也并没有很好的掌握,这也是我以后的学习中需要加强练习的
3.这三个题目集我看来对我的帮助还是很大的,让我觉得就是学到了什么知识就可以在题目中去运用到,但是后面的题目集我觉得有点一味的追求点菜了,就比如学到了多态,继承,接口但是没有题目让我们去熟悉这些知识点,我觉得这样会让我们学的知识遗忘的很快,而且一味的出点菜题目,题目难度确实很大,而且是一环扣一环的,没有对其进行及时的讲解就发出了下一个题目集,当一个点菜没有写完的时候,下一个根本没法写,而且还是希望可以公布测试点,有些测试点过不去,还没有及时的讲解,很容易让人一头雾水,然后一头雾水的进行下一次点菜,结果还是一头雾水的错,更加的迷茫。
4.希望多一些与我们学到的相关知识所配套的题目,可以给我们巩固学到的知识。