目 录
1 实验目标概述... 1
2 实验环境配置... 1
3 实验过程... 1
3.1 Magic Squares. 2
3.1.1 isLegalMagicSquare().. 2
3.1.2 generateMagicSquare() 3
3.2 Turtle Graphics. 5
3.2.1 Problem 1: Clone and import 5
3.2.2 Problem 3: Turtle graphics and drawSquare. 5
3.2.3 Problem 5: Drawing polygons. 5
3.2.4 Problem 6: Calculating Bearings. 5
3.2.5 Problem 7: Convex Hulls. 5
3.2.6 Problem 8: Personal art 6
3.2.7 Submitting. 6
3.3 Social Network. 6
3.3.1 设计/实现FriendshipGraph类... 6
3.3.2 设计/实现Person类... 7
3.3.3 设计/实现客户端代码main(). 8
3.3.4 设计/实现测试用例... 8
3.4 Tweet Tweet 10
3.4.1 Problem 1: Extracting data from tweets. 10
3.4.2 Problem 2: Filtering lists of tweets. 10
3.4.3 Problem 3: Inferring a social network. 10
3.4.4 Problem 4: Get smarter 10
4 实验进度记录... 10
5 实验过程中遇到的困难与解决途径... 11
6 实验过程中收获的经验、教训、感想... 11
6.1 实验过程中收获的经验和教训... 11
6.2 针对以下方面的感受... 11
1 实验目标概述
本次实验通过求解四个问题,训练基本 Java 编程技能,能够利用 Java OO 开。
发基本的功能模块,能够阅读理解已有代码框架并根据功能需求补全代码,能够。
为所开发的代码编写基本的测试程序并完成测试,初步保证所开发代码的正确性。
另一方面,利用 Git 作为代码配置管理的工具,学会 Git 的基本使用方法。
基本的 Java OO 编程;
基于 Eclipse IDE 进行 Java 编程;
基于 JUnit 的测试;
基于 Git 的代码配置管理。
2 实验环境配置
简要陈述你配置本次实验所需开发、测试、运行环境的过程,必要时可以给出屏幕截图。
特别是要记录配置过程中遇到的问题和困难,以及如何解决的。
- 用eclipse在本地新建一个项目;
- 在命令行中用“git init”新建库
- 利用git remote add origin <url>将本地库和远程库链接
- 将远程源中master分支的仓库拉到本地git push -u origin maste
- Git add .打包本地项目
- Git commit -m “20190301”为本地文件做标记
- Git push origin master推送上仓库
在这里给出你的GitHub Lab1仓库的URL地址(Lab1-学号):
https://github.com/ComputerScienceHIT/Lab1-1170400307
3 实验过程
请仔细对照实验手册,针对四个问题中的每一项任务,在下面各节中记录你的实验过程、阐述你的设计思路和问题求解思路,可辅之以示意图或关键源代码加以说明(但无需把你的源代码全部粘贴过来!)。
为了条理清晰,可根据需要在各节增加三级标题。
3.1 Magic Squares
问题理解:本问题要求实现判断一个nxn矩阵是否是一个幻方,并且理解一个针对n为奇数的幻方的生成算法。主要考察点:Java基本语法,文件读写,判断输入的合法性。
3.1.1 isLegalMagicSquare()
1. 读入文本。
InputStreamReader reader = new InputStreamReader(new FileInputStream(new File("src/P1/txt/" + fileName)),"UTF-8");
BufferedReader stream = new BufferedReader(reader);
2检查有没有非法字符,对于本题来说,合法的字符只有’0’到’9’和’\t’。
if(test[i].contains(".") || test[i].contains("-"))
{
System.out.print("contais - or .");
return false;
}
3检查是不是方阵。检查每一行的字符数是否等于行数。
if(checkStrings.length!=row)
{
System.out.print("lines is not equal rows");
return false;
}
4以上条件都满足时再判断是不是幻方。
for (int i = 0; i < row; i++) {
sum[i]=0;
checkStrings=test[i].split("\t");
if(checkStrings.length!=row)
{
System.out.print("lines is not equal rows");
return false;
}
for (int j = 0; j < checkStrings.length; j++) {
result[i][j]=Integer.valueOf(checkStrings[j]);
}
for (int j = 0; j < row; j++) {
sum[i]=sum[i]+result[i][j];
}
}
for (int i = 0; i < row; i++) {
sum[i+row]=0;
for (int j = 0; j < row; j++) {
sum[i+row]=sum[i+row]+result[j][i];
}
}
sum[2*row]=0;
sum[2*row+1]=0;
for(int i=0;i<row;i++)
{
sum[2*row]=sum[2*row]+result[i][i];
sum[2*row+1]=sum[2*row+1]+result[i][row-1-i];
}
for (int i = 1; i <= 2*row+1; i++) {
if(sum[i-1]!=sum[i])
{
System.out.print("sums are not equal");
return false;
}
3.1.2 generateMagicSquare()
思路:使用罗伯法构造一个n为奇数的nxn幻方。罗伯法的算法为把1(或最小的数)放在第一行正中;按以下规律排列剩下的(n×n-1)个数:
(1)每一个数放在前一个数的右上一格;
(2)如果这个数所要放的格已经超出了顶行那么就把它放在底行,仍然要放在右一列;
(3)如果这个数所要放的格已经超出了最右列那么就把它放在最左列,仍然要放在上一行;
(4)如果这个数所要放的格已经超出了顶行且超出了最右列,那么就把它放在底行且最左列;
(5)如果这个数所要放的格已经有数填入,那么就把它放在前一个数的下一行同一列的格内。
3.2 Turtle Graphics
该任务需要我去自主学习java的一个第三方画图方案Turtle,并且通过给出的现有的Turtle方法实现题目要求的画图任务,并且借助数学工具进行解题。
3.2.1 Problem 1: Clone and import
利用get clone命令行
3.2.2 Problem 3: Turtle graphics and drawSquare
这个函数的功能是画一个正方形。需要调用两个方法foward(int units)向当前方向画直线,长度是输入的数字,单位是内部规定单位。turn(double degrees)按照顺时针方向旋转画图方向。
3.2.3 Problem 5: Drawing polygons
这个任务包含几个小任务。
(1)calculateRegularPolygonAngle 计算正多边形的内角,(边数-2)/sides。
(2)int calculatePolygonSidesFromAngle(double angle)
这个方法和上一个类似,根据角度计算正多边形边数。
(3)drawRegularPolygon :调用calculateRegularPolygonAngle(sides)计算正多边形的内角为rotation,调用turtle.forward和turtle.turn进行前进和转向。
3.2.4 Problem 6: Calculating Bearings
calculateBearingToPoint :计算(当前点,当前朝向)构成的向量与(当前点,目标点)构成的向量之间的夹角,首先计算(当前点,目标点)构成的向量与y轴之间的tan,使用Math.atan2计算与y轴夹角,与当前朝向夹角(与y轴之间)作差计算两向量之间的夹角,需要注意负角变正角。
calculateBearings:对列表中的每两个相邻节点调用calculateBearingToPoint计算夹角。
3.2.5 Problem 7: Convex Hulls
这个是运用凸包算法。即对于一组输入的平面点集,求一个最小的集合组成的凸包,使这个凸包的所有点组成的凸多边形可以围着所有的点。
我采取的是gift-wrapping算法,这个算法形象的理解是,先选取一个必定在凸包里的点作为起点,这个点可以选取纵坐标最小的点(当存在多个纵坐标最小的点时,选取其中横坐标最小的点)。然后想象用一根绳子从起点出发,把平面上的所有点紧紧的围在一起,这条绳子上的拐点就是凸包上的点。
我的设计值得注意的几点是
1将输入的存放点集的set改成数组,方便操作
2通过向量叉积判断向量方位,例如A*B当A需要逆时针才能转向B时,A*B的值是正的。
3.2.6 Problem 8: Personal art
利用如下指令,借助函数改变绘画形状和颜色:
public static void drawPersonalArt(Turtle turtle) {
for (int i = 0 ; i < 1500; i++) {
turtle.forward(i/2);
switch ((i/15) % 10) {
case 0:turtle.color(PenColor.BLACK);break;
case 1:turtle.color(PenColor.GRAY);break;
case 2:turtle.color(PenColor.RED);break;
case 3:turtle.color(PenColor.PINK);break;
case 4:turtle.color(PenColor.ORANGE);break;
case 5:turtle.color(PenColor.YELLOW);break;
case 6:turtle.color(PenColor.GREEN);break;
case 7:turtle.color(PenColor.CYAN);break;
case 8:turtle.color(PenColor.BLUE);break;
case 9:turtle.color(PenColor.MAGENTA);break;
}
turtle.turn(91);
}
}
3.2.7 Submitting
利用git push命令行
3.3 Social Network
该任务是需要我去建立一个图,通过输入搭建有向社交网,并且给出正确的输出,对非法输入进行正确的判断。
3.3.1 设计/实现FriendshipGraph类
我采用的是邻接表的展示结构,效率较高。在List类型内装入Person类型,而且每一个Person内有List存储每一个人的序号
对于求出两个person之间的距离,先调用方法 calculateDistance
private void calculateDistance(Person name1){
int size = name1.getIdSize();
List<Integer> id = name1.getId();
for(int i = 0; i < size; i ++){
Person person = nameList.get(id.get(i));
if(!person.getKnown()){
person.setDistance(name1.getDistance()+1);
person.setKnown(true);
calculateDistance(person);
}else{
if(name1.getDistance()+1<person.getDistance()){
person.setDistance(name1.getDistance()+1);
}
}
}
}
这个方法以一个person为起点进行深度优先搜索,标记搜索过的点,并记录距起始搜索点的距离,然后通过getDistance方法获得两个person之间的信息,如果另一个person的distance是0,说明是同一个点,如果未搜索到,说明无关系,返回-1。
3.3.2 设计/实现Person类
Person设计尽量满足以下几点
1成员变量设置成private,成员变量的访问是通过成员方法进行的
2满足FreindshipGraph的要求
以下是源代码
public class Person{
private String name;
private boolean known;
private int distance;
private List<Integer> id = new ArrayList<>();
public boolean getKnown(){
return known;
}
public int getDistance(){
return distance;
}
public void setDistance(int Distance){
this.distance = Distance;
}
public String getName() {
return name;
}
public void setKnown(boolean flag){
known = flag;
}
public List<Integer> getId(){
return id;
}
public int getIdSize(){
return id.size();
}
public boolean existId(int id){
if(this.id.contains(id)){
return true;
}
return false;
}
public void setId(int p) {
Integer P = new Integer(p);
this.id.add(P);
}
public Person(String name){
this.name = name;
}
}
3.3.3 设计/实现客户端代码main()
客户端代码实验文档已经提供
FriendshipGraph graph = new FriendshipGraph();
Person rachel = new Person("rachel");
Person ross = new Person("ross");
Person ben = new Person("ben");
Person kramer = new Person("kramer");
graph.addVertex(rachel);
graph.addVertex(ross);
graph.addVertex(ben);
graph.addVertex(kramer);
graph.addEdge(rachel, ross);
graph.addEdge(ross, rachel);
graph.addEdge(ross, ben);
graph.addEdge(ben, ross);
System.out.println(graph.getDistance(rachel,ross));
System.out.println(graph.getDistance(rachel,ben));
System.out.println(graph.getDistance(rachel,rachel));
System.out.println(graph.getDistance(rachel,kramer));
3.3.4 设计/实现测试用例
主要对计算距离的算法进行了测试。
public void GetDistanceTest() {
FriendshipGraph graph = new FriendshipGraph();
Person rachel = new Person("Rachel");
Person ross = new Person("Ross");
Person ben = new Person("Ben");
Person kramer = new Person("Kramer");
Person abc = new Person("abc");
Person def = new Person("def");
Person hij = new Person("hij");
Person lmn = new Person("lmn");
graph.addVertex(rachel);
graph.addVertex(ross);
graph.addVertex(ben);
graph.addVertex(kramer);
graph.addVertex(abc);
graph.addVertex(def);
graph.addVertex(hij);
graph.addVertex(lmn);
graph.addEdge(rachel, ross);
graph.addEdge(ross, rachel);
graph.addEdge(ross, ben);
graph.addEdge(ben, ross);
graph.addEdge(rachel, def);
graph.addEdge(def, rachel);
graph.addEdge(abc, ross);
graph.addEdge(ross, abc);
graph.addEdge(hij, ross);
graph.addEdge(ross, hij);
graph.addEdge(lmn, ben);
graph.addEdge(ben, lmn);
assertEquals(1, graph.getDistance(rachel, ross));
assertEquals(2, graph.getDistance(rachel, ben));
assertEquals(0, graph.getDistance(rachel, rachel));
assertEquals(-1, graph.getDistance(rachel, kramer));
assertEquals(2, graph.getDistance(rachel, abc));
assertEquals(1, graph.getDistance(rachel, def));
assertEquals(2, graph.getDistance(rachel, hij));
assertEquals(3, graph.getDistance(rachel, lmn));
}
3.4 Tweet Tweet
3.4.1 Problem 1: Extracting data from tweets
getTimespan:
如果tweets为空则将当前时间作为始末时间点构造Timespan,否则调用getEarliestTime和getLatestTime分别获得所有tweets中的最早发表时间和最晚发表时间构造Timespan。时间比较调用Time.isBefore和Time.isAfter函数。
getMentionedUsers
检测tweet的text部分,先找到字符@,然后检测@前一个字符,当不是有效字符时,记录@后面的有效字符,即是我们要找的字符串。
3.4.2 Problem 2: Filtering lists of tweets
writtenBy:for循环检查所有tweet,获取username,然后和我们的字符串比较,相等即匹配成功。
inTimespan:利用Time.isBefore和Time.isAfter进行比较。
containing:先利用toLowerCase函数把推文内容和待查找字符串都转化为小写字母形式,然后直接调用contains函数进行检查。
3.4.3 Problem 3: Inferring a social network
guessFollowGraph:第一种证据思路是如果一名author在tweet中@过其他人,那么该author就会follow这些被@的人。扫描每条tweet,调用Extract.getMentionedUsers提取出该条tweet中所有被@到的人,将这些人加入到Map[author]->Set<Stirng>中。
public static List<String> influencers(Map<String, Set<String>> followsGraph)
influencers:按照社交网络的影响力(follow数目)对所有user进行排名。首先根据followsGraph统计每个人的follow数目,再对每个人的follow数目进行排名。
3.4.4 Problem 4: Get smarter
我采用的是最简单的寻找推文中的话题,利用话题的集合程度来表达两个人之间关系的亲密。
算法上和之间的寻找@的人物十分类似,我们的主要目的是希望找到两个具有相同话题的人,如果在此基础之上,两个人又有互相@的行为,我们就可以判定为他们的关系不应该局限于“互相影响上面”,而有可能是其他关系,例如朋友。
4 实验进度记录
请使用表格方式记录你的进度情况,以超过半小时的连续编程时间为一行。
日期 | 时间段 | 任务 | 实际完成情况 |
2019-3-1 | 15:45-17:30 | 配置好实验环境和编译器 | 按计划完成 |
2019-3-5 | 15:45-17:30 | 完成项目1 | 延期1小时完成 |
2019-3-7 | 15:45-17:30 | 完成项目2 | 遇到困难,未完成 |
2019-3-10 | 15:45-17:30 | 完成项目3 | 提前一小时完成 |
2019-3-15 | 15:45-17:30 | 完成项目4 | 遇到困难,求助谷歌 |
2019-3-17 | 15:45-17:30 | 完成实验报告 | 按计划完成 |
5 实验过程中遇到的困难与解决途径
遇到的难点 | 解决途径 |
对git使用不清楚
| 仔细阅读《git中文使用手册》 |
对于JAVA基本语法不熟悉
| 仔细学习《JAVA编程思想》 |
题目有点难度,错误比较多
| 逐次调试,改正bug |
6 实验过程中收获的经验、教训、感想
6.1 实验过程中收获的经验和教训
1.关于JAVA的一些基础知识不会,网上也没有适合的资料,学习的过程浪费了一些时间。
2.题目是英文的,阅读起来有些难度,需要借助于网络工具,很多时候对题意的理解也有问题,很难下手。
3.自己的代码写的很差,没有章法,没有明确的思路,结构也很混乱,只能保证答案正确。
6.2 针对以下方面的感受
(1) Java编程语言是否对你的口味?
JAVA是世界上最好的编程语言。
(2) 关于Eclipse IDE
Eclipse是世界上最好的IDE。
(3) 关于Git和GitHub
Git和GitHub是世界上最好的代码交流项目。
(4) 关于CMU和MIT的作业
作业很难,做作业的过程很艰辛,通过做CMU和MIT的作业,我深刻地认识到了自己和它们学生之间的差距,怪不得我考不上CMU和MIT。
(5) 关于本实验的工作量、难度、deadline
做完之后感觉难度还是有点大的,主要原因在于自己第一次用JAVA,关于语法和算法的基础知识属于现学现用,,只能照葫芦画瓢,很艰难。
(6) 关于初接触“软件构造”课程
上课的内容和实验的内容有一定差距,很多实验内容要自学,目前基础太差,以后需要更加努力。