Dijkstra算法模拟讲解

 dijkstra算法,是一个求单源最短路径算法

其算法的特点为:       

         层层逼进,有点类似宽度搜索的感觉

         其需要的数据结构为:
                 int map[N][N] 所有点之间的权表
                 int dis[N]  所有点到源点的最短距离
                 int prev[N]   存储每个点的前一个经过的点,用于输出路径
                 int used[N]   用于存储已经求出最短路径的点
         则总的点减去used中的点,为还没有找出最短路径的点
         初始化时:map为实际存储的权,如果某一边没有,则设置为无穷大INF,自身设置0
         dis为源点到该点的距离,如果没有,也设置为无穷大INF
         prev,如果与源点相邻,则设置为源点,否则为0
         used 除了源点外,其余全为0
         第一次比较源点到其相邻的点,找出最短距离的点k,将其加入used[k] = 1;
         比较与k相邻的点j到源点的距离,如果比(dis[k] + map[k][j])源点到k + k
         到j点的距离大,那么更新dis[j] = dis[k] + map[k][j],并记录prev[j] = k,
         表示j的前一个经过的点为k,再重复寻找其余的点到源点的最短距离,再把找到
         的点加入used中,直到全部节点都加入used中时,最短路径已完毕。


具体实现如下:

 

/*
	Filename:dijkstra.cpp
	Author: xiaobing
	E-mail: xiaobingzhang29@gmail.com
	Date: 2013-08-30
*/
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<string.h>
#include<stack>
#define N 50
#define M 50
#define INF 0xfffffff 
using namespace std;
/*
 *dijkstra算法,是一个求单源最短路径算法
 其算法的特点为:
	层层逼进,有点类似宽度搜索的感觉
	其需要的数据结构为:
		int map[N][N] 所有点之间的权表
		int dis[N]	  所有点到源点的最短距离
		int prev[N]   存储每个点的前一个经过的点,用于输出路径
		int used[N]   用于存储已经求出最短路径的点
		则总的点减去used中的点,为还没有找出最短路径的点
	初始化时:map为实际存储的权,如果某一边没有,则设置为无穷大INF,自身设置0
			  dis为源点到该点的距离,如果没有,也设置为无穷大INF
			  prev,如果与源点相邻,则设置为源点,否则为0
			  used 除了源点外,其余全为0
		第一次比较源点到其相邻的点,找出最短距离的点k,将其加入used[k] = 1;
		比较与k相邻的点j到源点的距离,如果比(dis[k] + map[k][j])源点到k + k
		到j点的距离大,那么更新dis[j] = dis[k] + map[k][j],并记录prev[j] = k,
		表示j的前一个经过的点为k,再重复寻找其余的点到源点的最短距离,再把找到
		的点加入used中,直到全部节点都加入used中时,最短路径已完毕。

*/

/*
 *dijkstra算法
 *@node		总共的节点数
 *@from     源点
 *@map		点与点之间的权表
 *@dis		源点到该点的最短距离
 *@prev		存储当前的前一个经过的点
 */
void dijkstra(int node, int from, int map[][N], int dis[], int prev []){
	int i,j,k;
	//初始化为所有节点均为求出最短路径
	int used[N] = {0};
	//第一个点已使用,并且已求出
	used[from] = 1;
	//初始化源点到其他点的距离
	for(i = 1;i <= node;i++){
		dis[i] = map[from][i];
		//如果源点到该点不可达,那么其前经过的点为0
		//相反为from
		if(dis[i] == INF || dis[i] == 0){
			prev[i] = 0;
		} else {
			prev[i] = from;
		}
	}
	int min;
	//遍历node次,寻找每个点到源点的最短距离
	for(i = 1;i <= node;i++){
		//初始化为无穷大
		min = INF;
		//遍历其他没有加入used中的点,并找出最短路径的点k
		for(j = 1;j <= node;j++){
			if(!used[j] && dis[j] < min){
				min = dis[j];
				k = j;
			}
		}
		
		//将该点加入used中,表示已求出从源点到该点的最短路径
		used[k] = 1;

		//更新与k相邻的点到源点的距离
		//如果经过k点到j的距离更短,那么更新dis[j](从源点到j的距离)
		//为源点到k的距离 + k到j的距离,即:dis[k] + map[k][j]
		//并更新j的前一个经过的点为k
		for(j = 1;j <= node;j++){
			if(dis[j] > dis[k] + map[k][j]){
				dis[j] = dis[k] + map[k][j];
				prev[j] = k; 
			}
		}
	}
}

//打印二维表
void print(int table[][M], int row, int col){
	int i,j;
	for(i = 0;i < row;i++){
		for(j = 0;j < col;j++){
			cout<<table[i][j]<<" ";
		}

		cout<<endl;
	}
}

//打印路径,由于是一个点储存才是前置节点,可以用栈来存储
//from	为源点
//to	为目的点
//prev	为前置节点路径
void printPath(int from, int to, int prev[]){
	stack<int> path;
	//把目标点入栈
	path.push(to);
	//一直找到源点,当然,也可能没有源点,但那个点的前置节点为0
	//这里需要防止环路,所以可以用距离来判断,当相等时,就退出了
	while(prev[to] != 0){
		path.push(prev[to]);
		to = prev[to];

	}
	//如果栈顶节点不是源点,说明从源点到目标点不可达
	if(path.top() != from){
		cout<<"没有路径"<<endl;
		return ;
	}

	cout<<"路径为: ";
	
	int flag = 0;	//第一次不输出指标
	while(!path.empty()){
		if(flag)
			cout<<"->";
		flag = 1;
		cout<<path.top();
		path.pop();
	}
	cout<<endl;
}
int main(){
	int i, j;
	//定义一个权表
	int map[N][M];
	//初始化map为INF
	for(i = 0;i < N;i++){
		for(j = 0;j < M;j++){
			map[i][j] = INF;
			if(i == j){
				map[i][j] = 0;
			}
		}
	}
	//print(map, N, M);
	//node 节点数
	//line 边数
	//start 源点
	int node,line,start;
	cin>>node;
	cin>>line;
	cin>>start;

	int from, to,len;
	//接受数据并初始化map
	for(i = 0;i < line;i++){
		cin>>from>>to>>len;
		map[from][to] = len;
	}
	cout<<endl;
	cout<<"原始数据为:"<<endl;
	print(map, node + 1, node + 1);
	cout<<endl;

	//初始时所有的最短路径为0,前置节点为0
	int dis[N] = {0};
	int prev[N] = {0};
	dijkstra(node, start, map, dis, prev);
	for(i = 0;i <= node;i++){
		cout<<prev[i]<<" ";
	}
	cout<<endl;
	
	cout<<"从节点"<<start<<"到其他节点的最短距离为:"<<endl;

	for(i = 1;i <= node;i++){
		cout<<start<<"--"<<i<<"距离为:"<<dis[i]<<endl;
		printPath(start, i, prev);
	}
    return 0;
}

 

测试数据为:
5
7
1
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60

原始数据为:
0 268435455 268435455 268435455 268435455 268435455 
268435455 0 10 268435455 30 100 
268435455 268435455 0 50 268435455 268435455 
268435455 268435455 268435455 0 268435455 10 
268435455 268435455 268435455 20 0 60 
268435455 268435455 268435455 268435455 268435455 0 

0 0 1 4 1 3 
从节点1到其他节点的最短距离为:
1--1距离为:0
路径为: 1
1--2距离为:10
路径为: 1->2
1--3距离为:50
路径为: 1->4->3
1--4距离为:30
路径为: 1->4
1--5距离为:60
路径为: 1->4->3->5


=====================================

5
7
5
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60

原始数据为:
0 268435455 268435455 268435455 268435455 268435455 
268435455 0 10 268435455 30 100 
268435455 268435455 0 50 268435455 268435455 
268435455 268435455 268435455 0 268435455 10 
268435455 268435455 268435455 20 0 60 
268435455 268435455 268435455 268435455 268435455 0 

0 0 0 0 0 0 
从节点5到其他节点的最短距离为:
5--1距离为:268435455
没有路径
5--2距离为:268435455
没有路径
5--3距离为:268435455
没有路径
5--4距离为:268435455
没有路径
5--5距离为:0
路径为: 5
=====================================
原始数据为:
0 268435455 268435455 268435455 268435455 268435455 
268435455 0 40 10 268435455 268435455 
268435455 268435455 0 10 30 50 
268435455 268435455 80 0 20 40 
268435455 268435455 268435455 268435455 0 10 
268435455 268435455 268435455 268435455 268435455 0 

0 0 0 2 2 4 
从节点2到其他节点的最短距离为:
2--1距离为:268435455
没有路径
2--2距离为:0
路径为: 2
2--3距离为:10
路径为: 2->3
2--4距离为:30
路径为: 2->4
2--5距离为:40
路径为: 2->4->5


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值