查看原文:http://www.wyblog.cn/2016/12/09/%e5%b8%a6%e6%9d%83%e8%b7%af%e5%be%84%e6%9c%80%e7%9f%ad-dijkstra%e7%ae%97%e6%b3%95/
Dijkstra算法是经典的求取带权最短路径的算法。 它采用贪心的思想,在每一步仅选取一个能够被确定为从已知顶点到该顶点已经为最短路径的顶点,并动态地去规划该顶点到其他顶点的最短路径距离。 本篇博文算法思想参考自《数据结构及算法分析》这本书,并将书本里的思想以及代码伪码给实现了。 图的实现还是采用邻接表的方式,比较节省空间。在每一步求取未知的最小路径的顶点时,可以采用小顶堆来实现,我这里是采用遍历的方式,因为顶点结构内包含了是否是未知的标记。 从Dijkstra算法的原理上看,要设置的变量有:
- 要确定顶点是已知还是未知的,所以需要一个Known变量。
- 要确定带权的路径的长度,需要一个dist变量。
- 要确定路径信息,所以每一个顶点结构体内部要储存最短路径到达此顶点的上一个顶点。
- 路径的权值,就储存在邻接表链表节点的weight变量里。
打印路径信息的函数采用递归的方式,逐层向上查找,直到达到起点。 算法代码如下:
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
#define MAX_VERTEX_NUM 100
#define Vertextype int
#define Infinity 0xffff
#define NotAVertex -1
typedef struct EdgeNode
{
int adjVertex;
int weight; //邻接权重
EdgeNode *nextEdgeNode;
}EdgeNode;
typedef struct VerNode
{
int Known;
Vertextype data;
int dist;
int path;
EdgeNode *firstedge;
}VerNode;
typedef struct Graph
{
VerNode verNode[MAX_VERTEX_NUM];
int vertex_num,edge_num;
}Graph;
void CreateDAG(Graph &G,int n,int e)
{
int i,j,w,k;
G.vertex_num=n;
G.edge_num=e;
for(i=1;i<=n;i++)
{
cin>>G.verNode[i].data;
G.verNode[i].Known=0;
G.verNode[i].dist=Infinity;
G.verNode[i].path=-1;
G.verNode[i].firstedge=NULL;
}
for(k=1;k<=e;k++)
{
EdgeNode *p;
p=new EdgeNode;
cin>>i>>j>>w;
p->adjVertex=j;
p->weight=w;
p->nextEdgeNode=G.verNode[i].firstedge;
G.verNode[i].firstedge=p;
}
}
void Dijkstra(Graph &G,int n,int start) //带权路径最短Dijkstra算法
{
VerNode V;
EdgeNode *w;
int i,j,temp_num,temp_dist;
G.verNode[start].dist=0;
for(i=1;i<=n;++i) //n个点待查找
{
temp_dist=Infinity;
temp_num=0;
for(j=1;j<=n;++j) //先寻找未知的最短顶点
{
if(G.verNode[j].Known==0 && G.verNode[j].dist<temp_dist)
{
temp_dist=G.verNode[j].dist;
temp_num=j;
}
}
G.verNode[temp_num].Known=1;
w=G.verNode[temp_num].firstedge;
while(w)
{
if(G.verNode[w->adjVertex].Known==0)
{
if(G.verNode[temp_num].dist+w->weight < G.verNode[w->adjVertex].dist)
{
G.verNode[w->adjVertex].dist = G.verNode[temp_num].dist+w->weight;
G.verNode[w->adjVertex].path=G.verNode[temp_num].data;
}
}
w=w->nextEdgeNode;
}
}
}
int PrintPath(Graph &G,int n,int end) //打印最短路径信息,并返回路径长度
{
if(G.verNode[end].path!=NotAVertex)
{
PrintPath(G,n,G.verNode[end].path);
printf(" => ");
}
printf("%d",G.verNode[end].data);
}
int main()
{
Graph G;
CreateDAG(G,7,12); //给出图的顶点数及边数量
Dijkstra(G,7,1); //给出顶点数以及起点编号
PrintPath(G,7,6); //给出顶点数以及终点编号
}
/***测试数据****
1 2 3 4 5 6 7
1 2 2
1 4 1
2 4 3
2 5 10
3 1 4
3 6 5
4 3 2
4 5 2
4 6 8
4 7 4
5 7 6
7 6 1
输出:1 => 4 => 7 => 6
*********************/