news 2026/2/2 22:48:52

数据结构:有向图

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据结构:有向图

一、有向图的定义

有向图是的重要类型,由顶点集合有向边集合组成,其中每条边都有明确的方向,仅能从一个顶点指向另一个顶点。若存在一条从顶点u指向顶点v的边,可表示为<u, v>,该边仅允许从uv的通行,反之不成立。

资料:https://pan.quark.cn/s/43d906ddfa1bhttps://pan.quark.cn/s/90ad8fba8347https://pan.quark.cn/s/d9d72152d3cf

有向图可形式化表示为G=(V, E),其中:

  • V是顶点的非空有限集合;
  • E是有向边的有限集合,每条边关联V中两个有序顶点(允许存在自环边,即<u, u>形式的边)。

二、有向图的核心概念

1. 顶点的度

有向图中顶点的度分为入度出度

  • 入度:记为indeg(v),指以顶点v为终点的有向边数量;
  • 出度:记为outdeg(v),指以顶点v为起点的有向边数量;
  • 顶点的总度数为入度与出度之和,且有向图所有顶点的入度之和等于出度之和,均等于边数|E|

2. 路径与环

  • 有向路径:从顶点uv的顶点序列v₀=u, v₁, v₂, ..., vₖ=v,其中每个相邻顶点对<vᵢ, vᵢ₊₁>都存在有向边,路径长度为边的数量;
  • 简单路径:路径中所有顶点互不重复的有向路径;
  • 有向环:起点和终点为同一顶点、长度≥1且顶点不重复(除起点终点)的有向路径,例如<A,B>,<B,C>,<C,A>构成一个有向环;
  • 有向无环图(DAG):不存在有向环的有向图,是拓扑排序的核心应用对象。

3. 连通性

有向图的连通性比无向图更复杂,主要分为两种:

  • 强连通:若对于图中任意两个顶点uv,既存在从uv的有向路径,也存在从vu的有向路径,则称该有向图为强连通图
  • 强连通分量:非强连通有向图中,每个最大的强连通子图称为强连通分量;
  • 弱连通:若忽略边的方向后,有向图变为连通的无向图,则称该有向图为弱连通图。

4. 完全有向图

若对于有向图中任意两个不同顶点uv,同时存在<u, v><v, u>两条有向边,则称为完全有向图。包含n个顶点的完全有向图,边数为n(n-1)

三、有向图的存储方式

1. 邻接矩阵

n×n的二维数组adj存储(n为顶点数),其中adj[i][j]表示是否存在从顶点i指向j的有向边:

  • adj[i][j]=1(或边的权重),表示存在有向边<i,j>
  • adj[i][j]=0(或无穷大),表示不存在该有向边;
  • 有向图的邻接矩阵非对称,即adj[i][j]adj[j][i]无必然相等关系。

优缺点

  • 优点:查询两顶点间是否存在指定方向边的时间复杂度为O(1),实现简单;
  • 缺点:空间复杂度为O(n²),稀疏图会造成大量空间浪费。

2. 邻接表

为每个顶点维护一个链表(或数组),存储该顶点指向的所有邻接顶点。整体为数组adj,其中adj[v]是顶点v的出边邻接顶点列表。

若需快速查询入边,可额外维护逆邻接表,存储以每个顶点为终点的所有起点。

优缺点

  • 优点:空间复杂度为O(|V|+|E|),适合稀疏图,遍历顶点出边效率高;
  • 缺点:查询从uv是否存在有向边的时间复杂度为O(outdeg(u))

四、有向图的核心算法

1. 深度优先搜索(DFS)

与无向图DFS逻辑类似,但需遵循边的方向,仅能沿有向边遍历。可用于有向环检测强连通分量求解(如Tarjan算法)。

  • 时间复杂度:邻接矩阵存储为O(n²),邻接表存储为O(|V|+|E|)

2. 广度优先搜索(BFS)

按层遍历有向图,仅能沿有向边扩散,可用于求解有向无权图的单源最短路径

  • 时间复杂度:邻接矩阵存储为O(n²),邻接表存储为O(|V|+|E|)

3. 拓扑排序

拓扑排序是对有向无环图(DAG)顶点的一种线性排序,满足:若存在有向边<u, v>,则排序中u一定在v之前。

  • 常用算法:Kahn算法(基于入度的贪心算法)、DFS逆序法
  • 应用场景:任务调度、课程安排、依赖关系解析等。

4. 关键路径

针对带权有向无环图,关键路径是从起点到终点的最长路径,决定了整个工程的最短完成时间,常用于项目进度规划。

五、有向图的实现示例

1. 邻接表实现(含拓扑排序)

