文章目录
-
- 查阅足迹
- 【坑】字符串中的路径表示法
-
- 相对路径
- 绝对路径
- 【记】读写文件时的善后工作
- 【记】Git命令初步
- 【坑】已知正多边形内角求多边形边数
- 【记】小乌龟转向问题
- 【记】凸包问题
- 【记】关于迭代器Iterator
- 【记】关系网络的距离求解
- 【坑】使用迭代器进行迭代时,改变迭代对象
- 【记】break跳出多层循环
w(゚Д゚)w大的同学们你们好!老师又让我们写博客了,终于写完了实验报告,程序健壮性需要考虑的东西很多,到最后脑子一片浆糊,边写报告边写博客两边懵逼,(@_@?
抵制一切盲目互佬的行为,构建良好的开源生态环境
查阅足迹
先不多废话了,也许在写完报告后回来完善博客,这里先记录一下在实验过程中的查阅足迹:
- Eclipse写JAVA的相对路径总结
- Java throw:异常的抛出
- Java读取txt文件和写入txt文件
- java中向上向下及四舍五入取整的方法,double型强制转换成int型的取整方法?
- 删除github中某个文件夹
- git中出现“non-fast-forward”errors时的终极解决方案
- 关于HashSet的各种使用方法总结
- 凸包问题的五种解法
- java中数据字典的使用
- 菜鸟教程-Java Stack 类
- Java队列(Queue)了解及使用
- 菜鸟教程-Java 实例 - 队列(Queue)用法
- No JUnit tests found’ in Eclipse
- 在JAVA中如何根据枚举索引值来获取枚举值(范型适用)
- java.util.ConcurrentModificationException 异常问题详解
【坑】字符串中的路径表示法
在Java中,或其它某些编程语言中,我们再进行文件操作时,常常要用到一个字符串变量filepath来表示文件路径,小伙伴们注意了,字符串中可是有转义字符的噢~
相对路径
如果你想用相对路径寻址的话,当然这是值得推荐的方式,同平台的可移植性较高。如果你用的Eclipse IDE的话,那么项目路径默认是在项目文件夹内,在当前状态下,诸如
src
bin
文件夹都是和当前路径平级的,这些文件夹下再寻址就要用到斜杠或者反斜杠了。
可以注意到,Windows系统中,资源管理器中的文件路径显示都是反斜杠 \,像这样:

而反斜杠在Java字符串中属于转义字符(在markdown标记语言和其它许多编程语言中都是这样),那么在用反斜杠时,切记连续键入两个反斜杠,以忽略转义!。
不过我们也可以用正斜杠 / 来写目录路径,虽然在Windows中使用反斜杠,而正斜杠通常用于Linux系统中。
绝对路径
不建议这种方式来描述文件位置,可移植性差,极差。但它的斜杠要求和上面说的相同,只是你需要从根目录开始逐级寻址。
【记】读写文件时的善后工作
在读写文件时,我们可能会创建这样的变量
FileReader reader = new FileReader(fileName);
BufferedReader br = new BufferedReader(reader);
记得在程序可能退出的位置之前,打上这样的两行,或者只打下面的第二行:
br.flush();
br.close();
第一行的意思大概是清空缓冲区,这里面有很多讲究,没有仔细探究。
第二行是把这个I/O流关闭,可以防止资源泄露,这行还是很重要的。
【记】Git命令初步
在初识Git时,有一些概念有必要了解一下。
- 本地仓库。本地仓库是在本地目录时用
命令之后,生成的一个git init
隐藏文件,它是你本次建立git仓库的仓库管理文件。其中保存着仓库历史记录等仓库相关信息。.git
- 远程仓库。远程仓库通常是在互联网上的一个服务器(很庞大的服务器),GitHub就属于一个服务器,也有人搭建自己的Git服务器。当你用
命令把本地仓库推送到远程时,就把自己的本地仓库备份到了互联网上,如果你的仓库类型是public公开的话,其他人也可以很方便地浏览。git push
- 分布式版本控制系统。Git是典型的代表,与集中式不同,分布式的分布指的是既在本地保存了仓库,也在远程服务器保存了仓库,版本控制管理更加灵活,也是当下大势所趋。
- Git Bash。Git Bash是下载安装Git后,我们应用Git的主要工具,起始还可以使用Git GUI,但是初学不建议使用GUI操作,用Bash操作有利于我们学习代码指令。
在本次实验中,我们的Git操作是这样的:
- 先按照实验环境声明创建远程仓库,然后在本地某个目录下打开Git Bash开始clone任务代码,记下目标仓库的HTTPS路径(或SSH路径),在相应目录下Git Bash中clone。clone前要先使用命令
以初始化git仓库,然后clone,git init
,然后任务相关代码就到了该目录下。git clone https://github.com/rainywang/Spring2019_HITCS_SC_Lab1.git
这里有可能遇到clone速度慢的情况,可以参考个人总结博客https://blog.csdn.net/qq_41662115/article/details/86993426.
- 然后你可以做实验了。
- 做完实验后开始提交。将远程仓库的HTTPS添加到标识符
中。如果之前已经添加过,那么就会出现如下fatal提示:origin
这步是为了用HIT Software Construction 2019spring Lab-1 总结
表示远程仓库,相当于在远程和本地之间搭了一座桥。origin
- 为了上传提交或更新提交我们在本地的项目开发,先将代码上传到暂存区,
即为将当前目录下所有文件上传到暂存区。git add .
HIT Software Construction 2019spring Lab-1 总结 - 然后用
命令提交更新,-m参数后面可以添加描述本次提交信息的字串。git commit
HIT Software Construction 2019spring Lab-1 总结 - 这时,本次提交就已经写入到本地Git管理历史中了。要想上传到远程仓库,用这个。可能要输入密码,这个密码是SSH密钥,是一种安全的信息传输协议。
HIT Software Construction 2019spring Lab-1 总结 - 然后在远程仓库中我们可以看到本次提交的信息,和更改状态。还可以查看本地的提交历史日志。下图给出的是我的最新的几次提交。
HIT Software Construction 2019spring Lab-1 总结
【坑】已知正多边形内角求多边形边数
这是上一个问题的拓展,上一个问题描述是这样的
已知正多边形边数,求内角度数
上一个问题的解决方法,我们小学的时候就学过公式了,设内角度数为 α α α,边数为 n n n,那么有 α = 180 × ( n − 2 ) ÷ n α = 180 \times (n - 2) \div n α=180×(n−2)÷n。这里面有一个问题是, n n n既然作为分母,结果难免会出现除不尽的情况,比如说正七边形,那么我们在Java中做浮点数除法时,得到的浮点数类型结果,必然不是精确值,但这种精确程度我们也可以接受了。
但是,在做这个问题的时候,我们要求边数 n n n,那么结果是一个整数,我们会出现浮点数舍入到整数的情况。在没有指定舍入方法的情况下,默认是向零舍入,正数向下,负数向上,这样如果你在计算过程中得到的 n n n是5.99…的话,那么结果就是5了,而不是应该舍入的6.
解决方案
- 先加0.5,再强转为
类型int
- 用
方法来做四舍五入。Math.round()
public static int calculatePolygonSidesFromAngle(double angle) {
int sides = (int) Math.round(360 / (180 - angle));
return sides;
}
【记】小乌龟转向问题
这段也算是一个比较麻烦的功能实现吧,跟二维平面上的几何关系有关,数学知识,直接把我的实验报告搬过来吧。
这部分要一个方法,calculateBearingToPoint,是在给定一个向量和y正半轴夹角,该向量是小乌龟的面朝向,再给定小乌龟的二维坐标,和目的坐标,求小乌龟想要到达目的地前,最少需要顺时针旋转的角度。
我在纸上对两给点的方位给出了8种情况的分析,最终合并8种情况为4种情况,两点互为上下或左右分别是两种情况,这种情况比较特殊,考虑起来很简单。再有就是两点并不互为上下左右,这样的话除了考虑当前点的朝向,计算旋转角度时还要考虑两点夹角,这里就把两点连线和水平线所夹的锐角作为参考,并认为这个锐角是-90°到90°之间的,记为β。这样的话,如果目标点在当前点的一三象限方位,那么β是正的,否则β是负的。合并四个方位发现,虽然一四象限和二三象限时的β正负各自不同,但是得到的结果是一样的,所以最后是四种情况。
我的情况分析是这样的:
- 两点互为上下。
- 目标点在上
- 返回(360-α)%360
- 目标点在下
- α在0~180°
- 返回180-α
- α在180~360°
- 返回540-α
- α在0~180°
- 目标点在上
- 两点互为左右。
- 目标点在左
- α在0~270°
- 返回270-α
- α在270~360°
- 返回630-α
- α在0~270°
- 目标点在右
- α在0~90°
- 返回90-α
- α在90~270°
- 返回450-α
- α在0~90°
- 目标点在左
- 目标点在左上或左下
- α在0~270°
- 270-α-β
- α在270~360°
- 630-α-β
- α在0~270°
- 目标点在右上或右下
- α在0~90°
- 90-α-β
- α在90~270°
- 450-α-β
- α在0~90°
简单的角度图凑活看吧
【记】凸包问题
先描述一下问题。给定平面上一些点的二维坐标,要求一个尽可能小的点集,该集合中的点在平面上围成一个凸多边形,且该凸多边形包含给定的所有点。
6.031给出的凸包问题建议算法,可以用外包裹算法,Jarvis算法。这个算法是这样的,先找到给定点集的边缘点,比如说最左下的那个点,以它作为凸包的起点,然后寻找第二个点,第二个点应该满足和起点连线与x正半轴夹角最小,从第三个点开始遍历,从第一次遍历开始,将第一个找到的点记为P1,第二个找到的点记为P2,要寻找的下一个点记为P3,每次寻找P3时,应满足P3P2和P2P1的夹角最小,这样步进寻找,得到的边连接起来可以囊括所有的点,直到找到的P3回到起点为止。
在构建凸包过程中,对P3的寻找,可能会遇到P2P3直线上有多个点,那么就要找距离P2最远的那一个,放进凸包中。还有就是只有一个点和两个点的情况,这时规定给定点全是凸包中的点,这时凸包是一个点,或是一条线。
附上角度示意图。总是希望两向量夹角θ是最小的,并且取最远的那个点。
【记】关于迭代器Iterator
对Set,List,Map.keySet这种具有集合性质的集遍历时,我们通常会使用两种方式,一种是比较间接的for-each,另一种是创建一个Iterator对象,用它来做迭代工作。给出一个示例:
Iterator iterator = points.iterator();
while (iterator.hasNext()) {
next = iterator.next();
/* 找到给定点集最左下的点作为起点 */
if (next.y() < p1.y())
p1 = next;
else if (next.y() == p1.y() && next.x() < p1.x())
p1 = next;
}
它的迭代原理似乎是比较复杂的,简单介绍来说呢,就是用hasNext()判断迭代过程中,是否还有下一个迭代项,如果是,就继续迭代,否则退出。获取迭代对象用next()方法,这相当于一次步进。
问题在于,假设我们的某一迭代器的迭代工作由于某种原因中断了,比如说以达成目标,break跳出循环while,而在接下来的工作中还需要迭代这同一个对象,那么,我们的正确做法,应该是重置迭代器
iterator
,绝不能在没有重置的情况,继续使用它。
一个迭代器只能用于一次迭代工作,如果它被中断了(不能说终止,接下来可能还会用到),再回到它来迭代时,是继续断点迭代的。如果我们想重新遍历这一对象,就必须要
iterator = XXX.iterator()
来重置迭代器,开启全新的遍历过程。
【记】关系网络的距离求解
问题描述。规定一个无向图,顶点代表人,边代表边上的两点之间存在关系,若AB存在关系,则认定AB距离为1,若A到P有路,则认定AP距离为路的长度。若A到P无路,则认定AP距离为-1.
该问题的实质是图问题中的最短路径问题,要求的是源点到给定点的最短路径,图的各条边权值均为1,图为无向图,但是后期可能要扩展到有向图。点和边手动输入。要求两个人的距离,也就是从一个人到另外一个人的最短路长。
使用的算法可以用广度优先搜索算法,记录下源点到各点的路径,然后从目标点回溯的源点,对路长计数,得出答案。
【坑】使用迭代器进行迭代时,改变迭代对象
问题:在做getsmarter问题的时候,我选择了triadic closure来实现进一步的关注推测,对于三角关系的处理,我自然想到的是三层循环,判断三者关系,错误代码如下:
// BUGGY CODE
for(String A : guessFollowsGraphMap.keySet()) {
for(String B : guessFollowsGraphMap.get(A)) {
for(String C : guessFollowsGraphMap.get(B)) {
if(guessFollowsGraphMap.get(B).contains(A) && guessFollowsGraphMap.get(C).contains(B)) {
if(!guessFollowsGraphMap.get(A).contains(C))
guessFollowsGraphMap.get(A).add(C);
if(!guessFollowsGraphMap.get(C).contains(A))
guessFollowsGraphMap.get(C).add(A);
}
}
}
}
这里会爆出这样的异常
原因可以参考上述这位仁兄的博客,小弟在这里转载过来了
java.util.ConcurrentModificationException 异常问题详解
这个问题可能过于复杂,加上网上给出的多篇博客,都是单线程下对迭代对象remove,或者多线程下的解决方案,对此,我的代码中对迭代对象进行了add操作,没有找到合适的解决方案,不过最后还是换了一种思维,实现了triadic closure的变相实现方式,修改后代码如下:
HashMap<String, String> waitingAddedFollow = new HashMap<String, String>();
for(String A : guessFollowsGraphMap.keySet()) {
for(String B : guessFollowsGraphMap.get(A)) {
for(String C : guessFollowsGraphMap.get(B)) {
if(guessFollowsGraphMap.get(B).contains(A) && guessFollowsGraphMap.get(C).contains(B)) {
waitingAddedFollow.put(A, C);
}
}
}
}
for(String A : waitingAddedFollow.keySet()) {
String C = waitingAddedFollow.get(A);
if(!guessFollowsGraphMap.get(A).contains(C))
guessFollowsGraphMap.get(A).add(C);
if(!guessFollowsGraphMap.get(C).contains(A))
guessFollowsGraphMap.get(C).add(A);
}
【记】break跳出多层循环
当我们在使用多层
for
嵌套时,有可能要在内层循环使用
break
,希望跳出多层循环,但仅用
break
是做不到的。需要用到一个叫做循环标记的语法。比如:
firstloop: for(int i=1; i<10; i++)
secondloop: for(int j=1; j<10; j++)
thirdloop: for(int k=1; k<10; k++)
break secondloop;
上述代码在执行到内层循环时,会直接跳出第二层循环,总的循环次数应该有
Eclipse的
ctrl+shift+f
贼强,有时间可以学习一下。