• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Recommended Posts

前言:

从第7周到第10周的四周时间里,我们在面向对象这门学科里学到的东西真的不多,但是学到的东西真的更深刻,更难理解。即便如此,我们实际上已经应用了一些作业。在这篇序言中,先总结一下接下来四周所学的知识点。在这四周的开始,我们主要涉及用java编写C语言的链表函数,虽然java中有一个容器可以代替链表函数,但是我们需要的是在不使用这个函数的情况下实现链表函数。在这四周里,我觉得我学到的最重要的知识是正则表达式。正则表达式的内容其实不算少,所以没学到多少。我只是在有必要使用正则表达式或者使用正则表达式会使代码编写更容易的时候,临时在网上搜索相关信息,以便在做作业时学习和使用。对继承和多态也有了更深入的理解和应用。从这几周布置的作业来看,作业量没有以前多,但是难度有了很大的提高,尤其是一些问题,需要做一天甚至更长时间。

设计与分析:

先说这次考试的题目分析,我觉得比较简单。

在过去的几周里,我们终于对java进行了一次考试。时间限制是两个半小时。总共有三个问题,这三个问题是递进的。也就是说,第一个问题是对第一个问题的改进,而第三个问题有时是对第二个问题的改进。所以,如果你连第一题都不会做或者不做,那么这次考试就吹了。不过还好题目难度不算太大。除了做题时有些粗心的错误,其他的都写得很顺利。我来详细解释分析一下这次考试的题目。

jsg0jc0w2cv3679.png

第一题的类图如上,本题设计的知识点只是聚合。在这个主题中,我通过在main函数中添加两个新的点来将它传递给line。将两点赋给线的两点类型的私有属性,代码如下,比较简单。在line的显示中也调用了两点的显示方法,所以我只需要在main中调用一次line的显示方法。

gzb2nzls30w3680.png

下一个第二题的类图如下:

2c4mrz0hyqj3681.png

这个高级主题使用继承和多态。题目中创建了一个元素抽象类,线、点、面都是这个抽象类的子类。在这个抽象类中,定义了一个显示方法,它由三个子类继承。

hfstg4buq4j3682.png

这次我的main里的代码如上图,我也和第一个问题一样。我创建了两个点,然后将它们传递到线中。但是,继承和多态的区别在于:我更新一个元素变量,然后我会按照标题所示的例子,把原来新生成的元素的子类依次赋给该元素,并调用display方法,这样就完成了这个标题。

第三个类图如下:

3gxn0hu5nd23683.png

01fwq03tnt13684.png

//www.icode9.com/i/l/?n=22&i=blog/2550995/202205/2550995-20220501221557338-612222562.png"/>

 

 这道题目倒是不如前面那两道题目那么好做我这回用上了容器的方法,将依据输入数字所选择的创建对象都传入我所new的go中,再在最后使用for-each遍历go中的每一个成员在一次调用display方法,最终得到结果。但是我在这一题中遇上了麻烦,经过我多次检查我才发现原来是我在对输入的index参数的判断时判断错误,导致我这道题目卡了好久。做完之后我对我自己都是大为无语,看来马虎不得啊,一旦马虎就可能导致卡好久。看来以后做题目需要多加注意了。

 

接下来我们来分析PTA上的题目集

在这几周的PTA题目集倒是没有之前布置的那么多,但是难度却是大为提升了。

先讲解题目集6吧,在题目集6中倒是难度不大,其中基本上是正则表达式的题目,主要目的就是让我们学习正则表达式的用法。

iouqpaol3gz3685.png

 

 

 这便是第一题的全部代码,很简单吧,主要就是让我们第一步接触正则表达式。其中[0]{1}\\d+就是判断开头是否为0,前面的s.length()则是判断输入的字符串长度是否符合条件。

 

接下来的第二题:

fqvj2pfjitt3686.png

 

 

 3wr01cl3iy03687.png

 

 代码依旧简单,我是通过输入字符串之后将其赋值给StringBuilder的str,用了StringBuilder就可以对字符串中的每一个字符进行查找与调换位置等之类的操作。

fxgbujotycn3688.png

 

 

 24g0o2hjzjq3689.png

 

 第三题如上所示,我们分析匹配内容。{0-9A-Za-z]{4}}的理解就是匹配输入的字符串是否是数字、大写字母或小写字母,并且总数是否为4个。

在之后我们有一道bank类题目,要求如下:

vkhw5xba0gw3690.png

 

 

 其中我对输入错误进行分析:

①输入错误处理  如果输入卡号不存在,则输出“Sorry,this card does not exist.”。

 如果输入 ATM 机编号不存在,则输出“Sorry,the ATM's id is wrong.”。

 如果输入银行卡密码错误,则输出“Sorry,your password is wrong.”。

 如果输入取款金额大于账户余额,则输出“Sorry,your account balance is insufficient.”。

 如果检测为跨行存取款,则输出“Sorry,cross-bank withdrawal is not supported.”。

对于以上的错误判断点则是需要依次判断,由上到下来进行判断。

 

接下来分析本次的重点题目:PTA上的图形类题目,就是这些题目花费了我大量的时间与精力,要求如下:

 

用户输入一组选项和数据,进行与四边形有关的计算。
以下四边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
选项包括:
1:输入四个点坐标,判断是否是四边形、平行四边形,判断结果输出true/false,结果之间以一个英文空格符分隔。
2:输入四个点坐标,判断是否是菱形、矩形、正方形,判断结果输出true/false,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
3:输入四个点坐标,判断是凹四边形(false)还是凸四边形(true),输出四边形周长、面积,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
4:输入六个点坐标,前两个点构成一条直线,后四个点构成一个四边形或三角形,输出直线与四边形(也可能是三角形)相交的交点数量。如果交点有两个,再按面积从小到大输出四边形(或三角形)被直线分割成两部分的面积(不换行)。若直线与四边形或三角形的一条边线重合,输出"The line is coincide with one of the lines"。若后四个点不符合四边形或三角形的输入,输出"not a quadrilateral or triangle"。
后四个点构成三角形的情况:假设三角形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z 不与xy都相邻,如z x y s、x z s y、x s z y
5:输入五个点坐标,输出第一个是否在后四个点所构成的四边形(限定为凸四边形,不考虑凹四边形)或三角形(判定方法见选项4)的内部(若是四边形输出in the quadrilateral/outof the quadrilateral,若是三角形输出in the triangle/outof the triangle)。如果点在多边形的某条边上,输出"on the triangle或者on the quadrilateral"。若后四个点不符合四边形或三角形,输出"not a quadrilateral or triangle"。

 

其实说句实话,这边的题目在编程上其实是并不难的,难的地方主要就是在这题目中的对图形的判断。这里需要用上大量的数学知识,在这题中的每一个判断我基本上都要临时查找资料来确定使用方法。

在这里我写了一个比较好用的类,可以将判断错误输入在这个类中完成。

代码如下:

xdwnd035hoj3691.png

 

 

 vk0hbfge5ax3692.png

 

 我在这题中的做法是将一行输入的字符串用空格分割,代码如下:

idy1to0gggz3693.png

 

 

 我在这用上了一个容器list,类型是coordinate,目的是匹配到空格之后将这字符分割,随后一个个加入到coordinate中每一个coordinate都是加入了一个坐标,随后在这个类之中对输入的坐标是否合法在进行判断,若是判断结果为有误,则直接System.exit(0);来结束整个程序。不过这里需要注意的是要排除开头是空格的情况,否则程序会报错。

下面对每一个判断条件进行分析:

 

 

1:输入四个点坐标,判断是否是四边形、平行四边形,判断结果输出true/false,结果之间以一个英文空格符分隔。
2:输入四个点坐标,判断是否是菱形、矩形、正方形,判断结果输出true/false,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
3:输入四个点坐标,判断是凹四边形(false)还是凸四边形(true),输出四边形周长、面积,结果之间以一个英文空格符分隔。 若四个点坐标无法构成四边形,输出"not a quadrilateral"
4:输入六个点坐标,前两个点构成一条直线,后四个点构成一个四边形或三角形,输出直线与四边形(也可能是三角形)相交的交点数量。如果交点有两个,再按面积从小到大输出四边形(或三角形)被直线分割成两部分的面积(不换行)。若直线与四边形或三角形的一条边线重合,输出"The line is coincide with one of the lines"。若后四个点不符合四边形或三角形的输入,输出"not a quadrilateral or triangle"。
后四个点构成三角形的情况:假设三角形一条边上两个端点分别是x、y,边线中间有一点z,另一顶点s:
1)符合要求的输入:顶点重复或者z与xy都相邻,如x x y s、x z y s、x y x s、s x y y。此时去除冗余点,保留一个x、一个y。
2) 不符合要求的输入:z 不与xy都相邻,如z x y s、x z s y、x s z y
5:输入五个点坐标,输出第一个是否在后四个点所构成的四边形(限定为凸四边形,不考虑凹四边形)或三角形(判定方法见选项4)的内部(若是四边形输出in the quadrilateral/outof the quadrilateral,若是三角形输出in the triangle/outof the triangle)。如果点在多边形的某条边上,输出"on the triangle或者on the quadrilateral"。若后四个点不符合四边形或三角形,输出"not a quadrilateral or triangle"。

 

第一个判断是判断输入的四个点所构成的图形的邻边是否斜率相等,若是相等,则不可构成四边形。

第二个则是判断则是在判断是否为四边形的基础上判断对边是否斜率相等,若是,则是平行四边形,判断四边相等则为菱形,在判断邻边斜率,若出现方向向量相乘为0的情况则表示垂直,垂直则可能是矩形或正方形。

判断凹凸性则为以下代码:

jblemdqw2nn3694.png

 

 通过这种方法就可以判断。

方法为

  如果M在ABCD内部,则ABCD任意一点和M所构成的向量在改点所在边的中间,即叉积的乘积<0。如下:

       AB × AM  * AM × AD<0

       BC × BM  * BM × BA<0

       CD × CM * CM × CB<0

       DA × DM * DM × DC<0

对于这道题目,虽然方法是知道,但能不能完整得写出来又是另一回事了,因为在这道题目中用上了大量的数学知识,不仅如此,在这之中还隐藏着许多的坑点,一不小心就会落入坑中并且很难爬出。

 

之后我们再分析链表题目,对于这一道题目我认为是重点。

在这链表中我实现了一个接口,目的就是能够让人一眼就知道我的代码中主要有哪些方法。

frm3rrfyzo13695.png

gxyzjfrjx1d3696.png

 

  在这之中写了一个节点类,而在主要实现链表的类之中就是设置了head,curr,tail。head就是在链表的头节点,我的代码在增加链表成员时时在head之后开始加入第一位,那么对于我的最终链表输出时也是从head的下一位开始输出的。

输出方式如下:

5ikm3wcakb23697.png

 

 而对于curr则是主要用在了add和remove上,对于add来说,我是将原先已经建造的链表通过不断地读取下一位找到需要增加的节点部分的前一个节点,然后再创建一个新node,在新node中将需要的内容输入赋值之后对它的previous接入到前一个节点上,而对它的next则赋值为下一个节点。一次来实现链表的add。其中若是要增加最后一个节点上的成员,则可以调用另一个add,因为另一个add就是在最后一位增加成员。

当我在增加节点的过程之中,我就在每一次的add的最后一个节点的next赋值为null,然后再赋值为tail,因此实现了一个尾节点,在最后的print中则是从head的next遍历到tail的previous为止。

给出代码或许更好理解:

