Skip to content

图算法

图算法用于处理图结构数据,包括最短路径、最小生成树、拓扑排序等问题。

最短路径

Dijkstra 算法

Dijkstra 算法用于计算从一个节点到其他所有节点的最短路径,适用于非负权边的图。

实现

python
import heapq

def dijkstra(graph, start):
    # 初始化距离字典
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    
    # 优先队列
    priority_queue = [(0, start)]
    
    while priority_queue:
        current_distance, current_node = heapq.heappop(priority_queue)
        
        if current_distance > distances[current_node]:
            continue
        
        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))
    
    return distances

# 示例图(带权)
graph = {
    'A': {'B': 4, 'C': 2},
    'B': {'A': 4, 'C': 1, 'D': 5},
    'C': {'A': 2, 'B': 1, 'D': 8, 'E': 10},
    'D': {'B': 5, 'C': 8, 'E': 2, 'F': 6},
    'E': {'C': 10, 'D': 2, 'F': 3},
    'F': {'D': 6, 'E': 3}
}

distances = dijkstra(graph, 'A')
print("Dijkstra 最短路径:")
for node, distance in distances.items():
    print(f"从 A 到 {node}: {distance}")

Floyd-Warshall 算法

Floyd-Warshall 算法用于计算图中所有节点对之间的最短路径。

实现

python
def floyd_warshall(graph):
    nodes = list(graph.keys())
    n = len(nodes)
    
    # 初始化距离矩阵
    dist = [[float('inf')] * n for _ in range(n)]
    
    # 设置对角线为 0
    for i in range(n):
        dist[i][i] = 0
    
    # 设置已知边
    for i, node in enumerate(nodes):
        for neighbor, weight in graph[node].items():
            j = nodes.index(neighbor)
            dist[i][j] = weight
    
    # 动态规划计算最短路径
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if dist[i][j] > dist[i][k] + dist[k][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]
    
    return dist, nodes

# 示例
dist, nodes = floyd_warshall(graph)
print("\nFloyd-Warshall 所有节点对最短路径:")
for i, start in enumerate(nodes):
    for j, end in enumerate(nodes):
        print(f"从 {start}{end}: {dist[i][j]}")

最小生成树

Prim 算法

Prim 算法从一个节点开始,逐步添加边来构建最小生成树。

实现

python
def prim(graph, start):
    mst = []
    visited = {start}
    edges = []
    
    # 添加起始节点的所有边
    for neighbor, weight in graph[start].items():
        heapq.heappush(edges, (weight, start, neighbor))
    
    while edges and len(visited) < len(graph):
        weight, u, v = heapq.heappop(edges)
        
        if v not in visited:
            visited.add(v)
            mst.append((u, v, weight))
            
            for neighbor, w in graph[v].items():
                if neighbor not in visited:
                    heapq.heappush(edges, (w, v, neighbor))
    
    return mst

# 示例
mst = prim(graph, 'A')
print("\nPrim 最小生成树:")
for u, v, weight in mst:
    print(f"{u} - {v}: {weight}")

拓扑排序

Kahn 算法

Kahn 算法使用入度和队列来进行拓扑排序。

实现

python
from collections import deque

def topological_sort(graph):
    # 计算入度
    in_degree = {node: 0 for node in graph}
    for node in graph:
        for neighbor in graph[node]:
            in_degree[neighbor] += 1
    
    # 初始化队列
    queue = deque([node for node in in_degree if in_degree[node] == 0])
    result = []
    
    while queue:
        node = queue.popleft()
        result.append(node)
        
        for neighbor in graph[node]:
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)
    
    # 检查是否有环
    if len(result) != len(graph):
        raise ValueError("图中存在环")
    
    return result

# 有向无环图
dag = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['E'],
    'D': ['F'],
    'E': ['F'],
    'F': []
}

top_order = topological_sort(dag)
print("\n拓扑排序结果:")
print(" -> ".join(top_order))  # A -> B -> C -> D -> E -> F