当前位置: 首页 > news >正文

图算法详解:最短路径、拓扑排序与关键路径

图是数据结构中的重要概念,在实际应用中有着广泛的用途。本文将深入探讨图的三个核心算法:最短路径算法、拓扑排序和关键路径算法,帮助读者理解其原理、实现和应用场景。

文章目录

  • 一、最短路径算法
    • 1.1 Dijkstra算法 - 单源最短路径
    • 1.2 Floyd算法 - 全源最短路径
  • 二、拓扑排序算法
    • 2.1 基于邻接矩阵的实现
    • 2.2 基于邻接表的改进实现
  • 三、关键路径算法
    • 3.1 算法实现
  • 四、算法应用与总结
    • 4.1 应用场景对比
    • 4.2 算法选择建议
    • 4.3 性能优化提示

一、最短路径算法

最短路径问题是图论中的经典问题,旨在寻找图中两点间路径权值和最小的路径。根据求解范围的不同,可以分为单源最短路径和全源最短路径问题。

1.1 Dijkstra算法 - 单源最短路径

Dijkstra算法用于解决从某个源点到图中其他所有顶点的最短路径问题,适用于非负权值的有向图或无向图。

算法核心思想:

  • 维护一个距离数组D[],记录源点到各顶点的最短距离
  • 使用贪心策略,每次选择当前距离最小且未访问的顶点
  • 通过该顶点更新其邻接顶点的距离值
float D[n];  // 存放各条最短路径的长度
int p[n], s[n];  // p[]记录前驱节点,s[]标记是否已访问void Dijkstra(int v, float dist[][n]) {int i, j, k, v1, min, max = 10000;v1 = v;// 初始化for(i = 0; i < n; i++) {D[i] = dist[v1][i];if(D[i] != max)p[i] = v1 + 1;else p[i] = 0;s[i] = 0;}s[v1] = 1;  // 源点标记为已访问// 主循环:找到n-1个最短路径for(i = 0; i < n-1; i++) {min = max + 1;// 找到距离最小的未访问顶点for(j = 0; j < n; j++) {if((!s[j]) && (D[j] <= min)) {min = D[j];k = j;}}s[k] = 1;  // 标记为已访问// 更新通过顶点k可达的其他顶点的距离for(j = 0; j < n; j++) {if((!s[j]) && D[j] > D[k] + dist[k][j]) {D[j] = D[k] + dist[k][j];p[j] = k + 1;}}}
}

复杂度分析:

  • 时间复杂度:O(n²)
  • 空间复杂度:O(n)

1.2 Floyd算法 - 全源最短路径

Floyd算法能够求出图中任意两个顶点之间的最短路径,采用动态规划的思想实现。

算法核心思想:

  • 通过一个中间顶点k,判断经由k的路径是否比直接路径更短
  • 逐个尝试每个顶点作为中间节点,更新所有顶点对之间的最短距离
int path[n][n];  // 路径矩阵,记录路径信息void Floyd(float A[][n], float dist[][n]) {int i, j, k, max = 1000;// 初始化路径长度矩阵和路径矩阵for(i = 0; i < n; i++) {for(j = 0; j < n; j++) {if(dist[i][j] != max)path[i][j] = i + 1;elsepath[i][j] = 0;A[i][j] = dist[i][j];}}// 三重循环:k为中间顶点for(k = 0; k < n; k++) {for(i = 0; i < n; i++) {for(j = 0; j < n; j++) {if(A[i][j] > A[i][k] + A[k][j]) {A[i][j] = A[i][k] + A[k][j];  // 更新距离path[i][j] = path[k][j];      // 更新路径}}}}
}

复杂度分析:

  • 时间复杂度:O(n³)
  • 空间复杂度:O(n²)

二、拓扑排序算法

拓扑排序是针对**有向无环图(DAG)**的一种排序方法,用于确定顶点的一个线性序列,使得对于图中每条有向边(u,v),顶点u都出现在顶点v之前。

应用场景:

  • 课程安排(先修课程关系)
  • 项目调度
  • 编译器中的依赖分析

