首页 > 代码库 > 数据结构:单源最短路径--Dijkstra算法

数据结构:单源最短路径--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


若有所帮助,顶一个哦!


专栏目录:

  • 数据结构与算法
  • c指针