fromcollectionsimportdequeclassDirectedGraph:def__init__(self,num_vertices):self.num_vertices=num_vertices# 邻接表:存储出边self.adj_list=[[]for_inrange(num_vertices)]# 入度数组self.indegree=[0]*num_verticesdefadd_edge(self,u,v):"""添加有向边<u, v>"""ifvnotinself.adj_list[u]:self.adj_list[u].append(v)self.indegree[v]+=1defremove_edge(self,u,v):"""删除有向边<u, v>"""ifvinself.adj_list[u]:self.adj_list[u].remove(v)self.indegree[v]-=1defdfs(self,start,visited=None):"""深度优先搜索"""ifvisitedisNone:visited=[False]*self.num_vertices visited[start]=Trueprint(start,end=" ")forneighborinself.adj_list[start]:ifnotvisited[neighbor]:self.dfs(neighbor,visited)defbfs(self,start):"""广度优先搜索"""visited=[False]*self.num_vertices queue=deque([start])visited[start]=Truewhilequeue:vertex=queue.popleft()print(vertex,end=" ")forneighborinself.adj_list[vertex]:ifnotvisited[neighbor]:visited[neighbor]=Truequeue.append(neighbor)deftopological_sort(self):"""Kahn算法实现拓扑排序,返回拓扑序列"""queue=deque()# 初始化队列:入度为0的顶点foriinrange(self.num_vertices):ifself.indegree[i]==0:queue.append(i)topo_order=[]whilequeue:u=queue.popleft()topo_order.append(u)# 遍历u的出边,减少邻接顶点入度forvinself.adj_list[u]:self.indegree[v]-=1ifself.indegree[v]==0:queue.append(v)# 若拓扑序列长度不等于顶点数,说明存在环iflen(topo_order)!=self.num_vertices:return"图中存在有向环,无法进行拓扑排序"returntopo_order

使用示例

# 初始化6个顶点的有向图(顶点0-5,模拟课程依赖)graph=DirectedGraph(6)# 添加有向边:表示课程先修关系,如<0,1>表示0是1的先修课graph.add_edge(0,1)graph.add_edge(0,2)graph.add_edge(1,3)graph.add_edge(2,3)graph.add_edge(3,4)graph.add_edge(3,5)print("DFS遍历结果(起点0):")graph.dfs(0)# 输出 0 1 3 4 5 2(顺序可能因邻接表存储不同有差异)print("\nBFS遍历结果(起点0):")graph.bfs(0)# 输出 0 1 2 3 4 5print("\n拓扑排序结果:")print(graph.topological_sort())# 输出 [0,2,1,3,5,4] 等合法序列

六、有向图的典型应用

  1. 依赖关系建模:如软件包的依赖、代码模块的调用关系、课程先修体系;
  2. 路径规划:如城市单行道的导航、网络数据包的路由;
  3. 状态机:如程序的状态转移、自动售货机的行为逻辑;
  4. 网络流:如物流运输的单向通路、通信网络的信号传输方向。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/31 14:42:22

终极懒人配置:lazy.nvim中文界面完美解决方案

终极懒人配置&#xff1a;lazy.nvim中文界面完美解决方案 【免费下载链接】lazy.nvim &#x1f4a4; A modern plugin manager for Neovim 项目地址: https://gitcode.com/GitHub_Trending/la/lazy.nvim 还在为Neovim插件管理器的英文界面而头疼吗&#xff1f;lazy.nvim…

作者头像 李华
网站建设 2026/1/31 15:26:33

23、Kubernetes开发与运维:常见问题及新兴项目解析

Kubernetes开发与运维:常见问题及新兴项目解析 1. 向容器添加自定义设置 在使用包含非自己创建的代码和系统的容器时,可能需要在容器内的进程运行前设置一些环境变量或创建配置文件。尤其是使用其他预先构建的开源软件,且没有现成可用的成熟容器时,这种需求更为常见。 常…

作者头像 李华
网站建设 2026/1/27 14:05:54

评职称为什么首选软件著作权?

作为专业技术人才晋升的重要参考&#xff0c;软著之所以备受青睐&#xff0c;主要基于以下几方面优势&#xff1a;一、申请流程简捷&#xff0c;获证周期短 软著申报材料相对简化&#xff0c;审核速度快&#xff0c;一般可在较短时间内取得证书。对于职称评审材料提交时间较为紧…

作者头像 李华
网站建设 2026/2/3 7:41:03

Wan2.2-T2V-5B如何应对模糊指令?容错机制解析

Wan2.2-T2V-5B如何应对模糊指令&#xff1f;容错机制解析 你有没有试过在AI视频生成器里输入“一个人跑步”&#xff0c;然后盯着屏幕等结果——心里却嘀咕&#xff1a;“到底是在操场跑&#xff1f;还是在末日废墟狂奔&#xff1f;” &#x1f605; 更糟的是&#xff0c;有些模…

作者头像 李华
网站建设 2026/2/3 8:17:53

制造业的迭代之困:版本混乱如何引发生产错误及系统化对策

在追求产品创新与市场响应速度的今天&#xff0c;制造业同样面临着“快速迭代”带来的严峻挑战。然而&#xff0c;与软件行业不同&#xff0c;制造业的版本混乱一旦引发生产错误&#xff0c;其代价往往是巨额的物料报废、整条生产线的停摆、严重的客户投诉乃至安全事故。因此&a…

作者头像 李华
网站建设 2026/2/1 5:45:09

极简接入流程(3步直连GPT-5)

一、3步极速接入GPT-5&#xff0c;零门槛上手步骤1&#xff1a;获取GPT-5专属API Key完成平台注册登录后&#xff0c;系统将自动发放GPT-5免费体验额度&#xff0c;无需提交额外申请材料&#xff0c;即时到账可用&#xff1b;登录后台管理系统&#xff0c;进入「API令牌管理」模…

作者头像 李华