最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。
Dijkstra算法是很有代表性的最短路算法,在很多专业
课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。
其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。

主题好好理解上图!
以下是具体的实现(C/C++):
* About: 有向图的Dijkstra算法实现
***************************************/
#include <iostream>
using namespace std;
const int maxnum = 100;
const int maxint = 999999;
void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum])
{
bool s[maxnum]; // 判断是否已存入该点到S集合中
for(int i=1; i<=n; ++i)
{
dist[i] = c[v][i];
s[i] = 0; // 初始都未用过该点
if(dist[i] == maxint)
prev[i] = 0;
else
prev[i] = v;
}
dist[v] = 0;
s[v] = 1;
// 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中
// 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度
for(int i=2; i<=n; ++i)
{
int tmp = maxint;
int u = v;
// 找出当前未使用的点j的dist[j]最小值
for(int j=1; j<=n; ++j)
if((!s[j]) && dist[j]<tmp)
{
u = j; // u保存当前邻接点中距离最小的点的号码
tmp = dist[j];
}
s[u] = 1; // 表示u点已存入S集合中
// 更新dist
for(int j=1; j<=n; ++j)
if((!s[j]) && c[u][j]<maxint)
{
int newdist = dist[u] + c[u][j];
if(newdist < dist[j])
{
dist[j] = newdist;
prev[j] = u;
}
}
}
}
void searchPath(int *prev,int v, int u)
{
int que[maxnum];
int tot = 1;
que[tot] = u;
tot++;
int tmp = prev[u];
while(tmp != v)
{
que[tot] = tmp;
tot++;
tmp = prev[tmp];
}
que[tot] = v;
for(int i=tot; i>=1; --i)
if(i != 1)
cout << que[i] << " -> ";
else
cout << que[i] << endl;
}
int main()
{
freopen("input.txt", "r", stdin);
// 各数组都从下标1开始
int dist[maxnum]; // 表示当前点到源点的最短路径长度
int prev[maxnum]; // 记录当前点的前一个结点
int c[maxnum][maxnum]; // 记录图的两点间路径长度
int n, line; // 图的结点数和路径数
// 输入结点数
cin >> n;
// 输入路径数
cin >> line;
int p, q, len; // 输入p, q两点及其路径长度
// 初始化c[][]为maxint
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
c[i][j] = maxint;
for(int i=1; i<=line; ++i)
{
cin >> p >> q >> len;
if(len < c[p][q]) // 有重边
{
c[p][q] = len; // p指向q
c[q][p] = len; // q指向p,这样表示无向图
}
}
for(int i=1; i<=n; ++i)
dist[i] = maxint;
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=n; ++j)
printf("%8d", c[i][j]);
printf("\n");
}
Dijkstra(n, 1, dist, prev, c);
// 最短路径长度
cout << "源点到最后一个顶点的最短路径长度: " << dist[n] << endl;
// 路径
cout << "源点到最后一个顶点的路径为: ";
searchPath(prev, 1, n);
}
方法二:
#include <iostream>
using namespace std;
#define MX 1000 //最大值 无穷
#define NUM 6 //最大顶点个数
typedef int adjmatrix[NUM][NUM];
typedef int path[NUM][NUM];
typedef int Dist[NUM];//v0到vi的的距离
int ps[NUM]={0}; //最短路径值
int final[NUM];//final[i]=1代表已经求出v0到vi的最短路径
const int vexs[NUM] = {0,1,2,3,4,5};
int arcs[NUM][NUM] = {
{MX,MX,10,MX,30,100},
{MX,MX,5,MX,MX,MX},
{MX,MX,MX,50,MX,MX},
{MX,MX,MX,MX,MX,10},
{MX,MX,MX,20,MX,60},
{MX,MX,MX,MX,MX,MX}
};
//=====================================================
void ShorttestPath_DIJ(adjmatrix arc,int v,path &p,Dist &d)
{
//用迪杰斯特拉算法求解v0到其余个点的最短路径,p[v][w]代表v0到v经过w
int w=0;
for(int nv=0;nv<NUM;nv++)
{
final[nv]=0;
d[nv]=arc[v][nv];
ps[nv]=d[nv];
for(int w=0;w<NUM;w++) p[nv][w]=false;
if(d[nv]<MX)
{
p[nv][v]=1;
p[nv][nv]=1;
}
}//for
d[v]=0;
final[v]=1;
int min=MX;
//开始主循环
for(int i=1;i<NUM;++i)
{
min=MX;
for(w=0;w<NUM;++w)
{
if(final[w]==0)
{
if(d[w]<min)
{
v=w;
min=d[w];
}
}
}//for
final[v]=1;
for(w=0;w<NUM;w++)
{
if(final[w]==0&&(min+arc[v][w])<d[w])
{
d[w]=min+arc[v][w];
ps[w]=ps[v]+arc[v][w];
for(int pos=0;pos<NUM;pos++)
{
p[w][pos]=p[v][pos];//借助最短路径到达w点
}
p[w][w]=1;//经过w点
}//endif
}//for
}//for
}
void DIJ_Print(int start,path &P)
{
for(int i=1;i<NUM;i++)
{
int u=i;
if(final[i]==1)
{
cout<<"距离:"<<ps[i]<<"\t";
cout<<start;
int m=start;
for(int j=1;j<NUM;j++)
{
if( P[u][j]==1)
{
if(arcs[m][j]>0 && arcs[m][j]<MX)
{
cout<<"->"<<j;
m=j;
j=1;
}
}
}
cout<<endl;
}//endif
}//endfor
}
void ShortestPath()
{
int start = 5;
Dist D; //D[i]表示从start到i的最短距离;
path P; //P[i,j]表示从start到i的最短路径上会经过j
int t[NUM]={0};
int n=0;
cout << "输入出发点 (0~5 空格分隔)" << endl;
cin >> start;
if(start>=0 && start<6)
{
//调用迪杰斯特拉算法
ShorttestPath_DIJ(arcs,start,P,D);
cout <<"从"<< start;
cout << "到其他各点的最短路径长度 :"<<endl ;
//调用迪杰斯特拉打印算法
DIJ_Print(start,P);
}//endif
else
cout << "没有这个地方!" << endl;
}
//============== mian文件 =============
int main()
{
char choose=0;
cout << "************************" << endl;
cout << " a.x到其他点的最短路径 " << endl;
cout << " b.退出 " << endl;
cout << " 版本号v1.8 " << endl;
cout << "************************" << endl;
cin >> choose;
while( choose!='b' )
{
if( choose=='a' )
{
ShortestPath();
cout << "===========================" << endl;
cout << " a.x到y的最短路径 b.退出 " << endl;
cout << "===========================" << endl;
}
else if(choose!='a'||choose!='b') cout << "输入错误,请重新输入:";
cin >> choose;
}
return 0;
}

浙公网安备 33010602011771号