第二次Blog作业 21201112 李夏楠
题目集4:
Task:用户输入一组选项和数据,进行与直线有关的计算。选项包括:
1:输入两点坐标,计算斜率,若线条垂直于X轴,输出"Slope does not exist"。
2:输入三个点坐标,输出第一个点与另外两点连线的垂直距离。
3:输入三个点坐标,判断三个点是否在一条线上,输出true或者false。
4:输入四个点坐标,判断前两个点所构成的直线与后两点构成的直线是否平行,输出true或者false.
5:输入四个点坐标,计算输出前两个点所构成的直线与后两点构成的直线的交点坐标,x、y坐标之间以英文分隔",",并输出交叉点是否在两条线段之内(不含四个端点)的判断结果(true/false),判断结果与坐标之间以一个英文空格分隔。若两条线平行,没有交叉点,则输出"is parallel lines,have no intersection point"。
设计思路:通过用swich,实现5种输入的选择。
总结:线的计算,其中设计比较难的地方,就是对于输入数据格式错误的判断,在这道题目中,我选择利用正则表达式完成输入格式正确与否的判断,主要代码如下。
static Boolean validate2(String s) {
if(s.matches("(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))"
+ "[\\s]{1})+(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?)))+"))
return true;
else
return false;
}
static Boolean validate3(String s) {
if(s.matches("(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))"
+ "[\\s]{1})+(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))"
+ "[\\s]{1})+(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?)))+"))
return true;
else
return false;
}
这种写法的坏处在于,你需要一个一个判断,比如说你输入的是三个点的坐标,你需要先判断它是不是符合输入一个点的坐标,再判断是不是符合输入两个点的坐标,最后判断是不是符合输入三个点的坐标。因为如果你直接判断是否是输入三个点的坐标的话,你无法确定它应该输出"Wrong Format",还是输出"wrong number of points"。
当然,经过后面计算三角形,计算四边形,我发现了更好的写法,主要代码如下。
public static boolean vaildata(String string) {
if (string.charAt(0) > '5' || string.charAt(0) < '1') {
return false;
}
if (string.charAt(1) != ':') {
return false;
}
string = string.substring(2, string.length());
String[] split = string.split(" ");
int j = 0;
for (j = 0; j < split.length; j++) {
if (!vaildata1(split[j])) {
return false;
}
}
return true;
}
public static boolean vaildata1(String s) {
if(s.matches("(([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?))[,]([+|-]?[1-9]+([\\.][0-9]+|[0-9]*)|([+|-]?[0]([\\.][0-9])?)))"))
return true;
else
return false;
}
这个表达式可以判断输入的格式是否正确,并且不限制于输入点的数量。比如说输入的是1:23,43 3,5 3,6 7,5 ,vaildata会想判断1和:的输入是否合法,再把23,43 3,5 3,6 7,5放入一个字符串,这个字符串利用.split(" "),将字符串以空格为分开标志,存入一个字符串数组。接着判断这个字符串数组中的每个元素是否符合输入一个点的情形,比之前的正则表达式通用性更好,而且可以判断是输入点的数量有问题,还是输入点的格式有问题。
还有一个重点就是利用射线法判断点是否在三角形内部,代码如下:
static class point{
double x;
double y;
public point(double x, double y) {
this.x = x;
this.y = y;
}
}
public static double max(double num1,double num2){
if(num1>num2){
return num1;
}
else {
return num2;
}
}
public static double min(double num1,double num2){
if(num1>num2){
return num2;
}
else {
return num1;
}
}
public static boolean isinpolygon(double x,double y,double x1,double y1,double x2,double y2,double x3,double y3) {
double pointx[] = {x1,x2,x3};
double pointy[] = {y1,y2,y3};
int ncross=0;
for(int i=0;i<3;i++) {
point p1 = new point(pointx[i],pointy[i]);
point p2 = new point(pointx[(i + 1) % 3],pointy[(i + 1) % 3]);
if (p1.y == p2.y)
continue;
if (y < min(p1.y, p2.y))
continue;
if (y >= max(p1.y, p2.y))
continue;
double tempx = (y - p1.y)*(p2.x - p1.x) / (p2.y - p1.y) + p1.x;
if (tempx > x)
ncross++; //只统计单边交点
}
return(ncross % 2 == 1);
}
题目集5
Task:卡片大小排序游戏规则:随机发放一些卡片给学生, 卡片仍然分为四种形状:圆形(Circle)、矩形(Rectangle)、三角形(Triangle)及梯形(Trapezoid), 并给出各种卡片的相应参数,要求学生首先根据卡片类型将所有卡片进行分组(一个类型分为一组, 所以最多四组),然后能够对每组内的卡片根据面积值从大到小进行排序,同时求出该组内所有卡片 的面积之和,最后求出每组卡片面积之和中的最大值。
类图如下:

总结:这次的作业比较简单,题目提供了类图。通过这次的作业,主要的学习到的有两点,一是对ArrayList的使用,设计了一个Card的容器类。二是设计Comparable接口,实现了对容器里Card的面积进行排序。此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
@Override
public int compareTo(Card card) {
// TODO 自动生成的方法存根
if(card.getShape().getArea()-this.getShape().getArea()<0) {
return -1;
}
else if(card.getShape().getArea()==this.getShape().getArea()) {
return 0;
}
else {
return 1;
}
}
题目集6
Task:
编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。
类图如下:

