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

图论基础:探索节点与关系的复杂网络

图是比线性表和树更为复杂的一种非线性数据结构。在线性表中,数据元素之间是线性关系;在树形结构中,元素之间是明显的层次关系(父子节点)。而在中,任意两个数据元素之间都可能存在关系,这使它能够完美地建模现实世界中各种复杂的关系网络,如社交网络、交通路线、任务依赖等。

一、 图的基本概念
  • 顶点:图中的数据元素,通常称为顶点 或 节点
  • :图中连接两个顶点的线,表示两者之间的关系。边可以是有方向的(有向图),也可以是无方向的(无向图)。
  • :边可以有一个数值权重,表示连接的代价、距离或强度,这样的图称为带权图
    • 无向图中,一个顶点的度是指与其相连的边的数量。
    • 有向图中,度分为入度(指向该顶点的边的数量)和出度(从该顶点指出的边的数量)。
  • 路径与环:从一个顶点经过一系列边到达另一个顶点构成的序列称为路径。如果路径的起点和终点是同一个顶点,则称之为

图的存储方式主要有两种:

  1. 邻接矩阵:使用一个二维数组来存储边的关系。简单直观,但空间复杂度高(O(V²)),适合稠密图。
  2. 邻接表:为每个顶点维护一个链表,存储所有与其相邻的顶点。空间效率高(O(V+E)),是更常用的表示方法,尤其适合稀疏图。

二、 图的遍历

图的遍历是指从图中某一顶点出发,按照某种策略访问图中所有顶点,且每个顶点仅被访问一次。遍历是许多图算法的基础。主要有两种策略:

1. 广度优先搜索(BFS)

  • 核心思想: “一圈一圈”地向外探索。先访问起始顶点,然后访问其所有未访问过的邻接顶点,再按顺序访问这些邻接顶点的邻接顶点,以此类推。
  • 数据结构: 队列。用于存储已被访问但其邻接点尚未被检查的顶点。
  • 算法步骤
    1. 将起始顶点标记为已访问,并放入队列。
    2. 当队列不为空时:
      • 从队列中取出一个顶点 v
      • 访问 v 的所有未被访问过的邻接顶点,将它们标记为已访问并依次放入队列。
  • 应用: 寻找无权图中的最短路径、检查图的连通性、社交网络中的“好友推荐”。
  • 复杂度: 时间复杂度 O(V+E),空间复杂度 O(V)。

代码示例(BFS 伪代码):

def BFS(graph, start_vertex):visited = set()          # 记录已访问的顶点queue = Queue()          # 创建一个队列visited.add(start_vertex)queue.enqueue(start_vertex)while not queue.is_empty():current_vertex = queue.dequeue()print(f”访问顶点:{current_vertex}”) # 处理当前顶点for neighbor in graph.adjacent_vertices_of(current_vertex):if neighbor not in visited:visited.add(neighbor)queue.enqueue(neighbor)

2. 深度优先搜索(DFS)

  • 核心思想: “一条路走到黑”。从起始顶点出发,沿着一条路径尽可能深地探索,直到没有未访问的邻接顶点,然后回溯到上一个顶点,继续探索其他路径。
  • 数据结构: (递归调用栈或显式栈)。体现了“后进先出”的回溯特性。
  • 算法步骤(递归版本)
    1. 访问当前顶点 v,并将其标记为已访问。
    2. 遍历 v 的所有邻接顶点 w
      • 如果 w 未被访问,则递归地执行 DFS(w)。
  • 应用: 寻找路径、检测图中是否存在环、拓扑排序。
  • 复杂度: 时间复杂度 O(V+E),空间复杂度 O(V)(主要取决于递归深度)。

代码示例(DFS 递归伪代码):

def DFS_recursive(graph, v, visited):visited.add(v)print(f”访问顶点:{v}”) # 处理当前顶点for w in graph.adjacent_vertices_of(v):if w not in visited:DFS_recursive(graph, w, visited)# 初始化调用
visited = set()
DFS_recursive(graph, start_vertex, visited)

三、 最小生成树(MST)

在一个带权的、连通的、无向图中,最小生成树是指一个无环的子图,它连接了图中所有的顶点,并且其所有边的权重之和最小。

应用场景: 要在多个城市之间铺设光缆,如何用最短的总线路连接所有城市(顶点)?这就是一个典型的最小生成树问题。

1. 普里姆算法(Prim‘s Algorithm)

  • 核心思想: 从任意一个顶点开始,一步步“生长”出一棵树。每次将连接当前生成树树外顶点的权重最小的边(以及该边对应的新顶点)加入到生成树中。
  • 数据结构: 优先队列(最小堆)。用于高效地找到当前可选的权重最小的边。
  • 算法步骤
    1. 任选一个顶点作为起始点,加入生成树。
    2. 将所有连接生成树内顶点与树外顶点的边加入优先队列。
    3. 从队列中取出权重最小的边。如果这条边连接的另一个顶点不在生成树中,则将该边和顶点加入生成树。
    4. 重复步骤2和3,直到所有顶点都加入生成树。

2. 克鲁斯卡尔算法(Kruskal‘s Algorithm)

  • 核心思想: 按权重从小到大考虑所有边,如果加入当前边不会与已选择的边构成环,则将其加入生成树。本质是并查集数据结构的完美应用。
  • 数据结构: 并查集。用于高效地判断两个顶点是否已经在同一连通分量(即加入边后是否会形成环)。
  • 算法步骤
    1. 将图中所有边按权重从小到大排序。
    2. 初始化一个空的生成树。
    3. 遍历排序后的边:
      • 如果当前边连接的两个顶点不在生成树的同一个连通分量中(即加入后不会形成环),则将该边加入生成树。
      • 否则,跳过该边。
    4. 当生成树中有 V-1 条边时,算法结束。

