Dijkstra算法
单源最短路径
给定一带权图,图中每条边的权值是非负的,代表着两顶点之间的距离。指定图中的一顶点为源点,找出源点到其它顶点的最短路径和其长度的问题,即是单源最短路径问题。
Dijkstra算法
求解单源最短路径问题的常用方法是Dijkstra(迪杰斯特拉)算法。该算法使用的是贪心策略:每次都找出剩余顶点中与源点距离最近的一个顶点。
算法思想
带权图G=<V,E>,令S为已确定了最短路径顶点的集合,则可用V-S表示剩余未确定最短路径顶点的集合。假设V0是源点,则初始 S={V0}。用数组Distance表示源点V0到其余顶点的路径长度,用数组pre[i]表示最短路径序列上顶点i的前一个顶点。初始时,pre[i]都是源点的下标。接下来需重复两个步骤:
- 从当前Distance[i]找出最小的一个,记录其下标v=i,源点V0到顶点Vv的最短路径即已确定,把Vv加入S。
- 更新源点到剩余顶点的最短路径长度。更新方法是:以上一步的顶点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);
- };
#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;
- }
//构造函数,指定顶点数目
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;
- }
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
若有所帮助,顶一个哦!
专栏目录: