目录
Dijkstra算法是一种常用的解决单源最短路径问题的贪心算法。在本篇文章中,我们将深入了解Dijkstra算法的原理、代码实现以及一些应用场景。不适用负权图,无法正确求出最短路径,但算法可执行完。
一、什么是单源最短路径?
单源最短路径问题是在一个带权重的有向图中寻找从一个特定顶点到其他顶点的最短路径。最短路径可以通过边的权重之和来度量。
二、Dijkstra算法原理
Dijkstra算法的主要思想是从源顶点开始,逐步扩展到其他顶点,找到最短路径。算法维护一个距离数组,用于记录源顶点到每个顶点的当前最短距离。每次选择未访问的顶点中距离最短的顶点,然后更新距离数组,再以新选定的顶点为中心继续扩展。
三、Dijkstra算法步骤
- 初始化距离数组,将源顶点距离设为0,与源顶点有关联的顶点距离设为其对应的边权值,在final数组中将源顶点标为true,表示源顶点已经找到到自身的最短路径。并将path数组也都初始化。
- 选择当前距离最小且未被标记的顶点作为中心顶点。
- 更新其他未访问顶点的距离,通过中心顶点计算新的距离。
- 标记中心顶点为已访问。
- 重复步骤2~4,直到所有顶点都被访问。
四、Dijkstra算法代码实现
以下是代码中创建的图:
0到2的最短路径应该是0->4->1->2 最短带权路径长度是5+3+1=9
以下是使用C++实现Dijkstra算法的示例代码:
1. 图
#define V 5 //顶点个数
struct Edge { //边结点
int vex;
int weight;
Edge* next;
};
struct Vex { //顶点结点
Edge* firstEdge;//顶点连的第一条边
};
Vex graph[V]; //图的邻接表存储,数组下标就是顶点标识
void initGraph() { //图初始化
for (int i = 0; i < V; i++) {
graph[i].firstEdge = NULL;
}
}
//添加边
void insertEdge(int source, int destination, int weight) {
if (source >= 0 && source < V && destination >= 0 && destination < V) {
Edge* newEdge = (Edge*)malloc(sizeof(Edge));
newEdge->vex = destination;
newEdge->weight = weight;
newEdge->next = graph[source].firstEdge;
graph[source].firstEdge = newEdge;
}
else {
cout << "添加失败" << endl;
}
}
2. Dijkstra
bool final[V]; //标记是否已经确认到某顶点的最短路径
int dist[V]; //最短路径长度
int path[V]; //路径上的前驱
//返回dist数组中未确定最短路径且dist最小的顶点的数组下标
int findMin() {
int Min = INT_MAX;
int min_index = -1;
for (int i = 0; i < V; i++) {
if (!final[i] && dist[i] < Min) {
Min = dist[i];
min_index = i;
}
}
return min_index;
}
void Dijkstra(int begin) {
//初始化上面三个辅助算法的数组
for (int i = 0; i < V; i++) {
final[i] = false;
dist[i] = INT_MAX;
path[i] = -1;
}
final[begin] = true;
dist[begin] = 0;
Edge* p = graph[begin].firstEdge;
while (p != NULL) {
dist[p->vex] = p->weight;
path[p->vex] = begin;
p = p->next;
}
for (int i = 0; i < V - 1; i++) {
int min_index = findMin();
final[min_index] = true;
p = graph[min_index].firstEdge;
while (p != NULL) {
int newDist = dist[min_index] + p->weight;
if (newDist < dist[p->vex]) {
dist[p->vex] = newDist;
path[p->vex] = min_index;
}
p = p->next;
}
}
}
3. 打印最短路径
void printMinRoad(vector<int> arr, int begin, int end) {
cout << "Dijkstra算法得到的由顶点" << begin << "到顶点" << end
<< "的最短路径:";
int i = end;
arr.push_back(i);
while (path[i] != begin) {
arr.push_back(path[i]);
i = path[i];
}
arr.push_back(begin);
for (int i = arr.size() - 1; i > 0; i--) {
cout << arr[i] << "->";
}
cout << arr[0] << endl;
cout << "最短带权路径长度是:" << dist[end] << endl;
}
五、完整代码
#include<iostream>
#include<vector>
using namespace std;
#define V 5 //顶点个数
struct Edge { //边结点
int vex;
int weight;
Edge* next;
};
struct Vex { //顶点结点
Edge* firstEdge;//顶点连的第一条边
};
Vex graph[V]; //图的邻接表存储,数组下标就是顶点标识
void initGraph() { //图初始化
for (int i = 0; i < V; i++) {
graph[i].firstEdge = NULL;
}
}
//添加边
void insertEdge(int source, int destination, int weight) {
if (source >= 0 && source < V && destination >= 0 && destination < V) {
Edge* newEdge = (Edge*)malloc(sizeof(Edge));
newEdge->vex = destination;
newEdge->weight = weight;
newEdge->next = graph[source].firstEdge;
graph[source].firstEdge = newEdge;
}
else {
cout << "添加失败" << endl;
}
}
bool final[V]; //标记是否已经确认到某顶点的最短路径
int dist[V]; //最短路径长度
int path[V]; //路径上的前驱
//返回dist数组中未确定最短路径且dist最小的顶点的数组下标
int findMin() {
int Min = INT_MAX;
int min_index = -1;
for (int i = 0; i < V; i++) {
if (!final[i] && dist[i] < Min) {
Min = dist[i];
min_index = i;
}
}
return min_index;
}
void Dijkstra(int begin) {
//初始化上面三个辅助算法的数组
for (int i = 0; i < V; i++) {
final[i] = false;
dist[i] = INT_MAX;
path[i] = -1;
}
final[begin] = true;
dist[begin] = 0;
Edge* p = graph[begin].firstEdge;
while (p != NULL) {
dist[p->vex] = p->weight;
path[p->vex] = begin;
p = p->next;
}
for (int i = 0; i < V - 1; i++) {
int min_index = findMin();
final[min_index] = true;
p = graph[min_index].firstEdge;
while (p != NULL) {
int newDist = dist[min_index] + p->weight;
if (newDist < dist[p->vex]) {
dist[p->vex] = newDist;
path[p->vex] = min_index;
}
p = p->next;
}
}
}
void printMinRoad(vector<int> arr, int begin, int end) {
cout << "Dijkstra算法得到的由顶点" << begin << "到顶点" << end
<< "的最短路径:";
int i = end;
arr.push_back(i);
while (path[i] != begin) {
arr.push_back(path[i]);
i = path[i];
}
arr.push_back(begin);
for (int i = arr.size() - 1; i > 0; i--) {
cout << arr[i] << "->";
}
cout << arr[0] << endl;
cout << "最短带权路径长度是:" << dist[end] << endl;
}
int main() {
initGraph(); //初始化图
//添加边
insertEdge(0, 1, 10);
insertEdge(0, 4, 5);
insertEdge(1, 4, 2);
insertEdge(4, 1, 3);
insertEdge(1, 2, 1);
insertEdge(4, 2, 9);
insertEdge(4, 3, 2);
insertEdge(2, 3, 4);
insertEdge(3, 2, 6);
insertEdge(3, 0, 7);
//Dijkstra算法求顶点0到其他顶点的最短路径
Dijkstra(0);
//打印
vector<int> arr;
printMinRoad(arr, 0, 2);
return 0;
}