系列文章目录 一:背景Dijkstra算法(中文名:迪杰斯特拉算法)是由荷兰计算机科学家Edsger Wybe Dijkstra提出。该算法常用于路由算法或者作为其他图算法的一个子模块。举例来说,如果图中的顶点表示城市,而边上的权重表示城市间开车行经的距离,该算法可以用来找到两个城市之间的最短路径。 二:算法过程我们用一个例子来具体说明迪杰斯特拉算法的流程。 定义源点为0,
第1步:从源点0开始,找到与其邻接的点:1,2,3,更新 第2步:从2开始,继续更新 第3步:从3开始,继续更新 第4步:从4开始,继续更新 第5步:所有点都已找到,停止。 对于上述步骤,你可能存在以下的疑问: 若A作为源点,与其邻接的只有B,C,D三点,其 假设存在如上图的红色虚线路径,使 根据上面的证明,我们可以推断出,Dijkstra每次循环都可以确定一个顶点的最短路径,故程序需要循环n-1次。 三:完整代码using namespace std;int matrix[100][100]; // 邻接矩阵bool visited[100]; // 标记数组int dist[100]; // 源点到顶点i的最短距离int path[100]; // 记录最短路的路径int source; // 源点int vertex_num; // 顶点数int edge_num; // 边数void Dijkstra(int source){ memset(visited, 0, sizeof(visited)); // 初始化标记数组 visited[source] = true; for (int i = 0; i < vertex_num;="" i++)="" {="" dist[i]="matrix[source][i];" path[i]="source;" }="">int min_cost; // 权值最小 int min_cost_index; // 权值最小的下标 for (int i = 1; i < vertex_num;="" i++)="">// 找到源点到另外 vertex_num-1 个点的最短路径 { min_cost = INT_MAX; for (int j = 0; j < vertex_num;="" j++)="" {="">if (visited[j] == false && dist[j] < min_cost)="">// 找到权值最小 { min_cost = dist[j]; min_cost_index = j; } } visited[min_cost_index] = true; // 该点已找到,进行标记 for (int j = 0; j < vertex_num;="" j++)="">// 更新 dist 数组 { if (visited[j] == false && matrix[min_cost_index][j] != INT_MAX && // 确保两点之间有边 matrix[min_cost_index][j] + min_cost < dist[j])="" {="" dist[j]="matrix[min_cost_index][j]" +="" min_cost;="" path[j]="min_cost_index;" }="" }="">int main(){ cout <>'请输入图的顶点数(<>; cin >> vertex_num; cout <>'请输入图的边数:'; cin >> edge_num; for (int i = 0; i < vertex_num;="" i++)="">for (int j = 0; j < vertex_num;="" j++)="" matrix[i][j]="(i" !="j)" int_max="" :="">0; // 初始化 matrix 数组 cout <>'请输入边的信息:\n'; int u, v, w; for (int i = 0; i < edge_num;="" i++)="" {="">cin >> u >> v >> w; matrix[u][v] = matrix[v][u] = w; } cout <>'请输入源点(<> < vertex_num=""><>'):'; cin >> source; Dijkstra(source); for (int i = 0; i < vertex_num;="" i++)="" {="">if (i != source) { cout < source=""><>' 到 ' < i=""><>' 的最短距离是:' < dist[i]=""><>',路径是:' < i;="">int t = path[i]; while (t != source) { cout <>'--' < t;="" t="path[t];" }="">cout <>'--' < source=""><>endl; } } return 0;} 输入数据,结果为: 请输入图的顶点数(100):5请输入图的边数:7请输入边的信息:0 1 30 2 10 3 21 3 32 3 23 4 32 4 3请输入源点(5):00 到 1 的最短距离是:3,路径是:1--00 到 2 的最短距离是:1,路径是:2--00 到 3 的最短距离是:2,路径是:3--00 到 4 的最短距离是:4,路径是:4--2--0 四:时间复杂度设图的边数为m,顶点数为n。 Dijkstra算法最简单的实现方法是用一个数组来存储所有顶点的 对于边数远少于$n^2$的稀疏图来说,我们可以用邻接表来更有效的实现该算法,同时需要将一个二叉堆或者斐波纳契堆用作优先队列来查找最小的顶点。当用到二叉堆的时候,算法所需的时间为 $O((m+n)logn)$,斐波纳契堆能稍微提高一些性能,让算法运行时间达到$O(m+nlogn)$。然而,使用斐波纳契堆进行编程,常常会由于算法常数过大而导致速度没有显著提高。 关于$O((m+n)logn)$的由来,我简单的证明了下:
综上所述:总的时间复杂度为:$O(n)+O(nlogn)+O(mlogn)=O((m+n)logn)$ 最后简单说下Dijkstra优化时二叉堆的两种实现方式:
相比之下,前者的编码难度较低,因此在平时编程甚至算法竞赛中,都是首选。 五:该算法的缺陷Dijkstra算法有个巨大的缺陷,请考虑下面这幅图:
那么对于上述的“一个不存在最短路径的图”,我们该用什么方法来解决呢?请接着看本系列第二篇文章。 |
|