对比

  • Prim算法是“顶点导向”的,适合稠密图(边多)。
  • Kruskal算法是“边导向”的,适合稀疏图(边少)。

四、 拓扑排序

拓扑排序是针对有向无环图(DAG) 的一种线性序列。该序列需要满足:对于图中的每一条有向边 u -> v,在序列中 u 都出现在 v 的前面。

应用场景: 课程选修顺序(必须先修完高数才能修线性代数)、任务调度、编译过程中的依赖解析。

核心思想(Kahn 算法,基于BFS)

  1. 统计入度: 计算图中每个顶点的入度。
  2. 初始化队列: 将所有入度为0的顶点加入队列。这些顶点是“不依赖任何其他任务的任务”。
  3. 处理队列
    • 从队列中取出一个顶点 u,将其输出到拓扑序列中。
    • 遍历 u 的所有邻接顶点 v,将 v 的入度减1(相当于移除边 u->v)。
    • 如果某个顶点 v 的入度减为0,则将其加入队列。
  4. 检查结果: 如果最终的拓扑序列包含了图中所有的顶点,则排序成功;如果序列中顶点数少于总顶点数,说明图中存在环,无法进行拓扑排序。

算法示例
假设有如下课程依赖图(A->B 表示修B前需先修A):

数学 -> 物理
数学 -> 编程
物理 -> 电子
编程 -> 电子
编程 -> 算法

一种可能的拓扑排序是:[数学, 物理, 编程, 电子, 算法] 或 [数学, 编程, 物理, 算法, 电子]

代码示例(拓扑排序 Kahn 算法伪代码):

def topological_sort(graph):in_degree = {v: 0 for v in graph.vertices} # 初始化入度表# 计算所有顶点的入度for u in graph.vertices:for v in graph.adjacent_vertices_of(u):in_degree[v] += 1queue = Queue()# 将所有入度为0的顶点入队for v in graph.vertices:if in_degree[v] == 0:queue.enqueue(v)topo_order = []while not queue.is_empty():u = queue.dequeue()topo_order.append(u)for v in graph.adjacent_vertices_of(u):in_degree[v] -= 1if in_degree[v] == 0:queue.enqueue(v)if len(topo_order) != len(graph.vertices):print("错误:图中存在环,无法进行拓扑排序!")else:return topo_order

总结

图是一种极其强大和灵活的数据结构,其相关算法是解决许多现实世界复杂问题的关键。

主题核心思想关键数据结构应用场景
BFS遍历层层扩散,先广后深队列最短路径(无权)、连通性
DFS遍历深度探索,回溯前进栈(递归)路径查找、环检测
最小生成树用最小代价连接所有点Prim:优先队列 / Kruskal:并查集+排序网络搭建、电路设计
拓扑排序为有向无环图安排顺序队列、入度表任务调度、依赖管理

理解这些经典图算法,不仅能帮助你在技术面试中游刃有余,更能为你提供解决复杂系统设计问题的强大工具箱。

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

相关文章:

  • 免费建网站 建站之星百度指数免费添加
  • python如何写数据到excel示例
  • Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
  • 测试经验分享,登录功能+购物车+限时秒杀(测试点)汇总
  • 腾讯云TVP走进美的,共探智能制造新范式
  • OpenAI 的 Sora 2来了:一场创意革命与失控的狂欢
  • 直播预告 | 时序数据赋能核电数字化转型,TDengine 引领创新新范式
  • 动漫网站建设规划书模板广州网站建设策划
  • 使用imapsync增量同步邮件到新邮局服务器
  • iOS 混淆与 IPA 加固全流程,多工具组合实现无源码混淆、源码防护与可审计流水线(iOS 混淆|IPA 加固|无源码加固|App 防反编译)
  • java数据结构--ArrayList与顺序表
  • 【IEEE/EI/Scopus检索】2026年IEEE第七届计算,网络与物联网国际会议(CNIOT 2026)
  • 大数据计算引擎-Hudi对Spark Catalyst 优化器的RBO、CBO做了什么
  • 设计模式之:建造者模式
  • 阿里云 RDS MySQL 可观测性最佳实践
  • 【含文档+PPT+源码】基于spring boot的固定资产管理系统
  • 企业门户网站建设新闻柳州seo培训
  • 广东长海建设工程有限公司网站众筹网站建设报价
  • 航运、应急、工业适用,AORO P1100三防平板引领行业数字化变革
  • Linux网络:UDP
  • vue3知识点-ref和reactive以及toRefs与toRef
  • 环保网站 源码wordpress展示页
  • NSSCTF - Web | 【第五空间 2021】pklovecloud
  • 了解“网络协议”
  • ECharts 实时数据平滑更新实践(含 WebSocket 模拟)
  • ImmutableList.of() 是 Google Guava 库 提供的一个静态工厂方法,用于创建一个不可变的(immutable)列表。
  • 【计算机网络】408考研计算机网络精讲:物理层核心——信道的极限容量(奈氏准则与香农定理)​​
  • 嵌入式模组拨号获取IP地址时,设置的ippass是什么原理,起到什么作用?
  • 网站开发 实训 报告郑州高端建站公司
  • 2025年--Lc203- 1218. 最长定差子序列(动态规划)--Java版