图论入门与邻接表详解


📘 图论入门与邻接表详解

—— 零基础也能看懂的图论学习笔记


一、什么是图论?

图论(Graph Theory) 是数学和计算机科学中的一个重要分支,研究“图”这种结构。

图(Graph) ≠ 柱状图/折线图
它是由 顶点(Vertex/Node)边(Edge) 组成的结构,用来表示对象之间的关系。

🌟 常见应用场景:

  • 社交网络:人是顶点,朋友关系是边
  • 地图导航:城市是顶点,道路是边
  • 课程依赖:课程是顶点,先修关系是边
  • 网页链接:网页是顶点,超链接是边

二、图的基本组成

概念说明
顶点(Vertex)表示一个对象,如人、城市、网页
边(Edge)表示两个顶点之间的连接或关系
图 G = (V, E)V 是顶点集合,E 是边集合

举例:

A —— B —— C
  • 顶点:A, B, C
  • 边:A-B, B-C

三、图的类型

类型说明示例
无向图边没有方向,A—B 等价于 B—A朋友关系
有向图边有方向,A→B 不一定可逆网页链接、课程依赖
加权图每条边有“权重”(如距离、成本)导航系统中的道路长度
简单图无自环、无重复边大多数算法题
多重图允许重复边或自环少见

四、基本术语

术语含义
度(Degree)一个顶点连接的边数(有向图分入度/出度)
路径(Path)从一个顶点到另一个顶点经过的边序列
环(Cycle)起点和终点相同的路径
连通图任意两点都有路径(无向图)
强连通任意两点可互相到达(有向图)
树(Tree)无环的连通无向图

五、图的存储方式

有两种主流方式:

1. 邻接矩阵(Adjacency Matrix)

  • 用二维数组 matrix[i][j] 表示是否有边
  • 空间复杂度:O(V²)
  • 适合稠密图

2. ✅ 邻接表(Adjacency List) ← 推荐初学者掌握


六、邻接表详解(重点!)

1. 什么是邻接表?

每个顶点维护一个列表,记录它连接的所有邻居。

📌 本质:“谁和我相连”

2. 如何建邻接表?(三步法)

✅ 步骤 1:初始化
# 顶点编号 0 ~ n-1(连续整数)
n = 5
g = [[] for _ in range(n)]  # g[i] 是顶点 i 的邻居列表

⚠️ 错误写法:g = [[]] * n → 所有子列表共享引用!
✅ 正确写法:g = [[] for _ in range(n)]

✅ 步骤 2:添加边
无向图(双向)
u, v = 1, 2
g[u].append(v)
g[v].append(u)
有向图(单向)
u, v = 1, 2  # u → v
g[u].append(v)
# 不加反向边
✅ 步骤 3:处理重复边(可选)
seen = set()
for a, b in edges:
    if (a, b) not in seen:
        seen.add((a, b))
        g[b].append(a)  # 例如课程依赖

3. 邻接表示例

示例 1:无向图
A — B — C
g = {
    'A': ['B'],
    'B': ['A', 'C'],
    'C': ['B']
}
示例 2:有向图(课程依赖)
prerequisites = [[1,0], [2,1]]  # 0→1, 1→2
g = [[1], [2], []]

图:0 → 1 → 2


4. 如何“读”邻接表?

给你一个邻接表,如何还原图?

g = [[1], [2], [0]]
  1. 顶点:0, 1, 2
  2. 读每行:
    • 0 → 1
    • 1 → 2
    • 2 → 0
  3. 画图 → 发现环:0→1→2→0

📌 判断有向/无向:

  • 对称 → 无向
  • 不对称 → 有向

5. 邻接表 vs 邻接矩阵

对比项邻接表邻接矩阵
空间O(V + E)O(V²)
适合稀疏图稠密图
查边O(度)O(1)
遍历邻居

推荐使用邻接表:大多数算法题中图是稀疏的。


七、邻接表 + 常见算法

1. BFS(广度优先搜索)

from collections import deque

def bfs(start, g):
    visited = [False] * len(g)
    queue = deque([start])
    order = []
    
    while queue:
        node = queue.popleft()
        if not visited[node]:
            visited[node] = True
            order.append(node)
            for neighbor in g[node]:
                if not visited[neighbor]:
                    queue.append(neighbor)
    return order

用途:最短路径(无权图)、层序遍历


2. DFS(深度优先搜索)

def dfs(node, g, visited, order):
    visited[node] = True
    order.append(node)
    for neighbor in g[node]:
        if not visited[neighbor]:
            dfs(neighbor, g, visited, order)

用途:检测环、拓扑排序、连通性


八、经典应用:课程表问题(拓扑排序)

判断是否能完成所有课程(即图是否有环):

def canFinish(numCourses, prerequisites):
    g = [[] for _ in range(numCourses)]
    for a, b in prerequisites:
        g[b].append(a)  # b → a
    
    colors = [0] * numCourses  # 0:未访问, 1:访问中, 2:已完成
    
    def dfs(x):
        colors[x] = 1
        for y in g[x]:
            if colors[y] == 1:
                return True  # 发现环
            if colors[y] == 0 and dfs(y):
                return True
        colors[x] = 2
        return False
    
    for i in range(numCourses):
        if colors[i] == 0 and dfs(i):
            return False  # 有环
    return True

📌 核心:用 colors 标记状态,g 存图,dfs 检测环。


九、学习建议

  1. 从画图开始:先画几个小图,练习 BFS/DFS 手动遍历
  2. 动手实现:用 Python 写邻接表 + BFS/DFS
  3. 刷题巩固
  4. 理解本质:图是“关系”的抽象,邻接表是“谁连谁”的记录

十、总结口诀

🔑 邻接表三步走

  1. g = [[] for _ in range(n)]
  2. 遍历边,取出 u, v
  3. 加边:
    • 无向:g[u].append(v) + g[v].append(u)
    • 有向:g[u].append(v)

🔑 图论一句话
顶点是对象,边是关系,邻接表是存储,BFS/DFS 是遍历工具。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值