最短路径----狄克斯特拉 (digkstra)+邻接矩阵:
采用邻接矩阵的存储方式存储。算法主要用到了三个数组:
disp[],path和s数组。 disp数组主要是存储最短路径长度,path存储最短路径上当前顶点的前一个顶点,s用来标志顶点是否处理过。
其中主要有两步:循环找(找符合条件的顶点),循环改(改顶点对应的disp,path的值),其他细节均在代码中写出,注意的是,算法的动态过程可以优先理解一下,再来理解下面的代码。
代码如下:
#include <stdio.h>
#include <malloc.h>
#define inf 330
#define max 50
typedef struct node{
int no;
}bnode;//顶点结构体
typedef struct graph{
int a[max][max];
int e,n;
bnode nu[max];
}G;//邻接矩阵结构体
//创建邻接矩阵
void create(G &g, int b[max][max], int n, int e)
{
int i ,j;
g.e =e;//边数
g.n =n;//顶点数
for(i = 0; i<n; i++)
{
for(j = 0; j <n; j++)
g.a[i][j] = b[i][j];
}
for(int i=0; i<n; i++)
g.nu[i].no = i;
}
void show(G g)
{
int i ,j;
printf("创建的邻接矩阵:\n");
//下面代码段是显示矩阵的行列标识
printf(" ");
for(int i =0; i<g.n; i++)
printf("%d ",i);
printf("\n");
for(i =0; i<g.n; i++)
{
printf("%d: ",i);
for(j=0; j<g.n; j++)
{
if(g.a[i][j] == inf)
printf(" ∞") ;
else
printf(" %d ",g.a[i][j]);
}
printf("\n");
}
printf("\n%d个顶点,%d条边 \n",g.n, g.e);
}
//输出路径
/*两步:第一输出对应的v,i,disp[i]
第二循环找到最短路径的所有点
*/
void showdis(G g, int disp[], int path[], int s[], int v)
{
int apath[max];
int d;
int k;
for(int i =0; i<g.n; i++)
if(s[i]==1&& i!=v)
{
printf("路径%d ---> 路径%d 的长度: %d 路径为:", v,i,disp[i]);
//循环将路径值存入apath中,最后逆序输出
d=0;
apath[d]=i; //注意,这里是将 i 存入数组中
k = path[i];
if(k==-1) printf("没有路径\n");
else{
while(k!=v) //在path一直往前找。一直到起始顶点
{
apath[++d]=k;
k = path[k];
}
//最后将起始顶点也存储到数组中
apath[++d] = v;
//这里先输出一个值是因为下面的 -> 这个符号前面必须要输出一个数字。
printf("%d",apath[d]);
for(int j = d-1; j>=0; j--)
printf("->%d ",apath[j]);
printf("\n");
}
}
}
//狄克斯特拉算法
/*算法定义了三个数组disp,path,s
主要是 一:对三个数组的初始化, 二:将编号为 0 的顶点选中 ,
三:循环寻找最近权值最小的顶点 ,之后将其s修改为 1
四:循环修改没处理过的顶点的对应的disp与path
*/
void dijkstra(G g, int v)
{
int disp[max]; //存放最短边值
int path[max];//最当最短路劲下的当前顶点的前一个顶点
int s[max];//判断是不是已经处理过的顶点,0表示没有,1表示处理过了
//这个循环是对三个数组进行初始化
for(int i =0; i<g.n; i++)
{
disp[i] = g.a[v][i];
s[i] = 0;
if(g.a[v][i]<inf)
path[i] = v;
else
path[i] = -1;//这里表示标号为v的,以及顶点到初始点的值为inf的 都初始化为-1。
}
//选取第一个0编号的顶点
s[v]=1;
path[v] = 0;
//这个循环是在g.n-1条边下寻找
for(int i =0; i<g.n-1; i++)
{
int u;
//找最小的
int min= inf;
//寻找边值最小同时也是最近的顶点
for(int j=0; j<g.n; j++)
if(s[j]==0 && disp[j] <min)
{
u = j; //记录顶点编号
min = disp[j];
}
//找到就将s置为1,表示处理过了
s[u] =1;
//这个循环是在没处理过的顶点里,修改相应的disp与path的值
for(int j =0; j<g.n; j++)
if(s[j] == 0 && g.a[u][j]<inf && g.a[u][j]+disp[u] <disp[j])
{
disp[j] = g.a[u][j] + disp[u];
path[j] =u;
}
}
printf("\n分别输出 disp, path, s 三个数组值:\n");
for(int i =0; i<g.n; i++)
{
printf("%d ",disp[i]);
}
printf("\n");
for(int i =0; i<g.n; i++)
{
printf("%d ",path[i]);
}
printf("\n");
for(int i =0; i<g.n; i++)
{
printf("%d ",s[i]);
}
printf("\n\n");
//构造完成之后输出路劲
showdis(g,disp,path,s,v);
}
int main()
{
G g; //注意,这里创建的是结构体类型变量,如果是结构体指针的话,创建的矩阵就是链式
int a[max][max]={
{0,5,inf,7,inf,inf},
{inf,0,4,inf,inf,inf},
{8,inf,0,inf,inf,9},
{inf,inf,5,0,inf,6},
{inf,inf,inf,5,0,inf},
{3,inf,inf,inf,1,0}
};
int n=6, e=10;
//创建邻接矩阵
create(g,a,n,e);
show(g);
dijkstra(g,0);
return 0;
}
程序运行如下: