算法导论-第24章- 单源最短路径 - 24.3 Dijkstra 算法

1、综述

Dijkstra(迪杰斯特拉)算法是典型的最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。

初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。

2、Dijkstra 算法

《算法导论-第24章- 单源最短路径 - 24.3 Dijkstra 算法》

3、代码

#include <iostream>   
#include <queue>
using namespace std;  

#define N 5   //点
#define M 10  //边
//边结点结构   
struct Edge  
{  
	int start;//有向图的起点   
	int end;//有向图的终点   
	int value;
}; 
//顶点属性
struct Vertex
{
	int d;//与的源点的距离
	int p;//在最短路径树中的父结点
}; 
Vertex V[N+1];//顶点集合
Edge E[M+1];//边集合
bool visited[N+1] ;//这里用bool表示边是否被加入到S中,如果为true,则表示已经加入S中
//初始化
void Initialize_Single_Source(int s)
{
	int i;
	for(i = 1; i <= N; i++)
	{
		V[i].d = 0x7fffffff;//初始距离为无穷大
		V[i].p = -1;//初始前驱点为-1
		visited[i] = false;
	}
	V[s].d = 0;
}
//对边uv松弛,w为边uv的权重
void Relax(int u, int v, int w)
{
	if(V[u].d != 0x7fffffff && V[v].d > V[u].d + w)
	{
		V[v].d = V[u].d + w;
		V[v].p = u;
	}
}
//输出每个顶点的属性
void Print()
{
	int i;
	for(i = 1; i <= N; i++)
		cout<<V[i].d<<' ';
	cout<<endl;
	for(i = 1; i <= N; i++)
		cout<<V[i].p<<' ';
	cout<<endl;
}
////Bellman_Ford算法
//bool Bellman_Ford(int s)
//{
//	int i, j;
//	//初始化
//	Initialize_Single_Source(s);
//	//对图的边进行|V|-1遍操作
//	for (i = 1; i < N; i++)
//	{
//		cout<<"第"<<i<<"轮:"<<endl;
//		//依次对每条边进行松弛操作
//		for(j = 1; j <= M; j++)
//		{
//			Relax(E[j].start, E[j].end, E[j].value);
//		}
//		//输出每一轮松弛后的结果
//		Print();
//	}
//	//对负权回路进行检查
//	for(j = 1; j <= M; j++)
//	{
//		if(V[E[j].end].d > V[E[j].start].d + E[j].value)
//			return false;
//	}
//	return true;
//}

//Dijkstra算法
void Dijkstra(int s)
{
	//初始化
	Initialize_Single_Source(s);
	//使用for循环代替队列,因为知道需要遍历的次数为N
	for(int j = 1 ; j <=N ; j++)
	{
		int d = 0x7fffffff;
		int u;
		//找出当前未加入S中的点中距离源点s最近的点
		for(int i=1 ; i <= N  ; i++)
		{
			if(visited[i] == false && V[i].d < d)
			{
				d = V[i].d;
				u = i;
			}
		}
		visited[u] = true;//把找出来的点放入S中
		cout<<"第"<<j<<"轮:"<<endl;
		for(int j = 1 ; j <= M ; j++) 
		{
			if(E[j].start == u)
				Relax(E[j].start,E[j].end,E[j].value);//对以当前点u为起点的边松弛
		}
		Print();
	}
}

int main()
{
	int i;
	//输入边
	int edge[11][3] ={{0,0,0},{1,2,10},{1,5,5},{2,3,1},{2,5,2},{3,4,4},{4,1,7},{4,3,6},{5,2,3},{5,3,9},{5,4,2}};
	for(i = 1; i <= M; i++)
	{
		E[i].start = edge[i][0];
		E[i].end = edge[i][1];
		E[i].value = edge[i][2];
	}
	//Bellman_Ford算法
	//Bellman_Ford(1);
	Dijkstra(1);
	return 0;
}

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/u012243115/article/details/41841927
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