做業所屬課程:軟件工程1619|W(福州大學)
做業要求:結對第二次—文獻摘要熱詞統計及進階需求
結對學號:221600111|221600138
做業目的:學習團隊協做,提升合做編程的能力,培養良好的代碼風格java
結對同窗:221600138
本次做業:第二次結對做業
(一開始不知道github的用法,本身建了一個項目,如下貼出的記錄是舊項目的)
Github舊項目地址:221600111&221600138
Github提交做業的項目地址:221600111&221600138
Github代碼簽入記錄圖:
git
因爲開發過程當中Github網站常常上不去,因此必要時咱們會用QQ互傳文件,因此Github上的代碼記錄僅做參考github
分工:221600111(隊友1)負責文件部分、統計熱詞,221600138(隊友2)負責統計行數字符樹及單元測試;功能的實現咱們有線上線下互相講解及合做實現部分功能。編程
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 20 | 30 |
• Estimate | • 估計這個任務須要多少時間 | 300 | 450 |
Development | 開發 | 150 | 300 |
• Analysis | • 需求分析 (包括學習新技術) | 20 | 35 |
• Design Spec | • 生成設計文檔 | ||
• Design Review | • 設計複審 | ||
• Coding Standard | • 代碼規範 (爲目前的開發制定合適的規範) | 35 | 20 |
• Design | • 具體設計 | 30 | 50 |
• Coding | • 具體編碼 | 100 | 300 |
• Code Review | • 代碼複審 | 20 | 105 |
• Test | • 測試(自我測試,修改代碼,提交修改) | 20 | 55 |
Reporting | 報告 | 100 | 120 |
• Test Report | • 測試報告 | ||
• Size Measurement | • 計算工做量 | ||
• Postmortem & Process Improvement Plan | • 過後總結, 並提出過程改進計劃 | ||
合計 | 795 | 1465 |
剛開始拿到題目時,咱們在進行討論時並無對此次做業有更深刻的理解,僅僅是以爲能夠用java來完成此次做業,因而在作題以前有專門去看了一些有關java的一些方法,可是在真正的進行編碼時,才發現並非這樣,這其中的不少功能並非用單個函數或類就能夠實現的,並且在對有效行、單詞頻數以及單詞在字典中的前後順序進行輸出時,咱們出現了很多的錯誤,在改正的時候,中間發現了很多有關有效行的判斷的錯誤,好比:在僅對「\r\n」進行判斷的時候很容易將多個只含換行符或含有多個空白字符的無效行計入有效行中,從而使得有效行的數目判斷錯誤,中間有在網絡上面進行相應錯誤、方法的查找。單詞頻率統計最開始用數組解決,經思考討論後最終用字符樹解決。數組
在設計實現過程,開始咱們將文件的處理代碼先寫在主函數中,再從中逐字符調用處理函數,在實現全部處理功能後再改變整個代碼的結構,即功能拆分紅如題目要求的API。其中對於所得的單詞的處理上,在隊友2的想法中是直接用數組將全部的被判斷爲是單詞的字符串所有存儲在一個字符串數組中同時用另外一個整型數組對每一個單詞的詞頻進行記錄,而且在後面添加一些排序的函數以及調用字符串在字典中前後順序的方法對整型數組以及相對應的字符串數組中的全部的單詞進行排序。這其中又有幾個相應的函數;部分關鍵函數是須要畫出流程圖的;網絡
這是類關係圖:
架構
這是計算單詞樹、計算行數的流程圖,它們的說明在上下文有說起這裏不過多解釋
函數
在改進程序的性能上咱們大約花了將近一天的時間,咱們先是經過將主體架構的文件輸入輸出代碼編寫後,再對其餘的方法和函數進行編寫。在全部功能都實現了以後,咱們首先在原來思想的基礎上,回顧了上面已經編寫的代碼,發現上面已經編寫的代碼有不少的冗餘的部分,並且用字符串數組以及整型數組分別存儲單詞以及單詞出現的頻率,這中間的代碼量並不友好,因此最後根據隊友1的想法,他建立了一個樹,在每讀入一個單詞的時候就將這棵樹增長一個分支,同時將上面全部的代碼的冗餘部分刪除。
咱們在進行編程的時候,一開始並未對這一部分有太多的想法,只是說若是在讀取文件中的字符是出現了「\r\n」這幾個字符的時候對記錄有效行的靜態變量(下面統一爲rowCount)進行+1運算,但後來發現,這樣作會將無效行也統計在內,因而咱們有改變思路:在其中加入一個判斷,只要「\r\n」的前一個字符或者是後一個字符(主要看怎麼進行「\r\n」的判斷)是非空白字符就將rowCount增長1,但這樣的代碼卻致使了若是在文件中的某一行的最後一個字符(「\r\n」前一個字符)或某一行的前面的字符(「\r\n」後一個字符)出現了空白字符,那麼即便這一行是有效行,程序也不會將這一行視做有效行;最後咱們用了一個布爾類型的靜態變量(後面記做rowFlag),將其初始化爲false,在每次的讀取字符時只要出現了非空字符,就將rowFlag設置爲true,並在對有效行進行判斷時將這個條件加入--即只要rowFlag爲true且出現了字符「\r\n」則將rowCount加1,同時將rowFlag設置爲false,這樣就解決了咱們在統計有效行時出現的一系列問題。
固然在最後的接口封裝階段,咱們爲了符合做業的要求,將全部的實現的函數以及類都獨立出來,但由於屢次讀入了文件內容,這中間整個程序的運行時間倒是大大增長了,也就是說咱們的改進雖然更加的符合了做業要求,但同時也極大的消耗了本來應該節省的時間。工具
咱們找了好久沒有發現合適的性能測試工具,JAVA課程也沒有學過因此性能測試部分使用Junit的結果代替一下
這是Junit分析一隻測試數據的截圖,能夠看到計算字符和計算行的時間相同,畢竟計算行就是多了兩句代碼,性能天然損耗不大,但將兩個功能拆分紅單獨API致使時間損耗了一倍;單詞統計由於建樹時間更長,熱詞統計由於建完樹還要遍歷致使時間最長,在預料之中;時間主要是由於讀取文件損耗的。性能
private static class charNode{ private char value; private charNode[] nextChar; private int count=0; public void nextCharInit() { nextChar=new charNode[36]; for(int i=0;i<26;i++) { nextChar[i+10]=new charNode('a'+i); } for(int i=0;i<10;i++) { nextChar[i]=new charNode('0'+i); } } public void generateTree(String word) { if(nextChar==null) { nextCharInit(); } if(word.length()==1) { nextChar[getNextCharIndex(word.charAt(0))].plus(); } else { nextChar[getNextCharIndex(word.charAt(0))].generateTree(word.substring(1)); } }
思路:這段代碼主要是用來建立樹的,前面也有說過,咱們的思路是經過建立一棵樹,再將已經判斷是單詞的那些字符串所有添加至樹的分支中去而且將每一個單詞的頻數也經過樹中的結點進行存儲,此外再在這棵樹外建立一個存儲熱詞的一個數組,可以在遍歷整棵樹的時候將每一個有意義的單詞都放入熱詞的存儲空間中而且在存入以前就調用相應的函數(插入排序)將其詞頻與下一個被從樹中遍歷的單詞的頻數進行對比,若其詞頻大,則不進行位置的交換,不然對其進行對換。樹的兒子結點按ascii碼從小到大排列,這樣在前序遍歷時不須要比較字典序,由於先遍歷到的便是字典序排前的單詞。
class TextCalculatorTest { static final int expectedCharCount=102; static final int expectedRowCount=2; static final int expectedWordCount=2; static final String expectedTopWordCount="<abcdefghijklmnopqrstuvwxyz>: 2"; @Test void testCharCount() { File inFile=new File("input.txt"); assertEquals(expectedCharCount, TextCalculator.charCount(inFile)); } @Test void testRowCount() { File inFile=new File("input.txt"); assertEquals(expectedRowCount, TextCalculator.rowCount(inFile)); } @Test void testWordCount() { File inFile=new File("input.txt"); assertEquals(expectedWordCount, TextCalculator.wordCount(inFile)); } @Test void testTopWordCount() { File inFile=new File("input.txt"); String actualTopWordCount=TextCalculator.topWordCount(inFile); assertEquals(expectedTopWordCount.length(),actualTopWordCount.length()); for(int i=0;i<expectedTopWordCount.length();i++) assertEquals(expectedTopWordCount.charAt(i),actualTopWordCount.charAt(i)); } }
說明:測試的函數有字符統計,行統計,單詞統計,熱詞統計四個
構造測試數據思路:測試數據,一部分由咱們參考例子自行製做,本身統計裏面的單詞等與結果比較,在基礎的測試都完成後,一部分數據來自網絡隨手複製英文段落,在文本里多複製高頻單詞,使用word工具統計高頻單詞數,確保詞頻統計在大的數據處理需求下結果正確且性能達標。
結對困難:剛開始作題時並未與隊友有過交流,只是各自先看題目而後作題,後來進行交流時才發現各自都有不少不一樣的想法;
解決方法:後面在作這次做業的時候並未各自單獨作,而是經過qq一直在進行交流以及文件的互傳
隊友值得學習的地方:隊友善於發現程序問題,針對個人程序(BUG)可以提出質疑和提供改進思路,省去了不少沒必要要的解決問題的時間。