JML(Java Modeling Language)是一種行爲規範接口語言,經過使用不會被編譯的註釋形式,和固定關鍵字的語法,指定Java模塊代碼的行爲。大致上包括如下三種要求:java
前置: @requires 子句定義了須要知足的條件。node
過程: @assignment 子句定義了能夠改變的成員。算法
後置: @ensure 子句定義了方法要達到的效果。數組
此外,還有一些比較經常使用的的語法以下:數據結構
@pure 子句代表該方法無反作用,即僅具備查詢功能架構
@constraint 子句定義了狀態變化約束框架
@invariant 子句定義了全過程當中的不變式函數
\nothing 關鍵詞代表該方法對類成員屬性不進行修改工具
\result 關鍵詞表明該方法的返回值學習
\forall表達式:全稱量詞修飾的表達式,表示對於給定範圍內的元素,每一個元素都知足相應的約束。
\exists表達式: 存在量詞修飾的表達式,表示對於給定範圍內的元素,存在某個元素知足相應的約束。
\sum表達式:返回給定範圍內的表達式的和。
\product表達式:返回給定範圍內的表達式的連乘結果。
\max表達式:返回給定範圍內的表達式的最大值。
\min表達式:返回給定範圍內的表達式的最小值。
\num_of表達式:返回指定變量中知足相應條件的取值個數。
OpenJML:OpenJML能夠對含有JML的代碼進行編譯 ,並提供不一樣類型的選項進行檢查。-esc能夠靜態檢查可能出現的隱藏bug,-rac是運行時檢查,-check則能夠檢查代碼是否符合JML規格要求。
JMLUnitNG:能夠根據代碼中所寫JML規範自動生成測試框架進行自動化測試。
測試結果以下:
本次做業徹底根據規格要求進行設計,爲了減小查詢的時間,採用了hashmap存放path與pathid。在distinctnode方面也採用了一個hashmap存儲不一樣的node,在方法getDistinctNodeCount()中,只需返回該hashmap的size便可,大大節省了查詢的時間。兩個map設計以下:
private HashMap<Integer, Path> map = new HashMap<>();
map的key爲pathid,value爲Path,這樣能夠節省查找時的時間。在removePath()方法中,須要對map進行遍歷,根據重寫的equals方法找到相應path便可。
private HashMap<Integer, Integer> dismap = new HashMap<>();
dismap的key爲nodeid,value爲該node出現的次數,這樣在刪除一條path時,能夠將該path全部出現的點的次數減一,當次數爲零時,從dismap中移除該點便可。
類圖以下:
複雜度分析:
本次做業按照規格設計時遇到了許多困惑,在對最短路徑求解時查詢了許多算法,最後使用了florid算法。本次做業並未重構,在第一次做業進行簡單修改就知足了題目要求。
設計以下:
private HashMap<Integer, Path> map = new HashMap<>(); private HashMap<Integer, Integer> dismap = new HashMap<>();
這兩個map沿用第一次的設計,功能也相同。
private int[][] graph = new int[250][250]; private HashMap<Integer, Integer> castmap = new HashMap<>(); private int[] nodecount = new int[250]; private int flag = 0; private Floyd floyd;
類圖設計:
複雜度分析:
本次做業有點相似曾經學過數據結構課程的最後一次地鐵做業,在最短路徑的求解上依舊採用floyd算法。在討論區學習到了一種算法,根據這種算法結合floyd進行了計算。本次做業最終思路是將問題轉化爲圖內邊的權值問題,而後進行求解。本次做業並未重構,大部份內容沿用第二次做業的代碼,部份內容從MyRailwaySystem類中移入了Floyd類。
算法內容以下:將每條path都變成徹底無向圖,每條path內的每一個點都有直接到達該path內任意一點的距離,同時path內的每條邊都要加上切換path時的額外權值。最終求出的值再減去一次換乘的額外權值,即爲所求。
MyRailwaySystem設計以下:
private HashMap<Integer, Path> map = new HashMap<>(); private int flag = 0; private int blockNumber;
以上三個數據成員和前兩次做業一直,blocknumber爲連通塊數量,根據並查集求解便可。
private Floyd leastOFtransfer = new Floyd(1); private Floyd leastOFfear = new Floyd(2); private Floyd leastOFunpleasant = new Floyd(3);
這三個數據成員即爲本次做業的核心,構造函數傳入構造模式(一個int型變量),以便區分額外權值。
Floyd設計以下:
private static int row = 120; private int[][] length = new int[row][row];// 任意兩點之間路徑長度 private int addweight;//額外權值 private static HashMap<Path, int[][]> pathHashMap = new HashMap<>();//存儲每條path的徹底無向圖 private static HashMap<Path, int[][]> unpleasantHashMap = new HashMap<>();//單獨存儲unpleasant的徹底無向圖 private static HashMap<Integer, Integer> castmap = new HashMap<>();//映射map private static int[] nodecount = new int[row];//標記數組 private static HashMap<Integer, Integer> dismap = new HashMap<>();//計算distinctnode點的map private static int[][] graph = new int[row][row];//存入floyd計算結果 private static int[][] shortestLength = new int[row][row];//最短路徑數組
類圖設計:
複雜度分析:
第一次做業:本次做業強測只獲得了80分,緣由是沒考慮到課程組會利用時間卡數據,在不應進行計算的地方反覆進行了計算,因此事件被拖慢了,可是綜合設計是沒有問題的。已經成功合併修復。
第二次做業:本次做業強測45分,由於沒有吸收第一次的教訓,致使本次做業依然犯了不應犯的錯誤,查詢時反覆計算,致使許多點都time_limited。已經成功合併修復。
第三次做業:本次做業強測95分,bug在於數據太大時,我所設定的無限大出如今了數據裏,致使數據錯誤。已經成功合併修復。
規格撰寫本質上體現了從上而下的設計思路,設計好大框架而後一點一點的去構建細節。在學習了JML以後,可以經過已給出的規格實現函數或者類所要求的功能,這是一種很棒的體驗。可是規格自己的學習是較爲困難的,有許多語法上的規定須要記憶,之後仍是要多多練習先寫規格,再寫代碼,這樣不會忘記本身設計的原始意圖,別人讀代碼也會輕鬆不少。