package LList;

public class LList<E> implements DoubleLinkedListImpl<E> {

private Node<E> head;// 头结点,非第一个节点
private Node<E> curr;// 当前节点
private Node<E> tail;// 最后一个节点
private int size;// 当前链表节点数

public LList(Node<E> head, Node<E> tail) {
this.head = head;
this.tail = tail;
}

public boolean isEmpty() {
if (this.size == 0) {
return true;
} else {
return false;
}
}

public int getSize() {
if (isEmpty()) {
System.out.println("this list is empty");
}
return this.size;
}

public E getData(int index) {
if (isEmpty()) {
System.out.println("this list is empty");
return null;
}
if (index < 0 || index >= size) {
System.out.println("invalid index");
return null;
}
curr = head;
for (int i = 0; i <= index; i++) {
curr = curr.getNext();
}
System.out.println("该位置成员为:" + curr.getData());
return curr.getData();
}

public void remove() {
if (isEmpty()) {
System.out.println("this list is empty");
return;
}
curr = head;
while (true) {
if (curr.getNext() == tail) {
break;
}
curr = curr.getNext();
}
curr.getPrevious().setNext(tail);
tail.setPrevious(curr.getPrevious());
size--;
}

public void remove(int index) {
if (isEmpty()) {
System.out.println("this list is empty");
return;
}
if (index < 0 || index >= size) {
System.out.println("invalid index");
return;
}
curr = head;
for (int i = 0; i < index; i++) {
curr = curr.getNext();
}
Node<E> R = curr.getNext();
curr.setNext(R.getNext());
curr.getNext().setPrevious(R.getPrevious());
size--;
}

public void add(int index, E theElement) {
if (isEmpty() && index == 0) {
add(theElement);
} else if (index < 0 || index > size) {
System.out.println("invalid index");
return;
} else {
curr = head;
for (int i = 0; i < index; i++) {
curr = curr.getNext();
}
curr.setNext(new Node<E>(theElement, curr.getNext(), curr));
size++;
}
}

public void add(E element) {
if (size == 0) {
head.setNext(tail);
}
curr = head;
while (true) {
if (curr.getNext() == tail) {
break;
}
curr = curr.getNext();
}
Node<E> node = new Node<E>(element, null, null);
node.setPrevious(curr);
node.setNext(tail);
tail.setPrevious(node);
curr.setNext(node);
this.size++;
}

public E getFirst() {
if (isEmpty()) {
System.out.println("this list is empty");
return null;
}
System.out.println("第一位成员为:" + head.getNext().getData());
return head.getNext().getData();
}

public E getLast() {
if (isEmpty()) {
System.out.println("this list is empty");
return null;
}
System.out.println("最后一位成员为:" + tail.getPrevious().getData());
return tail.getPrevious().getData();
}

public void printList() {
if (isEmpty()) {
System.out.println("this lsit is empty");
return;
}
System.out.print("现在链表为:");
for (curr = head.getNext(); curr != tail; curr = curr.getNext()) {
System.out.print(curr.getData() + " ");
}
System.out.println("\n");
}

}

如上可以明白链表的原理。

踩坑心得:

在编写代码是要仔细,不能够马虎大意,不然就有可能会像我一样由于没即使发现问题而花费大量时间。

对于容器的使用,要尤其注意泛型,泛型的类型是什么,那么所加入的成员就应该是什么类型,不然会报错。

 总结:

对于这次的阶段总结我要说的其实不多,在java的学习中我发现现在越来越加入了逻辑思维,在许多的题目中都蕴含大量的逻辑思考,不只这些,其实还含有这大量的数学知识,我们平时所使用的数学对一些事物的判断方法在平时我们并没有深入理解,从而在编写代码是会遇上困难,因为我们写代码是需要弄明白它们的原理才能够做到很好的判断成功,不然你总是会在自己做完判断方法之后才发现并不完整,从而不能拿到满分。

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now