总结:做这道题目的时候还是经历了一些坑的,最开始的时候,没有给每一个实体类设计一个类,后面进行了重写。这道题的主要难点在于,各个类之间的关系,最后我确立的关系是,银联类里有着存放银行种类的容器,银行类有存放用户和ATM的两个容器,用户类有存放账户的容器,账户类有存放银行卡的容器。通过这样的设计,合理设计各个实体类之间的关系。
Task:
对软件学院2020级同学学号进行校验,学号共八位,规则如下:
- 1、2位:入学年份后两位,例如20年
- 3、4位:学院代码,软件学院代码为20
- 5位:方向代码,例如1为软件工程,7为物联网
- 6位:班级序号
- 7、8位:学号(序号)
总结:设计表示正则表达式,将学号中不相关的部分拆开,分别实现,最后组合起来,得到了最终的正则表达式。前四位为固定的2020,五六位互相关联为学院和班级,七八位互相关联为学号。
if(s.matches("2020(1[1-7]|61|7[1-3]|8[1-2])(0[1-9]|[1-3][0-9]|40)")) {
题目集7
Task:用户输入一组选项和数据,进行与四边形有关的计算。 四边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最 后一个输入的顶点相邻。
总结:这个题目中有一个很重要的信息,就是输入的四个点是连续的,这个条件给后面的四边形判定,带来了很多便捷之处。这次的处理,虽然是四边形,但是很多时候,我们可以把四边形切成两个三角形来处理,比如判断点是否在四边形上,可以用到之前判断点是否在三角形内部的射线法,还有四边形面积的处理,也是通过分成两个三角形,套用海伦公式。在写题的过程中还遇到了一个问题,就是如何判断两直线平行,如果用斜率相等的话,斜率不存在的情况很难考虑到,后面通过公式的变换,可以考虑到各种情况的两直线平行,代码如下:
public static boolean isExist(double x1, double y1, double x2, double y2, double x3, double y3, double x4,
double y4) {
if ((y4 - y3) * (x4 - x2) == (y4 - y2) * (x4 - x3))
return false;
else if ((y4 - y3) * (x4 - x1) == (y4 - y1) * (x4 - x3))
return false;
else if ((y4 - y2) * (x4 - x1) == (y4 - y1) * (x4 - x2))
return false;
else if ((y3 - y2) * (x3 - x1) == (y3 - y1) * (x3 - x2))
return false; // 任意三个顶点成直线,非四边形
else
return true;
}
21级软件工程专业期中考试(OOP)
Task:在“点与线(继承与多态)”题目基础上,对题目的类设计进行重构,增加容器类保存点、线、面对象,并对该容器进行相应增、删、遍历操作。
类图如下:

总结:应该说这次考题的题目要比平常写作业的简单的多,都给了类图,考察的主要是类的设计,继承与多态和容器。考察的都不深,只是最基础的使用。
element = p1;//起点Point
element.display();
element = p2;//终点Point
element.display();
element = line;//线段
element.display();
element = plane;//面
element.display();
也就这几段代码最有特点,通过调用同一个函数,实现了不同的输出,展现出多态的特性。
超星双向链表
Task:在单链表基础上改写代码,实现双向链表数据结构。
踩坑心得:双链表是在单链表的基础上改进而来,并不是很难,但是在写public void add(int index, E theElement) 这个函数的时候踩坑了。在指定位置插入节点之后,这个节点后一个节点的getPrevious()会指向这个节点的前一个节点,而不去指向这个节点。最后,通过画图,重写了这个函数解决问题。
public void add(int index, E theElement) {
if(index < 1 || index > this.size + 1) {
return ;
}
Node<E> curr = new Node<E>();
curr.setData(theElement);
curr.setNext(null);
if(this.size == 0) {//当前链表为空的情况
curr.setPrevious(head);
head.setNext(curr);
this.curr = this.tail = curr;
}else if(index == this.size + 1){//在链表尾部插入节点的情况
curr.setPrevious(tail);
this.tail.setNext(curr);
tail = curr;
}else{//插入中间节点的情况
Node<E> tempNode = head;
//找到待插入位置的前一个节点
for(int i = 1; i < index; i++) {
tempNode = tempNode.getNext();
}
tempNode.getNext().setPrevious(curr);
curr.setPrevious(tempNode);
curr.setNext(tempNode.getNext());
tempNode.setNext(curr);
}
this.size ++;
}
总结:在双链接写插入节点时,要先写tempNode.getNext().setPrevious(curr),通过这样写,来把节点插入链表,不能用setNext(),如果用了tempNode.setNext()会改变temp的后节点指向,tempNode的后节点指向一定要放的最后来写。
第四次实验报告
Task:农夫过河问题
类图如下:

踩坑心得:这次作业大概是做过有史以来类最多的一次作业,规则有一个抽象类,载具有一个抽象类,物品有一个抽象类,Game有一个抽象类。这个题目比较难的就是理清这个程序运行的思路,如何调用每个类,类里面的每个方法,但经过思考也不是很难,只是比较耗时。
总结:这次的农夫过河写的是最多的,但是拓展性是最好的,可以在Game中增加动物植物等,选择它们吃的对象,也可以在Boat中做修改,改变一次性可以带过河的物品件数。同时掌握了final的使用方法,当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让它被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是final类中的所有成员方法都会被隐式地指定为final方法。

浙公网安备 33010602011771号