软件工程团队项目------Beijing Subway
目錄
零、分工
一、GitHub地址
二、PSP表格
三、控制臺(tái)程序解題思路
四、控制臺(tái)程序?qū)崿F(xiàn)
五、控制臺(tái)程序性能分析 六、控制臺(tái)黑盒測(cè)試
1./b功能
2./a功能 部分結(jié)果
3./c功能
4./z測(cè)試功能
七、界面設(shè)計(jì)
1.界面設(shè)計(jì)思路
2.將C++封裝為dll
3.圖形界面的實(shí)現(xiàn)
4.繪圖功能的實(shí)現(xiàn)
5.界面功能基本完成
八、個(gè)人感悟
零、分工
控制臺(tái):張玉偉
GUI: 徐志濤
一、GitHub地址
github地址:https://github.com/ZhangWuren/SE-Team-Project
二、PSP表格
三、控制臺(tái)程序解題思路
1. 建模思路和文本信息
在本項(xiàng)目中,建模的對(duì)象是北京地鐵圖,在建模的過(guò)程中,建立了兩個(gè)類(lèi),分別為類(lèi)Station和類(lèi)Map。類(lèi)Map包含了類(lèi)Station,具體的類(lèi)圖在項(xiàng)目完成后展示。
在文本數(shù)據(jù)beijing-subway.txt中,記錄了地鐵站及其對(duì)應(yīng)的線路,舉例如下
1 蘋(píng)果園
1 古城
1 八角游樂(lè)園
1 八寶山
1 玉泉路
1 五棵松
1 萬(wàn)壽路
1 公主墳-10
1 軍事博物館-9
1 木樨地
1 南禮士路
1 復(fù)興門(mén)-2
1 西單-4
1 天安門(mén)西
1 天安門(mén)東
首列為當(dāng)前線路,接著是對(duì)應(yīng)的站名,-表示當(dāng)前車(chē)站為換乘車(chē)站,跟著的是換乘線路,多個(gè)換乘線路用“,”隔開(kāi)
經(jīng)統(tǒng)計(jì),北京市地鐵最新的不重復(fù)地鐵站數(shù)量為330。
2. Dijkstra算法——/b功能
在/b功能的實(shí)現(xiàn)過(guò)程中,將問(wèn)題抽象出來(lái),就是一個(gè)無(wú)向圖最短路問(wèn)題,整個(gè)地鐵圖為無(wú)向圖,尋找兩點(diǎn)之間站點(diǎn)最少的路線。很容易想到的就是曾經(jīng)學(xué)過(guò)的Dijkstra算法。在Dijkstra算法中,重要的是設(shè)置鄰接矩陣。
3. /c功能實(shí)現(xiàn)
/c功能是輸出整條線路,只需要簡(jiǎn)單的輸出同一條線路上的地鐵站即可。
4. /a功能實(shí)現(xiàn)
/a功能是從選定站點(diǎn)出發(fā),遍歷全部的站點(diǎn)。在思考全遍歷功能時(shí),想起了之前相似的問(wèn)題有tsp問(wèn)題,哈密頓回路,歐拉回路等。其中tsp問(wèn)題要求每個(gè)節(jié)點(diǎn)只能訪問(wèn)一次,和哈密頓回路類(lèi)似。歐拉回路則是要求每個(gè)邊都訪問(wèn)一次。這里的全遍歷功能和它們都不太一樣,本題強(qiáng)調(diào)要遍歷所有站點(diǎn),對(duì)于邊并不做要求,只要點(diǎn)遍歷到了,有的邊甚至是可以忽略的,同時(shí)每個(gè)點(diǎn)的訪問(wèn)次數(shù)也可以是多次的。
經(jīng)過(guò)在網(wǎng)絡(luò)上搜索相關(guān)資料,決定采用貪心策略+dijkstra算法,從給定起點(diǎn)start開(kāi)始,隨機(jī)選取一個(gè)沒(méi)有路過(guò)的節(jié)點(diǎn)作為end,用之前/b功能的dijkstra算法找到這兩個(gè)點(diǎn)之間的最短路。接著將end作為新的start,再選取沒(méi)有經(jīng)歷的節(jié)點(diǎn)最后end,直到所有點(diǎn)都遍歷結(jié)束,最后再返回給定的初始start。在這個(gè)過(guò)程中,dijkstra算法的結(jié)果是局部最優(yōu)解,運(yùn)用貪心的策略,可以判定整個(gè)遍歷的過(guò)程也可取到最優(yōu)的解。
5. 換乘優(yōu)化
題目中要求,換乘時(shí)因?yàn)楦鞣N原因,相當(dāng)于坐了三個(gè)站。一開(kāi)始我陷入了難題,因?yàn)槊總€(gè)站點(diǎn)都是獨(dú)立的,譬如“公主墳”這個(gè)換乘站,公主墳既在1號(hào)線,又在10號(hào)線,在不考慮換乘為3站的情況下,它和“萬(wàn)壽路”軍事博物館“”蓮花臺(tái)“西釣魚(yú)臺(tái)”這四個(gè)站點(diǎn)的鄰接矩陣權(quán)值都是1,但是考慮換乘優(yōu)化時(shí),權(quán)值要根據(jù)上一站點(diǎn)變化,陷入了僵局。
(所說(shuō)權(quán)值均表示鄰接矩陣權(quán)值)后來(lái)經(jīng)過(guò)很長(zhǎng)時(shí)間的思考,就是設(shè)置多個(gè)同名的換乘站表示不同地鐵線上的同一個(gè)換成站,同名換乘站之間權(quán)值為0,同線路前后站權(quán)值為1,不同線路前后站權(quán)值為3。用“公主墳”舉例,即創(chuàng)建一個(gè)1號(hào)線上的公主墳,一個(gè)10號(hào)線上的公主墳,1號(hào)線上的公主墳和“萬(wàn)壽路”軍事博物館“權(quán)值為1,和”蓮花臺(tái)“西釣魚(yú)臺(tái)”權(quán)值為3表示換乘,和10號(hào)線上的公主墳權(quán)值為0,因?yàn)橥瑐€(gè)站點(diǎn)本質(zhì)上是在一起的,能夠成功的解決換乘優(yōu)化問(wèn)題。
6./z測(cè)試功能實(shí)現(xiàn)
/z功能也比較簡(jiǎn)單,首先根據(jù)設(shè)定好的鄰接矩陣來(lái)判斷遍歷順序是否合理。然后再判斷節(jié)點(diǎn)數(shù)以及是否全部遍歷,再給出遺漏的站點(diǎn),比較簡(jiǎn)單。
四、控制臺(tái)程序?qū)崿F(xiàn)
1. Dijkstra算法——/b功能代碼
Dijkstra算法的另一塊重點(diǎn)部分為鄰接矩陣權(quán)值的設(shè)定,代碼如下
2. /a功能代碼
其中函數(shù)setTransMartix()為換乘優(yōu)化時(shí)的矩陣,具體如下
3./z測(cè)試功能代碼
void Map::test(string filename) {this->setMartix();memset(this->m_tvis, false, sizeof(m_tvis));fstream fin(filename);string readline;string stas[_TOTALS * 10];for (int i = 0; i < _TOTALS * 10; i++){stas[i].clear();}getline(fin, readline);int count = stoi(readline);int count1 = 0;int i = 0;while (getline(fin, readline)){stas[i] = readline;i++;}for (int i = 1; !stas[i].empty(); i++){Station s1 = this->getStationbyname(stas[i]);Station s2 = this->getStationbyname(stas[i - 1]);m_tvis[s1.getNumber()] = true;m_tvis[s2.getNumber()] = true;if (!this->m_maze[s1.getNumber()][s2.getNumber()]){cout << "error" << endl;return;}}int novissta[_TOTAL];memset(novissta, -1, sizeof(novissta));for (int i = 0, j = 0; i < _TOTAL; i++){if (this->m_tvis[i] == false){novissta[j] = i;j++;}}if (novissta[0] == -1){cout << "true" << endl;}else{cout << "false" << endl;cout << "遺漏的站點(diǎn)有:" << endl;for (int i = 0; novissta[i] != -1; i++){cout << this->getStationbynumber(novissta[i]).getName() << endl;}} }五、控制臺(tái)程序性能分析
對(duì)全遍歷功能進(jìn)行性能分析,發(fā)現(xiàn)耗時(shí)較長(zhǎng)的函數(shù)是全遍歷函數(shù)traversal以及其調(diào)用的貪心迪杰斯特拉搜索greedSearch,均控制在較短時(shí)間,不再做進(jìn)一步優(yōu)化。
還有讀取地圖的setMap函數(shù),本項(xiàng)目采用txt方式,逐行讀取北京地鐵圖,因?yàn)閿?shù)據(jù)量較小,故不做進(jìn)一步改進(jìn)。
六、控制臺(tái)黑盒測(cè)試
1./b功能
和百度地圖比較
基本類(lèi)似
2./a功能 部分結(jié)果
3./c功能
房山線
4./z測(cè)試功能
將/a的結(jié)果用作測(cè)試時(shí),應(yīng)該為true
刪除部分/a的結(jié)果
造成錯(cuò)誤站點(diǎn)
七、界面設(shè)計(jì)
1.界面設(shè)計(jì)思路
以C++代碼為功能,將函數(shù)封裝為dll供圖形界面調(diào)用,因?yàn)樵谛W(xué)期的時(shí)候用過(guò)C#寫(xiě)過(guò)圖形界面,所以決定采用C#構(gòu)建圖形界面,在C++函數(shù)中將要走過(guò)的站點(diǎn)依次輸出到文本文件中,然后再根據(jù)之前存儲(chǔ)的坐標(biāo)信息將各個(gè)站點(diǎn)的位置和路線畫(huà)在以北京地鐵線路圖為背景的畫(huà)布上。
2.將C++封裝為dll
C++函數(shù)封裝成動(dòng)態(tài)鏈接庫(kù)時(shí)才能提供接口供C#進(jìn)行調(diào)用,首先創(chuàng)建一個(gè)dll項(xiàng)目,然后將之前編寫(xiě)好的C++頭文件復(fù)制到這個(gè)項(xiàng)目中,再將要用到的函數(shù)聲明在dll項(xiàng)目的頭文件中,如下圖所示
之后在C#中就可以直接聲明調(diào)用函數(shù)了
項(xiàng)目目錄大致是這樣的,然后再將項(xiàng)目進(jìn)行編譯 ,項(xiàng)目目錄下會(huì)生成一個(gè)名字為Subway_dll.dll的動(dòng)態(tài)鏈接庫(kù)文件,我們這時(shí)就的到想要的dll文件,然后將這個(gè)dll文件復(fù)制到C#圖形界面項(xiàng)目的可執(zhí)行文件目錄下,就能在圖形界面進(jìn)行C++函數(shù)的調(diào)用了
3.圖形界面的實(shí)現(xiàn)
在窗體中導(dǎo)入北京地鐵線路圖,想要正確的繪圖首先要得到各個(gè)站點(diǎn)的坐標(biāo),然后為了得到各個(gè)點(diǎn)的坐標(biāo),我寫(xiě)了一個(gè)Onclick事件,每點(diǎn)一次就獲得當(dāng)前位置的坐標(biāo),將各個(gè)站點(diǎn)的坐標(biāo)依次記錄在Beijing_Subway_Location.txt文件中。然后就可以根據(jù)經(jīng)過(guò)的站點(diǎn)信息畫(huà)圖了。
為了能夠在C#項(xiàng)目中調(diào)用遍歷功能的C++函數(shù),需要再主函數(shù)這里引入聲明要調(diào)用的函數(shù)
這個(gè)函數(shù)會(huì)將經(jīng)過(guò)的站點(diǎn)信息依次輸出存入txt文件中,然后C#讀這個(gè)文件,進(jìn)行繪圖。
4.繪圖功能的實(shí)現(xiàn)
因?yàn)樵诶L制路線圖的過(guò)程中會(huì)反復(fù)進(jìn)行繪圖,所以編寫(xiě)了一個(gè)DrawTool類(lèi)來(lái)實(shí)現(xiàn)繪圖功能,這個(gè)類(lèi)中會(huì)有兩個(gè)功能,一個(gè)是畫(huà)圖,一個(gè)是畫(huà)帶箭頭的線來(lái)表明路線,代碼如下
5.界面功能基本完成
設(shè)置了一個(gè)Button_Click事件,點(diǎn)擊Search按鈕即可實(shí)現(xiàn)繪制線路圖,點(diǎn)擊Search先會(huì)調(diào)用ResetMap函數(shù)來(lái)刷新界面,防止上一次的繪圖對(duì)本次繪圖發(fā)生影響,具體調(diào)用繪圖功能的代碼如下
執(zhí)行如下命令
界面如圖所示,手動(dòng)輸入坐標(biāo)會(huì)有誤差,站點(diǎn)繪制的并不是非常準(zhǔn)確,在可以接受的誤差范圍內(nèi)
八、個(gè)人感悟
本次結(jié)對(duì)項(xiàng)目中我負(fù)責(zé)界面的編寫(xiě),學(xué)習(xí)了運(yùn)用C#寫(xiě)圖形界面以及一些C#的語(yǔ)法,了解了dll的用法,也學(xué)習(xí)了如何合作使用GitHub,本次項(xiàng)目收獲頗豐
總結(jié)
以上是生活随笔為你收集整理的软件工程团队项目------Beijing Subway的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 联想家悦微型计算机的包装箱,08年联想家
- 下一篇: 趣图 | 这就是程序员的成长过程吧