QT_地图导航 源码下载
https://github.com/douzujun/MyMapView
主要算法讲解:
1. 计算最短路径(dijkstra算法)
Step1:
(1)找到最短路径已经确定的顶点,从它已经确定的顶点,从它除法更新相邻顶点的最短距离。
(2)此后不需要再关心1中的“最短距离已经确定的顶点”。
(3)在(1)和(2)中提到的“最短距离已经确定的顶点”要求解的关键。在最开始时,只有起点的最短距离是确定的。而在尚未使用过的顶点中,距离d[i]最小的顶点就是最短距离已经确定的顶点。这是因为由于不存在负边,所以d[i]不会在更新中变小。
定义几个方便算法描述的变量:
int cost[MAX_V][MAX_V]; //cost[u][v]表示表e=(u,v)的权值(不存在这条边时设为INF)
int d[MAX_V]; //顶点s出发的最短路径
bool used[MAX_V]; //已经使用的图
Step2:
(1)如果,我们需要输出最短路的路径。注,在求解最短路径时,满足d[j] = d[k] + cost[k][j]的顶点k(d[j]是表示从起点开始到j的最短路径距离,cost[k][j]是表示k到j的距离),就是最短路上的顶点j的前驱结点,因此通过不断寻找前驱结点就可以恢复最短路。时间复杂度是O(E)。
(2)如果,我们用prev[j]来记录最短路上的顶点j的前驱,那么就可以在O(|V|)时间内完成最短路的恢复。在d[j]=d[k]+cost[k][j]更新时,修改prev[j]=k, 这样就可以求得prev数组。在计算从起点s出发到j的最短路时,通过prev[j]就可以知道顶点j的前驱,因此不断把j替换成prev[j]直到j = s为止即可。代码如下:
1. 首先要对图进行初始化,才能正常计算最短路径
1 MainWindow::DijkstraFindPath::DijkstraFindPath() 2 { 3 mgraph.vexnum = 40; //初始化点数目 4 for (int i = 0; i < mgraph.vexnum; i++) //初始化点编号 5 mgraph.vexs.push_back (i); 6 mgraph.arcnum = 98; //边数 7 for (int i = 0; i < mgraph.vexnum; i++) { 8 for (int j = 0; j < mgraph.vexnum; j++) { 9 if (i == j) 10 mgraph.arcs[i][j].adj = 0; 11 else 12 mgraph.arcs[i][j].adj = INF; 13 } 14 } 15 }
2. 设置图的景点之间的权值。
1 void MainWindow::DijkstraFindPath::CreateGraph () 2 { 3 mgraph.arcs[0][1].adj = mgraph.arcs[1][0].adj = 45; //6 - 5 4 mgraph.arcs[0][6].adj = mgraph.arcs[6][0].adj = 165; //6 - 10 5 mgraph.arcs[1][2].adj = mgraph.arcs[2][1].adj = 45; //5 - 4 6 mgraph.arcs[2][3].adj = mgraph.arcs[3][2].adj = 45; //4 - 3 7 mgraph.arcs[3][4].adj = mgraph.arcs[4][3].adj = 45; //3 - 2 8 mgraph.arcs[3][15].adj = mgraph.arcs[15][3].adj = 24; //3 - 22 9 mgraph.arcs[4][5].adj = mgraph.arcs[5][4].adj = 45; //2 - 1 10 mgraph.arcs[13][15].adj = mgraph.arcs[15][13].adj = 85;//23 - 22 11 mgraph.arcs[0][13].adj = mgraph.arcs[13][0].adj = 55; //6 - 23 12 mgraph.arcs[13][2].adj = mgraph.arcs[2][13].adj = 50; //23 - 4 13 mgraph.arcs[5][11].adj = mgraph.arcs[11][5].adj = 65; //1 - 一食堂 14 mgraph.arcs[11][12].adj = mgraph.arcs[12][11].adj = 10;//一食堂-操场 15 mgraph.arcs[11][27].adj = mgraph.arcs[27][11].adj = 85;//一食堂-祁通1 16 mgraph.arcs[27][28].adj = mgraph.arcs[28][27].adj = 85;//祁通1-祁通2(路口) 17 mgraph.arcs[5][29].adj = mgraph.arcs[29][5].adj = 87; //一食堂-岔路口 18 mgraph.arcs[29][11].adj = mgraph.arcs[11][29].adj = 50;//一食堂到岔路(通向7号楼的) 19 mgraph.arcs[29][30].adj = mgraph.arcs[30][29].adj = 32;//岔路-祁通大道 20 mgraph.arcs[30][10].adj = mgraph.arcs[10][30].adj = 90;//祁通大道-图书馆 21 mgraph.arcs[30][28].adj = mgraph.arcs[28][30].adj = 80;//祁通大道-祁通2 22 mgraph.arcs[28][26].adj = mgraph.arcs[26][28].adj = 15;//祁通2-方肇周 23 mgraph.arcs[25][27].adj = mgraph.arcs[27][25].adj = 273;//西大门-祁通1 24 mgraph.arcs[27][28].adj = mgraph.arcs[28][27].adj = 84; //祁通1-祁通2 25 mgraph.arcs[5][12].adj = mgraph.arcs[12][5].adj = 70; //1 - 操场 26 mgraph.arcs[6][7].adj = mgraph.arcs[7][6].adj = 45; //10 - 9 27 mgraph.arcs[7][8].adj = mgraph.arcs[8][7].adj = 45; //9 - 8 28 mgraph.arcs[8][9].adj = mgraph.arcs[9][8].adj = 45; //8 - 7 29 mgraph.arcs[9][10].adj = mgraph.arcs[10][9].adj = 150; //7 - 图书馆 30 mgraph.arcs[6][14].adj = mgraph.arcs[14][6].adj = 140; //10 - 13 31 mgraph.arcs[14][16].adj = mgraph.arcs[16][14].adj = 39;//13 - 12 32 mgraph.arcs[14][17].adj = mgraph.arcs[17][14].adj = 39;//13 - 16 33 mgraph.arcs[16][18].adj = mgraph.arcs[18][16].adj = 39;//12 - 15 34 mgraph.arcs[17][18].adj = mgraph.arcs[18][17].adj = 39;//16 - 15 35 mgraph.arcs[18][19].adj = mgraph.arcs[19][18].adj = 20;//15 - 14 36 mgraph.arcs[17][20].adj = mgraph.arcs[20][17].adj = 137;//16 - 19 37 mgraph.arcs[20][21].adj = mgraph.arcs[21][20].adj = 39; //19 - 18 38 mgraph.arcs[21][22].adj = mgraph.arcs[22][21].adj = 39; //18 - 17 39 mgraph.arcs[19][22].adj = mgraph.arcs[22][19].adj = 130;//14 - 17 40 mgraph.arcs[22][23].adj = mgraph.arcs[23][22].adj = 53; //17 - 二超 41 mgraph.arcs[23][24].adj = mgraph.arcs[24][23].adj = 5; //二超 - 二食堂 42 43 //以下处理细节—这是景点之间的一小段路之间的权值,因为用界面绘制路线,会//出现弧状的路线,所以需要定额外的坐标 44 mgraph.arcs[30][31].adj = mgraph.arcs[31][30].adj = 30; //祁通大道-祁通大道2 45 mgraph.arcs[31][32].adj = mgraph.arcs[32][31].adj = 10; //祁通大道2-祁通大道3 46 mgraph.arcs[32][10].adj = mgraph.arcs[10][32].adj = 20; //祁通大道3-图书馆 47 mgraph.arcs[10][33].adj = mgraph.arcs[33][10].adj = 80; //图书馆-祁通大道4 48 mgraph.arcs[33][34].adj = mgraph.arcs[34][33].adj = 45; //祁通4-祁通5 49 mgraph.arcs[34][24].adj = mgraph.arcs[24][34].adj = 45; //祁通5-二食堂 50 mgraph.arcs[34][23].adj = mgraph.arcs[23][34].adj = 45; //祁通5-二超 51 mgraph.arcs[33][35].adj = mgraph.arcs[35][33].adj = 30; //祁通4-通向14号楼的小道 52 mgraph.arcs[35][19].adj = mgraph.arcs[19][35].adj = 10; //小道-14号楼 53 mgraph.arcs[35][36].adj = mgraph.arcs[36][35].adj = 10; //小道14-小道15 54 mgraph.arcs[36][18].adj = mgraph.arcs[18][36].adj = 10; //小道15-15 55 mgraph.arcs[36][16].adj = mgraph.arcs[16][36].adj = 5; //小道15-12 56 mgraph.arcs[37][29].adj = mgraph.arcs[29][37].adj = 40; //岔路-岔路2 57 mgraph.arcs[37][9].adj = mgraph.arcs[9][37].adj = 45; //岔路2-7 58 60 }
3. 计算最短路径,并对输出路径进行初始化工作。
1 void MainWindow::DijkstraFindPath::dijkstra (int startPos) 2 { 3 for (int i = 0; i < mgraph.vexnum; i++) d[i] = INF; 4 for (int i = 0; i < mgraph.vexnum; i++) used[i] = false; 5 for (int i = 0; i < mgraph.vexnum; i++) prev[i] = -1; 6 d[startPos] = 0; 7 8 while (true) { 9 int v = -1; 10 for (int u = 0; u < mgraph.vexnum; u++) { 11 if (!used[u] && (v == -1 || d[u] < d[v])) v = u; 12 } 13 14 if (v == -1) break; 15 used[v] = true; 16 17 for (int u = 0; u < mgraph.vexnum; u++) { 18 if (d[u] > d[v] + mgraph.arcs[v][u].adj) { 19 d[u] = d[v] + mgraph.arcs[v][u].adj; 20 prev[u] = v; 21 } 22 } 23 } 24 }
4.存储起点到终点之间的路径。
1 QVector<int> MainWindow::DijkstraFindPath::get_Path (int endPos) 2 { 3 QVector<int> path; 4 //保存景点之间的最短路径上的全部景点 5 for ( ; endPos != -1; endPos = prev[endPos]) { 6 path.push_back (endPos); 7 } 8 //由于路径是从终点向起点保存的,还需要将路径逆置。 9 std::reverse(path.begin (), path.end ()); 10 return path; 11 }
全部代码:
1 首先要对图进行初始化,才能正常计算最短路径
1 /** 2 * 主要功能: 3 * 1. 绘制输入起点,终点最短路径 4 * 2. 双击地点, 查看景点信息 5 * 3. 修改景点图片 6 * 4. 打开测试地图,查看地图坐标,可缩放地图. 7 **/ 8 #ifndef MAINWINDOW_H 9 #define MAINWINDOW_H 10 11 #include <QMainWindow> 12 #include "mapwidget.h" 13 #include <QToolButton> 14 #include <QGraphicsLineItem> 15 #include <QGraphicsScene> 16 #include <QGraphicsView> 17 #include <QLabel> 18 #include <QComboBox> 19 #include <QTextEdit> 20 #include <QVector> 21 #include <QMouseEvent> 22 #include <QDialog> 23 #include <QPixmap> 24 #include <QGridLayout> 25 #include <QLineEdit> 26 #include <QFileDialog> 27 #include <QHBoxLayout> 28 29 class MainWindow : public QMainWindow 30 { 31 Q_OBJECT 32 public: 33 MainWindow(QWidget *parent = 0); 34 ~MainWindow(); 35 void createToolBar(); 36 void createAction(); 37 void setStart(int X, int Y); 38 void setEnd(int X, int Y); 39 void setNextPos (int index); 40 void initScene(); 41 public slots: 42 void setStartStation(); 43 void setEndStation(); 44 void FindPath(); 45 void Clear(); 46 void Revise(); 47 void callOtherMap(); 48 void ShowDialog(); 49 private: 50 MapWidget *mapWidget; 51 QLabel *startLabel; 52 QLabel *endLabel; 53 QComboBox *startComboBox; 54 QComboBox *endComboBox; 55 QComboBox *reviseComboBox; 56 57 QAction *findPathAction; 58 QAction *clearAction; 59 QAction *reviseAction; 60 QAction *callMap; 61 62 QGraphicsScene *scene; 63 QGraphicsView *view; 64 65 int startX, startY, endX, endY; 66 QVector<int> nextPath; 67 68 /* 69 * 图的实现,和最短路径算法声明 70 */ 71 struct ArcCell{ //弧信息 72 int adj; //对无权图有1,0表示是否相邻,对带权图,则为权值类型 73 // string info; //该弧的相关信息 74 }; 75 76 77 //内部类 78 static const int MAX_VERTEX_NUM = 50; 79 static const int INF = 999999; 80 81 struct MGraph{ 82 QVector<int> vexs; //顶点集合 83 //临接矩阵 84 ArcCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; 85 int vexnum; //顶点数 86 int arcnum; //边数 87 // int kind; //图的类型 88 }; 89 90 class DijkstraFindPath 91 { 92 public: