2. 打印输入有向图的结果:以邻接矩阵的形式打印出矩阵结果。
3. 求解最优路径:
Dijkstra算法是一种根据路径长度的递增顺序,逐步求出最短路径的算法,其主要思想为:首先求得一条最短的路径,然后再根据该条最短路径求得次最短路径,如此循环上述操作,最终求得一顶点至其他所有点的最短路径。如:
由上图可知,由源点v出发的最短路径为v-v1,此时就可确定已最短路径为v-v1有最短路径的基础上,从v1出发,看是否通过v1到其他点的路径,若新得到的路径比原本v到vn的路径短,则用v-v1-vn代替v-vn的路径,在此轮更新完毕后,选出路径中新得到的最小路径做为次最小路径,如此循环,即得到v到其他所有顶点的最短路径。
有向图如图所示:
寻找A到其他各点最短路径的步骤如下:
进行第一轮地筛选:
得到最第一轮中的最短路径为A-B的路径,路径长度为1,在A-B的路径基础上进行第二轮筛选:
由上可知,由B出发可有的相邻结点有:B-C(长度为4)、B-D(长度为2)、B-E(长度为5),得到几条新的路径:A-B-C(长度为5)、A-B-D(长度为3)、A-B-E(长度为6),因为A-B-C比A-C短,A-B-D比A-D短,A-B-E比A-E长,所以更新A到C的路径,更新A到D的路径,最终得到的第二轮筛选结果如下所示。
在第二轮筛选的结果中,最短路径为A-E,所以,通过A-E进行第三轮筛选:由E出发相邻的结点有:E-D(长度为3)(因为A-B已经是最短的路径,所以此处不用再算E到B的路径),得到的新路径为:A-E-D(长度为6),因A-E-D比A-D长,所以不用更新任何路径,结果如下。
由第三轮筛选结果得,A-B-D是最短的路径,所以在此基础上进行第四轮筛选:D无任何相邻结点,所以更新后结果如下。
至此,通过Dijkstra算法求出A到其它顶点的最优路径过程完毕,各最优路径分别为:
A到B:A-B,长度为1;
A到C: A-B-C,长度为5;
A到D: A-B-D, 长度为3;
A到E: A-E,长度为3。
class GraphMatrix{
public:
~GraphMatrix();
void createdGraph();
void printGraph();
void inputVertexNumber(); //输入有向图的结点数目
void makeVertexArray();//生成装有结点的数组
void inputEdgeNumber();//输入有向图的边的数目
void inputEdgeInfo();//输入边的信息,格式为:起点 权重 终点
void addEdgeToList(int vFrom, int weight, int vTo);//添加边到对应的邻接矩阵中
int n();//返回有向图的结点总数
int e();//返回有向图的边的总数
int first(int v);//返回结点v的第一个相邻结点
int next(int v, int w);//返回结点v在相邻结点w后的第一个邻结点
int weight(int v1, int v2);//返回结点v1和v2之间的权重
int getMark(int v);//得到结点v是否被访问的标记
void setMark(int v, int val);//设置结点是否被访问的标记
bool isEdge(int v1, int v2);//判断结点v1和v2间是否有边
void setRoute(int v1, int v2, int val);//存储有向图的路径,将路径矩阵的坐标(v1, v2)处的值设为val(一般为结点值)。
int getRoute(int i, int j);//得到存储路径的矩阵中结点i与j之间的值(一般为结点值)。
int ConvertInput(string str);//将字符串str(地点名称)转换为对应的结点的数字
void CityName(int Node);//得到结点整数Node所对应的城市名称
bool JudgeIsFalse(string str);//进行一些防错机制的判断
private:
int m_vCount;//结点数目
int m_eCount;//边的数目
int** m_vVertex;//邻接矩阵
int *mark;//标记结点是否已确定最短路径
int** Route;//存储具体的路径
string *City;//存储城市的名称
};
名称 | A | B | C | D | E |
---|---|---|---|---|---|
结点对应整数 | 0 | 1 | 2 | 3 | 4 |
D[] | D[0] | D[1] | D[2] | D[3] | D[4] |
值 | 0 | 1 | 7 | ∞ | 3 |
void InitD(GraphMatrix * G, int * D, int StartNode){
for (int i = 0; i < G->n(); i++){//从源点开始遍历每个结点
if (G->isEdge(StartNode, i)){
D[i] = G->weight(StartNode, i);//若源点StartNode与结点i之间存在边,则令D[i]等于两结点之间的权重
}else{
D[i] = INT_MAX;//若源点与结点i间不存在边,则令D[i]值为无穷大
}
}
D[StartNode] = 0;//令源点与其本身的距离为0
}
void InitRouteMatrix(GraphMatrix * G, int StartNode){
for (int i = 0; i < G->n(); i++){//一层一层地对矩阵进行处理
G->setRoute(i, 0, StartNode);//设置每层的第一个数为StartNode
G->setRoute(i, 1, i);//设置每层的第二个数为层数
for (int j = 2; j < G->n(); j++){
G->setRoute(i, j, -1);//将每层的其余数值设为-1
}
}
}
void InitMark(GraphMatrix* G){
for (int i = 0; i < G->n(); i++){
G->setMark(i, UNVISITED);//将每个点设置为未被访问
}
}
int minVertex(GraphMatrix * G, int* D){
int i, Shortest = 0;
for (i = 0; i < G->n(); i++){
if(G->getMark(i) == UNVISITED){
Shortest = i;//先找到一个未被访问的结点
break;
}
}
for (i++; i < G->n(); i++){
if ((G->getMark(i) == UNVISITED) && (D[i] < D[Shortest])){
Shortest = i;//在其它未被标记的结点中找到一个具有更短路径的结点
}
}
return Shortest;
}
void Dijkstra(GraphMatrix * G, int* Dis, int StartNode){
int i, Shortest, w;
InitD(G, Dis, StartNode);
InitRouteMatrix(G, StartNode);//初始化路径矩阵
InitMark(G);
for (i = 0; i < G->n(); i++){
Shortest = minVertex(G, Dis);//得到最短路径的终点
if (Dis[Shortest] == INT_MAX) return;//若最短路径长度为正无穷,则此时剩余的路径中不存在可达的路径,则结束算法
G->setMark(Shortest, VISITED);//将最短路径的终点设为已被访问
for (w = G->first(Shortest); w < G->n(); w = G->next(Shortest, w)){//依次遍历最短路径终点的每个相邻结点
if (Dis[w] > (Dis[Shortest] + G->weight(Shortest, w))){
Dis[w] = Dis[Shortest] + G->weight(Shortest, w);//如果新得到的s与w间的路径长度D[v]+weight(v,w) < 原路径D[w], 则更新D[w]的值
//更新路径矩阵
//每当从s到w有更短的路径时,就将s到w的路径更新为s到v的路径 + v到w的边
int j;
for (j = 0; (G->getRoute(Shortest, j) != -1) && (j < G->n()); j++){
G->setRoute(w, j, G->getRoute(Shortest, j));
}
G->setRoute(w, j, w);
}
}
}
}
若需要见源代码,请见:https://blog.csdn.net/qq_40369246/article/details/86651145