Dijstra 算法 寻找最短路径
在图论中,经常要遇到的就是寻找最短路径。今天先学了下Dijstra算法
思想:在加权有向图中,从当前节点出发,寻找邻居节点中路径最短的那条。然后将该节点作为下次出发的节点。如果下次遍历到已经访问的节点,比较从该路径到达此节点的路径长度,更新最短的距离。
实现方法:利用数组A记录下每个节点的到起始节点的最短距离。
利用数组B记录下节点是否已经访问过了。此访问与遍历图的访问概念不同。只有遍历完此节点的邻居节点才能算访问结束。
本文的图结构为如下所示:
分析:
本文设置的是从D点开始,也就是索引为3。程序将计算其它节点到该点的最短距离。
从D开始,分析邻居节点,标记A与H到D点的距离,edge(DH)<edge(DA)。将D标记为已访问。
而后从H点开始,标记E与H点,分析到A,E,I中E的currDist值最小。将H标记为已访问。
从E开始,更新A,FcurrDist,待比较的元素为A,F,I,因此又从A开始,以此类推
过程如下:
节点 距离
D 0
A -1,4
H -1,1
E -1,-1,6,5
I -1,,1,10,10,10,9
F -1,-1,-1,-1,8,
B -1,-1,-1,-1,-1,9,
C -1,-1,-1,-1,-1,11,11,
G -1,-1,-1,-1,-1,15,15,12
J -1,-1,-1,-1,-1,-1,11,
代码如下:
void Graph::findPathTest()
{
int weightGraph[10][10]=
{
{0,0,0,0,1,0,0,10,0,0},//A
{0,0,2,0,0,0,0,0,0,0},//B
{0,2,0,0,0,0,0,0,0,0},//C
{4,0,0,0,0,0,0,1,0,0},//D
{0,0,0,0,0,3,0,0,0,0},//E
{0,1,3,0,0,0,7,0,1,0},//F
{0,0,0,0,0,0,0,0,0,0},//G
{0,0,0,0,5,0,0,0,9,0},//H
{0,0,0,0,0,0,0,0,0,2},//I
{0,0,0,0,0,0,1,0,0,0},//J
};//初始化带权图
int currDist[10];
for (int i=0;i<10;i++)
{
currDist[i]=-1;
}
int nStartNodePos=3;
//设起始点为d.矩阵的大小为10*10
DijkstraAlgorithm(weightGraph,nStartNodePos,currDist);
cout<<endl<<endl<<"各节点到"<<nStartNodePos<<"的最短距离为:"<<endl;
for (int i=0;i<10;i++)
{
cout<<" "<<currDist[i];
}
}
/************************************************************************/
/*函数功能:最短路径
参数说明:weightGraph 加权有向图
startNodePos 开始节点
currDist 各节点到起始节点的最短路径
*/
/************************************************************************/
void Graph::DijkstraAlgorithm( int weightGraph[10][10],int startNodePos,int currDist[10] )
{
currDist[startNodePos]=0;//起始点的最短路径为0。
int compare[10];//访问标记,-1为未访问,0为已经访问过了,1代表下次应该访问
for(int i=0;i<10;i++)
{
compare[i]=-1;
}
int tempNodeFlag=startNodePos;//当前访问的索引
int num=0;//计算已经访问的个数
while(num<10)//当访问的个数<10
{
int weightValue=-1;//计算从该点出发的路径最短的点
for (int i=0;i<10;i++)
{
if (weightGraph[tempNodeFlag][i]>0)//保证是未被访问过的节点
{
int data=weightGraph[tempNodeFlag][i]+currDist[tempNodeFlag];
if (currDist[i]==-1)//若还未进行赋值
{
currDist[i]=data;
}
else if (currDist[i]>data)//若权重更小,则重新赋值
{
currDist[i]=data;
}
if (compare[i]==-1)
{
compare[i]=1;//将数据的索引赋予tempArray。比较的时候从currDist中对应的索引取数据
}
}
}
compare[tempNodeFlag]=0;//将访问的标志设为true
num++;//访问节点数目加1
for (int i=0;i<10;i++)
{
if (compare[i]==1)//如果下次应该访问
{
if (weightValue==-1)
{
weightValue=currDist[i];
tempNodeFlag=i;
}
else if (currDist[i]<weightValue)
{
tempNodeFlag=i;//找到最小的那个元素
}
}
}
}
//算法分析:复杂度为O(V^2).while执行O(V),分析是否有邻居节点以及是否要比较的元素均为O(V)
运行结果:
小结:
1)结束也可以用是否所有的点的visited都为true判断。
2)还是标志
3)各位大牛还多多指教