景点旅游信息系统——C/C++程序设计、Qt图形化界面
🔋 一個 Qt、C/C++ 程序設計項目
文章目錄
- 一、簡單的效果演示
- 二、系統要求
- 三、系統設計
- 四、框架搭建
- 五、算法設計
- 5.1 創建景區景點分布圖的算法:
- 5.2 判斷創建的導游線路圖有無回路的算法——拓撲圖:
- 5.3 輸出給定入口景點的導游線路圖的算法——DFS
- 5.4 求兩個景點間的最短路徑的算法——Floyd
- 5.5 給出道路建設(最小生成樹)的算法——Kruskal
- 六、測試數據及其結果分析
- 七、完整代碼
- 八、參考附錄
一、簡單的效果演示
??● 說明:簡單演示了一下新增/刪除結點和邊,以及一些功能按鈕。
二、系統要求
??● 景區旅游信息系統,需要實現的功能有如下 4 項:
????(1) 能自行建立一個導游線路地圖。能通過拓樸排序判斷圖中有無回路,若有回路,則打印輸出回路中的景點。
????(2) 若給出一個入口景點,能自行采用深度優先策略建立一個導游線路圖。
????(3) 在導游線路圖中,能實現查看從一個景點到另一個景點的最短路徑。
????(4) 景區道路能保證連通所有景點,且能通過最小代價生成樹的策略來修建道路(代價只與它的里程有關)。
三、系統設計
四、框架搭建
??● 項目管理如下:
??● 說明:
????① main.cpp 是主函數入口。
????② main_window.cpp 是 “開始” 界面的源代碼。
????③ tour_system.cpp 是景區旅游信息系統的源代碼 。
??● 頭文件tour_system.h 如下:
??● 說明【這段話很關鍵】:其中主要反復調用的函數是mousePressEvent(),即 “鼠標相應函數”。因為我們在進行相關圖形操作時,都是以 “點” 為基本操作對象(若是要確定一條邊,也是點擊某兩個點。若要進行某項功能,也是點擊相應的功能按鈕一下)。所以我們主要在mousePressEvent()寫 “景區系統的主核心艙”,配合switch()語句來實現對各個功能的反復調用。
??● mousePressEvent()的 框架版代碼 如下:
void Tour_System::mousePressEvent(QMouseEvent* e) // 鼠標點擊事件 {if (e->button() == Qt::LeftButton) // 按左鍵{switch(function_num){case 1: // 添加點function_num = 0; // 執行完后歸零...break;case 2: // 新增邊(選擇邊的起點)function_num = 3;...break;case 3: // 新增邊(選擇邊的終點)function_num = 0; ... break;case 4: // 刪除結點function_num = 0; ...break;case 5: // 刪除邊(選擇邊的起點)function_num = 6; ...break;case 6: // 刪除邊(選擇邊的終點)function_num = 0; ...break;case 7: // 編輯結點的標簽function_num = 0; ...break;case 8: // 修改邊(選擇邊的起點)function_num = 9; ...break;case 9: // 修改邊(選擇邊的終點)function_num = 0; ...break;case 10: // 建立導游路線圖(DFS)function_num = 0; ...break;case 11: // 求兩點之間的最短路徑(Floyd)——選擇起點function_num = 12; ...break;case 12: // 求兩點之間的最短路徑(Floyd)——選擇終點...break;}} }void Tour_System::on_Btn_1_1_clicked() // 新增結點 { function_num = 1... }void Tour_System::on_Btn_1_2_clicked() // 新增邊 { function_num = 2... }void Tour_System::on_Btn_1_3_clicked() // 刪除結點 { function_num = 4... }void Tour_System::on_Btn_1_4_clicked() // 刪除邊 { function_num = 5... }void Tour_System::on_Btn_1_5_clicked() // 編輯結點 { function_num = 7... }void Tour_System::on_Btn_1_6_clicked() // 修改邊 { function_num = 8... }void Tour_System::on_Btn_2_1_clicked() // 判斷是否有回路 { ... }void Tour_System::on_Btn_2_2_clicked() // 建立一張導游線路圖(DFS) { function_num = 10... }void Tour_System::on_Btn_2_3_clicked() // 求兩點之間的最短路徑(Floyd) { function_num = 11... }void Tour_System::on_Btn_2_4_clicked() // 最小生成樹(Kruskal) { ... }void Tour_System::on_Btn_3_1_clicked() // 顯示所有邊長 { ... }void Tour_System::on_Btn_3_2_clicked() // 加載地圖 { ... }void Tour_System::on_Btn_3_3_clicked() // 保存地圖 { ... }void Tour_System::on_Btn_3_4_clicked() // 加載背景 { ... }void Tour_System::on_Btn_3_5_clicked() // 清除屏幕 { ... }五、算法設計
??● 在寫算法之前,先把所有要用到的全局變量展示出來,如下圖所示:
5.1 創建景區景點分布圖的算法:
??● 運用繪圖函數paintEvent()和鼠標點擊響應函數mousePressEvent()來處理景區景點以及道路的繪制與連接。
??● 景點的繪制機制:鼠標點擊處所在的小圓域(半徑自行設置),如果沒有其他已創建的景點(結點),那么將新生成并繪制該景點(結點)。
??● 道路的繪制機制:用鼠標選取兩個景點(結點),即可新生成一條景區道理,并會賦予該道路相應的結構體成員信息。
??● 流程圖如下:
??● 代碼如下:
void Tour_System::mousePressEvent(QMouseEvent* e) // 鼠標點擊事件 {if (e->button() == Qt::LeftButton) // 按左鍵{QPoint cur_click_pos = e->pos(); // e->pos(): 獲取當前點擊位置switch(function_num){case 1: // 添加點if(node_num < Node_MAX_NUM && cur_click_pos.x() >= show_window_x &&cur_click_pos.x() <= show_window_x+show_window_width &&cur_click_pos.y() >= show_window_y && cur_click_pos.y() <= show_window_y+show_window_height) // 判斷所加的點是否在窗口范圍內{int save_node_num = node_num;node_num++;for(int i = 1; i < node_num; i++){if(is_Click_Suc(cur_click_pos, point[i], RADIUS+10)) // 判斷鼠標所點擊位置和圖上所有已添加的結點位置,是否靠的太近{node_num--;QMessageBox::warning(this, "警告", "兩個點靠太近!");}}if(save_node_num == node_num)break;point[node_num] = e->pos(); // 當前位置賦給最新的結點point_info[node_num] = QString::number(++info_ind); // 創建默認標簽update();}else if(node_num >= Node_MAX_NUM){QMessageBox::warning(this, "警告", "目前結點數已達上限,無法再繼續添加!");}else{QMessageBox::warning(this, "警告", "新加結點已超出邊界!");}ui->Message_1->clear();ui->Message_1->addItem("目前有結點個數:" + QString::number(node_num));ui->Message_1->addItem("目前有邊的條數:" + QString::number(side_num));ui->Message_1->addItem("如果還要繼續添加, 請選擇下一個點的位置。");function_num = 1; // 功能號 1 保持不變(便于重復添加點)break;case 2: // 新增邊(選擇邊的起點)if(side_num >= Side_MAX_NUM){QMessageBox::warning(this, "警告", "路徑數已達上限!");}else{for( int i = 1; i <= node_num; i++ ){if( is_Click_Suc(cur_click_pos, point[i], RADIUS) ) // 判斷是否選中{function_num = 3; // 找到了新增邊的起點后, 還需找到其終點. 故把控制權交給功能號3temp_Point_1 = point[i];line[side_num + 1].node_1 = i;ui->Message_1->clear();ui->Message_1->addItem("請選擇邊的終點位置");break;}}}update();break;case 3: // 新增邊(選擇邊的終點)for( int i = 1; i <= node_num; i++ ){if(point[i] != temp_Point_1 && is_Click_Suc(cur_click_pos, point[i], RADIUS)) // 若選中了與第一個點不同的點{function_num = 2; // 重新把控制權交給功能號2(便于重復添加“邊”)int save_side_num = side_num++; // 線數量 + 1temp_Point_2 = point[i];line[side_num].node_2 = i;if(line[side_num].node_1 > line[side_num].node_2) // 確保邊的起點下標比終點的小, 不然做交換{int temp = line[side_num].node_1;line[side_num].node_1 = line[side_num].node_2;line[side_num].node_2 = temp;}for( int j = 1; j < side_num; j++ ) // 判斷是否路線已經存在{if(line[side_num].node_1 == line[j].node_1 && line[side_num].node_2 == line[j].node_2){line[side_num] = line[0];side_num--;QMessageBox::warning(this, "警告", "該路徑已添加!");break;}}if(save_side_num != side_num) // 如果路該線之前在圖中不存在, 則該表達式成立{int ind_1 = line[side_num].node_1;int ind_2 = line[side_num].node_2;dis_matrix[ind_1][ind_2] = dis_matrix[ind_2][ind_1] = Count_distanse(point[ind_1], point[ind_2]); // 距離矩陣賦值line[side_num].ind = side_num; // 邊的“編號”line[side_num].dis = Count_distanse(point[ind_1], point[ind_2]); // 邊的長度}ui->Message_1->clear();ui->Message_1->addItem("目前有結點個數:" + QString::number(node_num));ui->Message_1->addItem("目前有邊的條數:" + QString::number(side_num));ui->Message_1->addItem("如果還要繼續添加邊, 請選擇下一條邊的起點");break;}}update();break;case 4: // 刪除結點......}} }void Tour_System::on_Btn_1_1_clicked() // 新增結點 {All_flag_Clear(); // 標簽清空操作Recover(); // 按鈕信息重置if(function_num != 1){function_num = 1;ui->Btn_1_1->setStyleSheet("border-image: url(:/new/prefix1/btn_2.png);");ui->Btn_1_1->setText("停止該操作");ui->Message_1->clear();ui->Message_1->addItem("請選擇一個位置添加新結點");}else{function_num = 0;ui->Btn_1_1->setText("新增結點");ui->Message_1->clear();}}void Tour_System::on_Btn_1_2_clicked() // 新增邊 {All_flag_Clear(); // 標簽清空操作Recover(); // 按鈕信息重置if(function_num != 2){function_num = 2;ui->Btn_1_2->setStyleSheet("border-image: url(:/new/prefix1/btn_2.png);");ui->Btn_1_2->setText("停止該操作");ui->Message_1->clear();ui->Message_1->addItem("請選擇新增邊的起點");}else{function_num = 0;ui->Btn_1_2->setText("新增邊");ui->Message_1->clear();} }5.2 判斷創建的導游線路圖有無回路的算法——拓撲圖:
??● 算法思路:
????[1]采用拓撲排序,先用一維數組存儲所有結點的度(數組下標設為結點對應的序號)
????[2]每有一條邊,與之相連的結點的度數就加 1
????[3]然后我們進行遍歷,將度數為 1 的結點刪去(與之相連的邊也要刪去)
????[4]數組也要隨之更新,刪去的那條邊所相連的結點的度數 - 1
????[5]如果已沒有符合條件的結點被刪去,則跳到[5],否則轉向[2]
????[6]如果還有數組中還有數,那么打印出它們即是存在回路的幾個結點。
????時間復雜度:O(n^2)
??● 流程圖如下:
??● 代碼如下:
5.3 輸出給定入口景點的導游線路圖的算法——DFS
??● 算法思路如下:
????[1]首先設定每個結點最多只能被訪問一次(有些結點所處的位置可能是“死胡同”)
????[2]用一維的vector來儲存結果, 單元依次存儲路徑結點的info(標簽).
????[3]采用DFS方式進行搜索, 每搜索到一個結點就放入當前的vector里面
????[4]發生遞歸(兩種情況:<1>搜完了所有結點;<2>搜索失敗), 注意對vector的調整
????[5]每次調用該函數時,都會進行“性能”比較,會將“好路線”更新到ans里面
????[6]最后輸出對應ans最后一組結點信息即可。
??● 流程圖如下:
??● 代碼如下:
5.4 求兩個景點間的最短路徑的算法——Floyd
??● 算法思路如下:
????[1]初始化距離矩陣和路徑矩陣
????[2]依次加入每一個結點, 加入后更新距離矩陣和路徑矩陣
????[3]更新機制:
????[4]最后再進行 “回溯” 輸出最短路徑即可(詳見Find_Shortest_Path()函數)
??● 流程圖如下:
??● 代碼如下:
5.5 給出道路建設(最小生成樹)的算法——Kruskal
??● 算法思路如下:
????[1]將所有的邊提取出來, 然后按邊長進行排序(快排+升序)
????[2]再將每一個結點都劃分為一個單獨的集合(初始化)
????[3]然后依次加邊(按邊長從小到大的順序), 被連接在一起的結點歸屬到一個集合
????[4]在加邊過程中,加了這條邊若會形成回路就跳過這條邊(采用查并集算法)
????[5]當所有的結點(n個)都被加入且在一個連通集合里面的時候, 把所有加入的邊(n-1條)都輸出出來, 圖形界面展示即可
????[6]最后給出景區建設中的能花最小的代價的道路建設。
??● 流程圖如下:
??● 代碼如下:
六、測試數據及其結果分析
??● 登錄界面如下:
??● 創建景區結點和道路:
??● 刪除景區結點和邊:
??● 刪除景區結點和邊:
??● 編輯景區結點和邊:
??● 加載圖片背景(無結點、邊的數據):
??● 注:加載地圖功能和加載背景功能類似,只是多加了一個讀文本文件的操作,而加載背景只讀取限定后綴名的圖片。保存地圖功能是加載地圖的反操作。清除屏幕功能即是把顯示框里面的所有內容清除。這三個功能不方便用截圖方式體現,詳見源代碼。
??● 判斷有無回路(拓撲排序)的演示圖:
??● 建立導游線路(DFS)的演示圖:
??● 求兩點之間的最短路徑(Floyd)的演示圖:
??● 最小代價修建道路(Kruskal)的演示圖:
七、完整代碼
??● 可執行文件下載鏈接(百度云網盤,提取碼: mlxg):https://pan.baidu.com/s/1eStv1uIHXjaMns_0JZY3eg.
??● 項目文件源代碼:https://download.csdn.net/download/Wang_Dou_Dou_/47693292.
八、參考附錄
[1]《Qt5 開發及實例 第3版》 作者:陸文周
[2] Qt 5.14.2 下載、安裝、使用教程,Qt+vs2019開發環境搭建
鏈接: https://www.bilibili.com/video/BV1r54y1G7m4.
[3] “地圖”編輯器 之 程序演示【感謝南開大學的鍆鋅UP主,框架搭建主要參考了他的】
鏈接: https://www.bilibili.com/video/BV1k64y1W73o?spm_id_from=333.999.0.0.
?? ??
總結
以上是生活随笔為你收集整理的景点旅游信息系统——C/C++程序设计、Qt图形化界面的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql codesmith_Code
- 下一篇: 关于spring MVC 绑定json字