求最短路径最常用的有迪杰斯特拉(Dijkstra)和弗洛伊德(Floyd)算法两种。本着简洁为王道的信条,我选择了Floyd算法。
Floyd算法
首先来看一个简单图,红色标记代表在数组的下标,橙色标记代表距离(边权值)
我们用D[6][6]这个矩阵存储两点之间最短路径,用P[6][6]这个矩阵存储路径
两个矩阵初始化如下,若两点不直接联通,则初始化为无穷大
A | B | C | D | E | F | |
A | 0 | 7 | ∞ | ∞ | 10 | 5 |
B | 7 | 0 | 8 | ∞ | ∞ | ∞ |
C | ∞ | 8 | 0 | 6 | ∞ | 5 |
D | ∞ | ∞ | 6 | 0 | 7 | ∞ |
E | 10 | ∞ | ∞ | 7 | 0 | 4 |
F | 5 | ∞ | 5 | ∞ | 4 | 0 |
A | B | C | D | E | F | |
A | 0 | 1 | 2 | 3 | 4 | 5 |
B | 0 | 1 | 2 | 3 | 4 | 5 |
C | 0 | 1 | 2 | 3 | 4 | 5 |
D | 0 | 1 | 2 | 3 | 4 | 5 |
E | 0 | 1 | 2 | 3 | 4 | 5 |
F | 0 | 1 | 2 | 3 | 4 | 5 |
核心代码
for (int k = 0; k < G->numVertexes; ++k)
{
for (int v = 0; v < G->numVertexes; ++v)
{
for (int w = 0; w < G->numVertexes; ++w)
{
if (D[v][w] > D[v][k] + D[k][w])
{
D[v][w] = D[v][k] + D[k][w];
P[v][w] = P[v][k];
}
}
}
}
其中k为中转顶点下标,级无论走哪条路径,都要经过k下标的顶点,v代表起始顶点,w代表终点。
当取k=0时代表所有路径都经过下标为0的地点(A)
- v取2,w取3,即从C到D,有C-A-D,可惜这个路径的和不小于C-D的路径大小,所以D数组不会有变化。
- v取1,w取4,即从B到E,有B-A-E,发现它的值为17,小于B-E的无穷大,所以D[1][4]由无穷大改为17,因为D数组变化了,所以P数组也要跟着变化,把P[1][4]改为当前P[1][0],代表从B到E下一节点为A
- 同理在k取0时,将这个时间复杂度为O(6^2)的循环走完,那么D和P矩阵如下
A | B | C | D | E | F | |
A | 0 | 7 | ∞ | ∞ | 10 | 5 |
B | 7 | 0 | 8 | ∞ | 17 | 12 |
C | ∞ | 8 | 0 | 6 | ∞ | 5 |
D | ∞ | ∞ | 6 | 0 | 7 | ∞ |
E | 10 | 17 | ∞ | 7 | 0 | 4 |
F | 5 | 12 | 5 | ∞ | 4 | 0 |
A | B | C | D | E | F | |
A | 0 | 1 | 2 | 3 | 4 | 5 |
B | 0 | 1 | 2 | 3 | 0 | 0 |
C | 0 | 1 | 2 | 3 | 4 | 5 |
D | 0 | 1 | 2 | 3 | 4 | 5 |
E | 0 | 0 | 2 | 3 | 4 | 5 |
F | 0 | 0 | 2 | 3 | 4 | 5 |
然后取k=1,2,3,4,5遍历完成后,D和P就是我们的目标数组了。
输出结果
这个就比较简单了,比如我输入1,4,代表我想知道从B走到E的最短路径,先输出最短路径为D[1][4]。然后就是具体的路径,我们找到P[1][4],发现它等于0,意味着从B走到E要先走B-A,然后我们看P[0][4],发现它等于4,也就是E,到达终点。
void AdjacencyList::ShowShortestResult(int originPos,int endPos) {
int temp;
cout << "地点" << _mapName[originPos] << "到地点" << _mapName[endPos] << "最短距离为" << ShortestPathvalue[originPos][endPos] << endl;
temp = ShortestPathmatrix[originPos][endPos];
cout<<"具体路径为:"<<_mapName[originPos]<<"——>";
while (temp!=endPos){
cout<<_mapName[temp]<<"——>";
temp = ShortestPathmatrix[temp][endPos];
}
cout<<_mapName[endPos]<<endl;
}