天天看點

HIT Software Construction 2019spring Lab-1 總結

文章目錄

    • 查閱足迹
    • 【坑】字元串中的路徑表示法
      • 相對路徑
      • 絕對路徑
    • 【記】讀寫檔案時的善後工作
    • 【記】Git指令初步
    • 【坑】已知正多邊形内角求多邊形邊數
    • 【記】小烏龜轉向問題
    • 【記】凸包問題
    • 【記】關于疊代器Iterator
    • 【記】關系網絡的距離求解
    • 【坑】使用疊代器進行疊代時,改變疊代對象
    • 【記】break跳出多層循環

w(゚Д゚)w大的同學們你們好!老師又讓我們寫部落格了,終于寫完了實驗報告,程式健壯性需要考慮的東西很多,到最後腦子一片漿糊,邊寫報告邊寫部落格兩邊懵逼,(@_@?

抵制一切盲目互佬的行為,建構良好的開源生态環境

查閱足迹

先不多廢話了,也許在寫完報告後回來完善部落格,這裡先記錄一下在實驗過程中的查閱足迹:

  1. Eclipse寫JAVA的相對路徑總結
  2. Java throw:異常的抛出
  3. Java讀取txt檔案和寫入txt檔案
  4. java中向上向下及四舍五入取整的方法,double型強制轉換成int型的取整方法?
  5. 删除github中某個檔案夾
  6. git中出現“non-fast-forward”errors時的終極解決方案
  7. 關于HashSet的各種使用方法總結
  8. 凸包問題的五種解法
  9. java中資料字典的使用
  10. 菜鳥教程-Java Stack 類
  11. Java隊列(Queue)了解及使用
  12. 菜鳥教程-Java 執行個體 - 隊列(Queue)用法
  13. No JUnit tests found’ in Eclipse
  14. 在JAVA中如何根據枚舉索引值來擷取枚舉值(範型适用)
  15. java.util.ConcurrentModificationException 異常問題詳解

【坑】字元串中的路徑表示法

在Java中,或其它某些程式設計語言中,我們再進行檔案操作時,常常要用到一個字元串變量filepath來表示檔案路徑,小夥伴們注意了,字元串中可是有轉義字元的噢~

相對路徑

如果你想用相對路徑尋址的話,當然這是值得推薦的方式,同平台的可移植性較高。如果你用的Eclipse IDE的話,那麼項目路徑預設是在項目檔案夾内,在目前狀态下,諸如

src

bin

檔案夾都是和目前路徑平級的,這些檔案夾下再尋址就要用到斜杠或者反斜杠了。

可以注意到,Windows系統中,資料總管中的檔案路徑顯示都是反斜杠 \,像這樣:

HIT Software Construction 2019spring Lab-1 總結

而反斜杠在Java字元串中屬于轉義字元(在markdown标記語言和其它許多程式設計語言中都是這樣),那麼在用反斜杠時,切記連續鍵入兩個反斜杠,以忽略轉義!。

不過我們也可以用正斜杠 / 來寫目錄路徑,雖然在Windows中使用反斜杠,而正斜杠通常用于Linux系統中。

絕對路徑

不建議這種方式來描述檔案位置,可移植性差,極差。但它的斜杠要求和上面說的相同,隻是你需要從根目錄開始逐級尋址。

【記】讀寫檔案時的善後工作

在讀寫檔案時,我們可能會建立這樣的變量

FileReader reader = new FileReader(fileName);
			BufferedReader br = new BufferedReader(reader);
           

記得在程式可能退出的位置之前,打上這樣的兩行,或者隻打下面的第二行:

br.flush();
br.close();
           

第一行的意思大概是清空緩沖區,這裡面有很多講究,沒有仔細探究。

第二行是把這個I/O流關閉,可以防止資源洩露,這行還是很重要的。

【記】Git指令初步

在初識Git時,有一些概念有必要了解一下。

  1. 本地倉庫。本地倉庫是在本地目錄時用

    git init

    指令之後,生成的一個

    .git

    隐藏檔案,它是你本次建立git倉庫的倉庫管理檔案。其中儲存着倉庫曆史記錄等倉庫相關資訊。
  2. 遠端倉庫。遠端倉庫通常是在網際網路上的一個伺服器(很龐大的伺服器),GitHub就屬于一個伺服器,也有人搭建自己的Git伺服器。當你用

    git push

    指令把本地倉庫推送到遠端時,就把自己的本地倉庫備份到了網際網路上,如果你的倉庫類型是public公開的話,其他人也可以很友善地浏覽。
  3. 分布式版本控制系統。Git是典型的代表,與集中式不同,分布式的分布指的是既在本地儲存了倉庫,也在遠端伺服器儲存了倉庫,版本控制管理更加靈活,也是當下大勢所趨。
  4. Git Bash。Git Bash是下載下傳安裝Git後,我們應用Git的主要工具,起始還可以使用Git GUI,但是初學不建議使用GUI操作,用Bash操作有利于我們學習代碼指令。

在本次實驗中,我們的Git操作是這樣的:

  • 先按照實驗環境聲明建立遠端倉庫,然後在本地某個目錄下打開Git Bash開始clone任務代碼,記下目标倉庫的HTTPS路徑(或SSH路徑),在相應目錄下Git Bash中clone。clone前要先使用指令

    git init

    以初始化git倉庫,然後clone,

    git clone https://github.com/rainywang/Spring2019_HITCS_SC_Lab1.git

    ,然後任務相關代碼就到了該目錄下。
這裡有可能遇到clone速度慢的情況,可以參考個人總結部落格https://blog.csdn.net/qq_41662115/article/details/86993426.
  • 然後你可以做實驗了。
  • 做完實驗後開始送出。将遠端倉庫的HTTPS添加到辨別符

    origin

    中。如果之前已經添加過,那麼就會出現如下fatal提示:
    HIT Software Construction 2019spring Lab-1 總結
    這步是為了用

    origin

    表示遠端倉庫,相當于在遠端和本地之間搭了一座橋。
  • 為了上傳送出或更新送出我們在本地的項目開發,先将代碼上傳到暫存區,

    git add .

    即為将目前目錄下所有檔案上傳到暫存區。
    HIT Software Construction 2019spring Lab-1 總結
  • 然後用

    git commit

    指令送出更新,-m參數後面可以添加描述本次送出資訊的字串。
    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~270°
        • 傳回270-α
      • α在270~360°
        • 傳回630-α
    • 目标點在右
      • α在0~90°
        • 傳回90-α
      • α在90~270°
        • 傳回450-α
  • 目标點在左上或左下
    • α在0~270°
      • 270-α-β
    • α在270~360°
      • 630-α-β
  • 目标點在右上或右下
    • α在0~90°
      • 90-α-β
    • α在90~270°
      • 450-α-β

簡單的角度圖湊活看吧

HIT Software Construction 2019spring Lab-1 總結

【記】凸包問題

先描述一下問題。給定平面上一些點的二維坐标,要求一個盡可能小的點集,該集合中的點在平面上圍成一個凸多邊形,且該凸多邊形包含給定的所有點。

6.031給出的凸包問題建議算法,可以用外包裹算法,Jarvis算法。這個算法是這樣的,先找到給定點集的邊緣點,比如說最左下的那個點,以它作為凸包的起點,然後尋找第二個點,第二個點應該滿足和起點連線與x正半軸夾角最小,從第三個點開始周遊,從第一次周遊開始,将第一個找到的點記為P1,第二個找到的點記為P2,要尋找的下一個點記為P3,每次尋找P3時,應滿足P3P2和P2P1的夾角最小,這樣步進尋找,得到的邊連接配接起來可以囊括所有的點,直到找到的P3回到起點為止。

在建構凸包過程中,對P3的尋找,可能會遇到P2P3直線上有多個點,那麼就要找距離P2最遠的那一個,放進凸包中。還有就是隻有一個點和兩個點的情況,這時規定給定點全是凸包中的點,這時凸包是一個點,或是一條線。

附上角度示意圖。總是希望兩向量夾角θ是最小的,并且取最遠的那個點。

HIT Software Construction 2019spring Lab-1 總結

【記】關于疊代器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);
			}
		}
	}
}
           

這裡會爆出這樣的異常

HIT Software Construction 2019spring Lab-1 總結

原因可以參考上述這位仁兄的部落格,小弟在這裡轉載過來了

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

賊強,有時間可以學習一下。

繼續閱讀