/* 引入:: Dijkstra算法算是贪心算法实现的,在每个阶段都把当前的当作最好的处理。
该算法的核心是:我们默认是先加入0这个顶点到最短路径中,再加入其他顶点,加入的顶点应该满足到其他没有加入最短路径的顶点的距离最小。并且每加入一个顶点就要更新它到其他没有加入到最短路径的顶点的距离是否更近,如果找到经过这个刚刚加进去的顶点与其他顶点的距离更近的,那么就更新该以这个顶点为下标lowcost数组的值,以便于之后进行下一次的查找,直到所有的顶点都加入到最短路径中,这样就完成了单源最短路径的算法dijstra算法的实现。*/
#include<stdio.h>
#include<stdlib.h
#define maxsize 100
#define INFINITY 65535//表示不可达,一般用于初始化
//用邻接矩阵来设计迪杰斯特拉算法
typedef struct
{
int numnode, numedge;
int vert[maxsize];
int arc[maxsize][maxsize];
}pragh;//邻接矩阵的数据结构
void init(pragh *G)//图的初始化
{
printf("请输入顶点数和边数\n");
scanf_s("%d%d", &G->numedge, &G->numedge);
printf("图的初始化工作完毕\n");
}
void create(pragh* G)
{
int w,i,j;
printf("请分别输入顶点\n");
for ( i = 0; i < G->numnode; i++)
{
scanf_s("%d", &G->vert[i]);
}
for ( i = 0; i < G->numnode; i++)
{
for ( j = 0; j < G->numnode; j++)
{
G->arc[i][j] = INFINITY;
}
}
for (int m = 0; m < G->numedge; m++)
{
printf("请输入(i,j)边的下标i和j和权值w\n");
scanf_s("%d%d%d", &i, &j, &w);
G->arc[i][j] = w;
G->arc[j][i] = G->arc[i][j];
}
printf("图的初始化工作完毕\n");
}
typedef int patharc[maxsize];//用于存储最短路径的下标的数组(p[v]表示前驱顶点的下标)
typedef int shortpathtable[maxsize];//用于存储各点的最短路径的权值和
void shortpathdijkstra(pragh G,patharc *P,shortpathtable *D)
{
int final[maxsize];//当它的值为0时表示已经找到了最短路径
//已经作为根基再往外扩建,再寻找路径,并进行更新后,再寻找,直到将所有的顶点连接在一起
int i,min;//min用于寻找接下来加入到最短路径的是某个顶点的权值
int j;//本程序中是用于内层for循环,找到从1开始的所有顶点到
//还没有加入最短路径发其他结点的关系,(即用于寻找最短路径的下标k
//和对应权值)
int k;//用于之后再存储最短路径的顶点的下标
for (i = 0; i < G.numnode; i++)
{
final[i] = 0;//初始化所有的结点都没有加入到最短路径中
*(D)[i] = G.arc[0][i];//将与0相连的所有顶点的权值都加入到D权值这个数组里面
//至于为什么要解引用,因为传入的参数D是一个二级指针,而取它的值必须要对其解引用
*(P)[i] = -1;//表示刚开始时所有顶点的最短路径还没有
}
//现在把v0加入到最短路径的(这个是任意的,但是我们一般把v0最先加入到最短路径之中)
for (i = 1; i < G.numnode; i++)//注意现在的顶点的初始化要从1开始,因为0已经加入到最短路径之中了
{
min = INFINITY;
for (j = 1; j < G.numnode; j++)
{
if (*(D)[j] < min && !final[j])
{
min = *(D)[j];
k = j;
}
}
//退出内层for循环之后就可以找到距离i顶点的(i从1开始)
//到其余还没有加入到生成树的结点的最短路径的该顶点的下标k
//和与最短路径的权值min
//找到了之后注意要进行存储
final[k] = 1;//表示刚刚找到的k顶点已经加入到最短路径的数组内了
*(P)[i] = k;//表示i顶点的最短路径的下标为k
*(D)[i] = min;//且i顶点的最短路径的下标k对应的权重为min
//更新D数组,因为加入了一个顶点之后可能会有新的最短路径出现(因为路径可能更多了
//可能会经过这个刚刚加入的顶点到其他顶点的距离更小了,那么就相当于代价更小了
//所以要进行更新数组
for (i = 0; i < G.numnode; i++)
{
if (!final[i] && (min + G.arc[k][i] < *(D)[i]))
{//判断条件的第二句话的意思就是如果经过k顶点(刚刚加入到最短路径的顶点)
//到其余没有加入到最短路径的顶点的距离更小的话,那么就要更新
//这些顶点所在的最短路径的下标和权值
*(D)[i] = min + G.arc[k][i];
*(P)[i] = k;
}
}
}
printf("dijkstra算法执行完毕,最短路径已经找到\n");
}
int main(void)
{//且dijkstra算法和FLoyd算法的不同之处在于:前者只能用于求一个顶点到
//路径中任意一个顶点的最短距离(单源),但是后者可以用于求图中的任意一个
//顶点到任意的另外一个顶点的最短据伦理(多源)
//但是如果我们将dijkstra算法的所有顶点都遍历一遍,也可以和floyd算法
//达到一致的效果,且时间复杂度都是n的立方
//但是floyd算法要简单一点,且所用的时间也要少一点(因为dijkstra算法的
//真正的时间复杂度为2n的立方,但是Floyd算法的时间复杂度为n的立方,
//所以Floyd算法所用时间相对较小一点
```c
pragh G;
patharc P;
shortpathtable D;
init(&G);
create(&G);
shortpathdijkstra(G,&P,&D);
system("pause");
return 0;
}
/*该算法和prim算法很相似,都是用了加点法,但是prim算法求的是最小生成树,但是dijstra本程序的算法求的是最短路径*/