数据结构:单源最短路径--Dijkstra算法

Dijkstra算法

单源最短路径

给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离。指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题。

Dijkstra算法

求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法。该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点。

算法思想

带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合。假设V0是源点,则初始
S={V0}。用数组Distance表示源点V0到其余顶点的路径长度,用数组pre[i]表示最短路径序列上顶点i的前一个顶点。初始时,pre[i]都是源点的下标。接下来需重复两个步骤:

  1. 从当前Distance[i]找出最小的一个,记录其下标v=i,源点V0到顶点Vv的最短路径即已确定,把Vv加入S。
  2. 更新源点到剩余顶点的最短路径长度。更新方法是:以上一步的顶点Vv为中间点,若Distance[v]+weight(v,i)<Distance[i],则修改值:pre[i]=v;Distance[i]=Distance[v]+weight(v,i);

重复以上两个步骤,直至所有顶点的最短路径都已找到。

需要指出,Dijkstra算法求解的不仅是有向图,无向图也是可以的。下面给出一个完整的有向带权图的实例:

实例

有向带权图

Dijkstra算法的求解过程

其中,INF是infinity无穷大的意思。

代码

类定义

#include<iostream>
#include<iomanip>
#include<stack>
using namespace std;
#define MAXWEIGHT 100
#ifdef INFINITY
#undef INFINITY
#endif
#define INFINITY 1000
class Graph
{
private:
	//顶点数
	int numV;
	//边数
	int numE;
	//邻接矩阵
	int **matrix;
public:
	Graph(int numV);
	//建图
	void createGraph(int numE);
	//析构方法
	~Graph();
	//迪杰斯特拉算法
	void Dijkstra(int);
	//打印邻接矩阵
	void printAdjacentMatrix();
	//检查输入
	bool check(int, int, int);
};

类实现

//构造函数,指定顶点数目
Graph::Graph(int numV)
{
	//对输入的顶点数进行检测
	while (numV <= 0)
	{
		cout << "顶点数有误!重新输入 ";
		cin >> numV;
	}
	this->numV = numV;
	//构建邻接矩阵,并初始化
	matrix = new int*[numV];
	int i, j;
	for (i = 0; i < numV; i++)
		matrix[i] = new int[numV];
	for (i = 0; i < numV; i++)
	for (j = 0; j < numV; j++)
	{
		if (i == j)
			matrix[i][i] = 0;
		else
			matrix[i][j] = INFINITY;
	}
}
void Graph::createGraph(int numE)
{
	/*
	对输入的边数做检测
	一个numV个顶点的有向图,最多有numV*(numV - 1)条边
	*/
	while (numE < 0 || numE > numV*(numV - 1))
	{
		cout << "边数有问题!重新输入 ";
		cin >> numE;
	}
	this->numE = numE;
	int tail, head, weight, i;
	i = 0;
	cout << "输入每条边的起点(弧尾)、终点(弧头)和权值" << endl;
	while (i < numE)
	{
		cin >> tail >> head >> weight;
		while (!check(tail, head, weight))
		{
			cout << "输入的边不正确!请重新输入 " << endl;
			cin >> tail >> head >> weight;
		}
		matrix[tail][head] = weight;
		i++;
	}
}
Graph::~Graph()
{
	int i;
	for (i = 0; i < numV; i++)
		delete[] matrix[i];
	delete[]matrix;
}
/*
迪杰斯特拉算法
求指定顶点vertex到其它顶点的最短路径
不仅要得出最短路径长度,也要得到其序列
*/
void Graph::Dijkstra(int vertex)
{
	int i;
	//最短路径序列中每个顶点的直接前驱
	int *pre = new int[numV];
	for (i = 0; i < numV; i++)
		pre[i] = vertex;
	//顶点vertex到各个顶点的路径长度
	int *Distance = new int[numV];
	//初始化路径长度
	for (i = 0; i < numV; i++)
		Distance[i] = matrix[vertex][i];
	//标记各个顶点最短路径找到与否
	bool *find = new bool[numV];
	memset(find, 0, numV);
	find[vertex] = true;
	int d, v, count;
	count = 1, v = vertex;
	while (count < numV)
	{
		d = INFINITY;
		//确定一个最短距离
		for (i = 0; i < numV; i++)
		{
			if (!find[i] && Distance[i] < d)
			{
				d = Distance[i];
				v = i;
			}
		}
		find[v] = true;
		//更新剩余顶点的前驱和最短距离
		for (i = 0; i < numV; i++)
		{
			if (!find[i])
			{
				d = Distance[v] + matrix[v][i];
				if (d < Distance[i])
				{
					pre[i] = v;
					Distance[i] = d;
				}
			}
		}
		count++;
	}
	//打印最短路径序列和其长度
	stack<int> s;
	for (i = 0; i < numV; i++)
	{
		if (Distance[i] == 0);
		else if (Distance[i] == INFINITY)
			cout << "顶点 " << vertex <<" 到顶点 " << i <<" 无路径!" << endl;
		else
		{
			cout << "顶点 " << vertex << " 到顶点 " << i
				 << " 最短路径长度是 " << Distance[i]
				 << " ,其序列是...";
			v = i;
			s.push(v);
			do
			{
				v = pre[v];
				s.push(v);
			} while (v!=vertex);
			//打印最短路径序列
			while (!s.empty())
			{
				cout << setw(3) << s.top();
				s.pop();
			}
			cout << endl;
		}
	}
	cout << endl;
	delete[]find;
	delete[]pre;
	delete[]Distance;
}
//打印邻接矩阵
void Graph::printAdjacentMatrix()
{
	int i, j;
	cout.setf(ios::left);
	cout << setw(7) << " ";
	for (i = 0; i < numV; i++)
		cout << setw(7) << i;
	cout << endl;
	for (i = 0; i < numV; i++)
	{
		cout << setw(7) << i;
		for (j = 0; j < numV; j++)
			cout << setw(7) << matrix[i][j];
		cout << endl;
	}
}
bool Graph::check(int tail, int head, int weight)
{
	if (tail < 0 || tail >= numV || head < 0 || head >= numV
		|| weight <= 0 || weight >= MAXWEIGHT)
		return false;
	return true;
}