2.1 基于邻接矩阵的实现

void TopoSortA(Graph *g, int n) {int i, j, k, t, v, D[n];for(i = 0; i < n; i++)D[i] = 0;  // 标记数组初始化v = 1;  // 序号计数器for(k = 0; k < n; k++) {// 寻找入度为0的顶点(全0列)for(j = 0; j < n; j++) {if(D[j] == 0) {t = 1;for(i = 0; i < n; i++) {if(g->arcs[i][j] == 1) {t = 0;break;}}if(t == 1) {m = j;break;}}}if(j != n) {D[m] = v;  // 分配新序号printf("%d\t", g->vex[m]);for(i = 0; i < n; i++)g->arcs[m][i] = 0;  // 删除该顶点的所有出边v++;} else break;}if(v < n)printf("\n图中存在环路\n");
}

2.2 基于邻接表的改进实现

typedef struct {int adjvex;      // 邻接点struct node *next;
} EdgeNode;typedef struct {int vertex;      // 顶点信息int id;          // 入度EdgeNode *link;  // 边表头指针
} VexNode;void TopoSortB(VexNode ga[]) {int i, j, k, m = 0, top = -1;EdgeNode *p;// 建立入度为0的顶点栈for(i = 0; i < n; i++) {if(ga[i].id == 0) {ga[i].id = top;top = i;}}while(top != -1) {j = top;top = ga[top].id;  // 出栈printf("%d\t", ga[j].vertex);m++;p = ga[j].link;while(p) {k = p->adjvex;ga[k].id--;  // 入度减1if(ga[k].id == 0) {ga[k].id = top;top = k;  // 新的零入度顶点入栈}p = p->next;}}if(m < n)printf("\n图中存在环路\n");
}

复杂度对比:

  • 邻接矩阵实现:O(n³)
  • 邻接表实现:O(n + e)

三、关键路径算法

关键路径算法用于解决**AOE网络(Activity On Edge)**中的项目调度问题,寻找决定整个项目完成时间的关键活动序列。

核心概念:

  • 事件:用顶点表示,代表项目中的某个状态
  • 活动:用边表示,代表需要消耗时间的任务
  • 关键路径:从起点到终点的最长路径
  • 关键活动:位于关键路径上的活动

3.1 算法实现

typedef struct node {int adjvex;      // 邻接点int dur;         // 活动持续时间struct node *next;
} EdgeNode;typedef struct {char vertex;     // 顶点信息int id;          // 入度EdgeNode *link;  // 边表头指针
} VexNode;int CriticalPath(VexNode digl[]) {int i, j, k, m;int front = -1, rear = -1;  // 队列指针int tpord[n], ve[n], vl[n];int l[maxsize], e[maxsize];EdgeNode *p;// 初始化事件最早发生时间for(i = 0; i < n; i++)ve[i] = 0;// 拓扑排序,计算ve[]for(i = 0; i < n; i++) {if(digl[i].id == 0)tpord[++rear] = i;}m = 0;while(front != rear) {front++;j = tpord[front];m++;p = digl[j].link;while(p) {k = p->adjvex;digl[k].id--;// 更新最早发生时间if(ve[j] + p->dur > ve[k])ve[k] = ve[j] + p->dur;if(digl[k].id == 0)tpord[++rear] = k;p = p->next;}}if(m < n) {printf("AOE网络中存在环路\n");return 0;}// 初始化事件最迟发生时间for(i = 0; i < n; i++)vl[i] = ve[n-1];// 按逆拓扑序列计算vl[]for(i = n-2; i >= 0; i--) {j = tpord[i];p = digl[j].link;while(p) {k = p->adjvex;if((vl[k] - p->dur) < vl[j])vl[j] = vl[k] - p->dur;p = p->next;}}// 计算活动的最早开始时间e[]和最迟开始时间l[]i = 0;for(j = 0; j < n; j++) {p = digl[j].link;while(p) {k = p->adjvex;e[++i] = ve[j];l[i] = vl[k] - p->dur;printf("活动<%d,%d> e=%d l=%d 松弛时间=%d\t", digl[j].vertex, digl[k].vertex, e[i], l[i], l[i] - e[i]);if(l[i] == e[i])printf("关键活动");printf("\n");p = p->next;}}return 1;
}

