06图

Lingfeng2025-07-07

06图

1. 定义与基本概念

  • 无向图:边是顶点的无序对,即边没有方向性。
  • 有向图:其边是顶点的有序对,即边有方向性。
  • 连通分量:无向图中的极大连通子图。
  • 连通图:如果对于无向图 G 中任意两个顶点都是连通的,则称 G 是连通图。
  • 强连通分量:有向图中的极大强连通子图称作有向图的强连通分量。
  • 生成树:一个连通图 G 的一个包含所有顶点的极小连通子图 T 是包含 G 的所有顶点 n 个,T 为连通子图,T 包含的边数最少。则 T 是一棵有 n 个顶点,n-1 条边的生成树。

2. 存储结构

2.1 顺序存储

邻接矩阵

graph = [[0] * n for _ range(n)]

2.2 链式存储

邻接表

graph = defaultdict(list)
graph[v].append(u)

3. 遍历

3.1 深度优先 DFS

递归实现

visited = set()

def dfs(v):
    visited.add(v)
    for u in graph[v]:
        if u not in visited:
            dfs(u)

栈实现

def dfs(start):
    visited = set()
    stack = [start]

    while stack:
        v = stack.pop()
        if v not in visited:
            visited.add(v)

            for u in reversed(graph[v]):
                if u not in visited:
                    stack.append(u)

3.2 广度优先 BFS

队列实现

def bfs(start):
    visited = set()
    queue = deque([start])
    visited.add(start)

    while queue:
        v = queue.popleft()

        for u in graph[v]:
            if u not in visited:
                visited.add(u)
                queue.append(u)

4. 连通性问题

4.1 Prim 算法

def prim(start):
    visited = set()
    heap = [(0, start)]
    total_weight = 0

    while heap:
        weight, u = heapq.heappop(heap)
        if u in visited:
            continue

        visited.add(u)
        total_weight += weight

        for v, w in graph[u]:
            if v not in visited:
                heapq.heappush(heap, (w, v))

    return total_weight

时间复杂度为 ,空间复杂度为

4.2 Kruskal 算法

需要使用并查集

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n + 1))
        self.rank = [0] * (n + 1)

    def find(self, u):
        if (par := self.parent[u]) != u:
            self.parent[u] = self.find(par)
        return self.parent[u]

    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)

        if root_u != root_v:
            rank_u = self.rank[root_u]
            rank_v = self.rank[root_v]

            if rank_u > rank_v:
                self.parent[root_v] = root_u
            elif rank_v > rank_u:
                self.parent[root_u] = root_v
            else:
                self.parent[root_v] = root_u
                self.rank[root_u] += 1
def kruskal():
    edges.sort(key=lambda x: x[-1])
    total_weight = 0
    uf = UnionFind()

    for u, v, w in edges:
        if uf.find(u) != uf.find(v):
            uf.union(u, v)
            total_weight += w

    return total_weight

时间复杂度为 ,空间复杂度为

5. 有向无环图及其应用

5.1 拓扑排序

def topo_sort(graph):
    indegrees = {node: 0 for node in graph}

    for neighbors in graph.values():
        for n in neighbors:
            indegrees[n] += 1

    queue = deque(
        node for node, indegree in indegrees.items() if indegree == 0
    )
    topo_order = []

    while queue:
        node = queue.popleft()
        topo_order.append(node)

        for neighbor in graph[node]:
            indegrees[neighbor] -= 1
            if indegrees[neighbor] == 0:
                queue.append(neighbor)

    return topo_order

时间复杂度为 ,空间复杂度为

5.2 判断是否有环

拓扑排序,判断 len(topo_order) == n 即可。

或者 DPS:

def has_cycle(graph):

    def dfs(node):
        if state[node] == ON_PATH:
            return True
        if state[node] == VISITED:
            return False

        state[node] = ON_PATH
        for neighbor in graph[node]:
            if dfs(neighbor):
                return True
        state[node] = VISITED

        return False

    state = {node: UNVISITED for node in graph}
    for node in graph:
        if state[node] == UNVISITED:
            if dfs(node):
                return True

    return False

时间复杂度为 ,空间复杂度为

6. 最短路径

6.1 Dijkstra 算法

def dijkstra(start):
    distance = [float("inf")] * n
    distance[start] = 0
    heap = [(0, start)]

    while heap:
        dist, u = heapq.heappop(heap)

        if dist > distance[u]:
            continue

        for v, weight in graph[u]:
            if (new_dist := distance[u] + weight) < distance[v]:
                distance[v] = new_dist
                heapq.heappush(heap, (v, new_dist))

    return distance

时间复杂度为 ,空间复杂度为

6.2 Floyd 算法

def floyd():
    dist = [[float("inf")] * n for _ in range(n)]

    for i in range(n):
        dist[i][i] = 0

    for u in range(n):
        for v, weight in graph[u]:
            dist[u][v] = weight

    for i in range(n):
        for j in range(n):
            for k in range(n):
                if (new_dist := dist[i][k] + dist[k][j]) < dist[i][j]:
                     dist[i][j] = new_dist

    return dist

时间复杂度为 ,空间复杂度为

Last Updated 12/13/2025, 12:57:16 PM