主函数

int main()
{
	cout << "******Dijkstra***by David***" << endl;
	int numV, numE;
	cout << "建图..." << endl;
	cout << "输入顶点数 ";
	cin >> numV;
	Graph graph(numV);
	cout << "输入边数 ";
	cin >> numE;
	graph.createGraph(numE);
	cout << endl << "Dijkstra..." << endl;
	for (int i = 0; i < numV; i++)
	graph.Dijkstra(i);
	system("pause");
	return 0;
}

运行

完整代码下载:Dijkstra算法

转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38360337

若有所帮助,顶一个哦!

专栏目录:

数据结构:单源最短路径--Dijkstra算法,布布扣,bubuko.com

时间: 2024-08-02 06:59:06

数据结构:单源最短路径--Dijkstra算法的相关文章

单源最短路径Dijkstra算法

1.单源最短路径 函数:返回还未被收录顶点中dist最小者 1 Vertex FindMinDist(MGraph Graph, int dist[], int collected[]) 2 { 3 /*返回未被收录顶点中dist最小者*/ 4 Vertex MinV, V; 5 int MinDist = INFINITY; 6 7 8 for (V = 0; V < Graph->Nv; ++V) 9 { 10 if (collected[V] == false && di

单源最短路径 dijkstra算法实现

本文记录一下dijkstra算法的实现,图用邻接矩阵表示,假设图为无向图,并且连通,有向图,不连通图的做法类似. 算法简述: 首先确定"单源"的源,假设是第0个顶点. 维护三个数组dist[], color[], path[],设其下标分别为0-i-n-1: dist[] 表示源点到顶点i的最短距离,在初始化时,如果源点到顶点i有路径,则初始化为路径的权重,否则初始化为INT_MAX: color[] 数组其实表示两个集合,即color[i]值为1的集合表示已经确定最短路径的点的集合,

(转)图算法单源最短路径Dijkstra算法(邻接表/邻接矩阵+优先队列STL)

一.前言 最短路径算法,顾名思义就是求解某点到某点的最短的距离.消耗.费用等等,有各种各样的描述,在地图上看,可以说是图上一个地点到达另外一个地点的最短的距离.比方说,我们把地图上的每一个城市想象成一个点,从一个城市到另一个城市的花费是不一样的.现在我们要从上海去往北京,需要考虑的是找到一条路线,使得从上海到北京的花费最小.有人可能首先会想到,飞机直达啊,这当然是时间消耗最小的方法,但是考虑到费用的高昂,这条线路甚至还不如上海到北京的高铁可取.更有甚者,假设国家开通了从上海到西藏,再从西藏到兰州

单源最短路径——Dijkstra算法学习

每次都以为自己理解了Dijkstra这个算法,但是过没多久又忘记了,这应该是第4.5次重温这个算法了. 这次是看的胡鹏的<地理信息系统>,看完之后突然意识到用数学公式表示算法流程是如此的好理解,堪称完美. 内容摘抄如下: 网络中的最短路径是一条简单路径,即是一条不与自身相交的路径,最短路径搜索的依据:若从S点到T点有一条最短路径,则该路径上的任何点到S的距离都是最短的. Dijkstra算法搜索步骤: 1.对起始点作标记S,且对所有顶点令D(X)=∞,Y=S: 2.对所有未做标记的点按以下公式

单源最短路径Dijkstra、BellmanFord、SPFA【模板】

Dijkstra算法: 将所有点分为两个集合.如果源点s到u的最短路径已经确定,点u就属于集合Va,否则属于集合Vb. 1.将源点s到图中各点的直接距离当做初始值记录为s到各点的最短距离,不能到达的记为INF.S到S距离为0. 2.在集合Vb中的点中找一个点u,使得源点s到该点u路径长度最短,将u从Vb中除去,加到V1中.这时候求出了当前S到u的最短路径. 3.把新确定的点u更新s到集合Vb中每一个点v的距离,如果s到u的距离加上u到v的直接距离小于当前s到v的距离,则表示新找到的最短路径长度比

单源最短路问题 dijkstra算法 总结

Dijkstra(迪杰斯特拉)算法,用于计算一个节点到其他所有节点的最短路径.要注意的是这个算法中路径的权值不能有负边,如果有负边的话要运用bellman ford算法. 学习了一下dijkstra算法,感觉跟最小生成树的Prim算法有点类似.感觉dijkstra也是一个贪心的策略,用集合S表示的是已经找出最小路径的点,用dis[]来表示每个点当前距离源点的最短距离.再用一个数组来存储两点之间的距离,对于没有直接相连的两点就将值赋为INF. 1.一开始的时候,集合S中只有源点. 2.选取尚未被找

单源最短路径Dijkstra和优先级算法

百度百科:迪杰斯特拉算法. 代码实现如下: import java.util.Comparator; import java.util.PriorityQueue; import java.util.Scanner; class Node { int x; int value; } public class Main { static int N,M,cnt; static final int MAX = 105; static final int INF = 1000009; static N

单源最短路径——Floyd算法

正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3). Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B.所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,

单源最短路径(dijkstra算法)php实现

做一个医学项目,其中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路如下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么(Vi...Vk)也必定是从i到k的最短路径.Dijkstra是以最短路径长度递增,逐次生成最短路径的算法.例如:对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+cost[i][j]}.假设G