算法步骤:

  1. 通过拓扑排序计算事件的最早发生时间ve[]
  2. 按逆拓扑序列计算事件的最迟发生时间vl[]
  3. 计算每个活动的最早开始时间e[]和最迟开始时间l[]
  4. 找出松弛时间为0的活动(e[i] = l[i]),即关键活动

复杂度分析:

  • 时间复杂度:O(n + e)
  • 空间复杂度:O(n + e)

四、算法应用与总结

4.1 应用场景对比

算法适用场景典型应用
Dijkstra单源最短路径,非负权值GPS导航,网络路由
Floyd全源最短路径,允许负权值距离矩阵计算,传递闭包
拓扑排序有向无环图排序课程安排,依赖分析
关键路径项目调度优化工程管理,资源分配

4.2 算法选择建议

  • 图规模较小且需要全源最短路径:选择Floyd算法
  • 图规模较大且只需单源最短路径:选择Dijkstra算法
  • 存在负权边但无负权环:使用Bellman-Ford算法(Floyd的变种)
  • 需要判断依赖关系或检测环路:使用拓扑排序
  • 项目管理和时间优化:使用关键路径算法

4.3 性能优化提示

  1. Dijkstra算法优化:使用优先队列(堆)可将时间复杂度降至O((n+e)logn)
  2. 拓扑排序优化:邻接表存储比邻接矩阵更高效
  3. 关键路径优化:可以结合并行计算技术处理大规模项目网络

这三个算法构成了图论算法的重要基础,掌握它们不仅有助于理解图的性质,更能为解决实际问题提供有力工具。在实际应用中,需要根据具体问题的特点选择合适的算法,并考虑数据规模和性能要求进行相应的优化。

http://www.dtcms.com/a/354521.html

相关文章:

  • 使用 httpsok 工具全面排查网站安全配置
  • Nginx + Certbot配置 HTTPS / SSL 证书(简化版已测试)
  • Android稳定性问题的常见原因是什么
  • JSP程序设计之JSP指令
  • react+vite+ts 组件模板
  • CVPR2025丨VL2Lite:如何将巨型VLM的“知识”精炼后灌入轻量网络?这项蒸馏技术实现了任务专用的极致压缩
  • 传统星型拓扑结构的5G,WiFi无线通信网络与替代拓扑结构自组网
  • BGP路由协议(一):基本概念
  • UE的SimpleUDPTCPSocket插件使用
  • 百度地图+vue+flask+爬虫 推荐算法旅游大数据可视化系统Echarts mysql数据库 带沙箱支付+图像识别技术
  • 【数字黑洞2178】2022-10-28
  • Linux学习-TCP并发服务器构建(epoll)
  • 【C++】C++11的右值引用和移动语义
  • Unity游戏打包——iOS打包基础、上传
  • 使用Docker部署ZLMediaKit流媒体服务器实现gb/t28181协议的设备
  • Day30 多线程编程 同步与互斥 任务队列调度
  • ArcGIS学习-12 实战-综合案例
  • Unity游戏打包——iOS打包pod的重装和使用
  • Flutter:ios打包ipa,证书申请,Xcode打包,完整流程
  • Intern-S1-mini模型结构
  • SpringBoot系列之实现高效批量写入数据
  • 专项智能练习(图形图像基础)
  • 文本处理与模型对比:BERT, Prompt, Regex, TF-IDF
  • 高精度惯性导航IMU价格与供应商
  • [sys-BlueChi] docs | BluechiCtl命令行工具
  • 【C#/Cpp】CLR项目搭建的内联和托管两选项
  • IPv4和IPv6的主要区别,以及常见的过渡策略有哪些
  • OpenCV计算机视觉实战(22)——图像拼接详解
  • 机器视觉学习-day07-图像镜像旋转
  • 【开题答辩全过程】以 基于Spring Boot农产品运输服务平台为例,包含答辩的问题和答案