数据结构与算法之数据结构 图经典问题 最小生成树 / 最短路径

数据结构与算法阿木 发布于 2025-07-11 13 次阅读


摘要:

图数据结构是计算机科学中一种重要的数据结构,广泛应用于网络、图论等领域。本文将围绕图数据结构,探讨最小生成树和最短路径两个经典问题,并分别介绍Prim算法、Kruskal算法、Dijkstra算法和Bellman-Ford算法的实现。

一、

图数据结构由节点(顶点)和边组成,节点表示实体,边表示实体之间的关系。在图数据结构中,最小生成树和最短路径问题是两个重要的应用场景。最小生成树问题要求在无向连通图中,找出一个包含所有节点的最小权值生成树;最短路径问题则要求在图中找到两个节点之间的最短路径。

二、最小生成树

最小生成树问题可以通过Prim算法和Kruskal算法解决。

1. Prim算法

Prim算法是一种基于贪心策略的最小生成树算法。其基本思想是从一个节点开始,逐步扩展生成树,每次选择与已生成树连接的最小权值边。

python

def prim(graph):


n = len(graph)


visited = [False] n


min_edge = [float('inf')] n


min_edge[0] = 0


parent = [-1] n


for i in range(n):


u = min_edge.index(min(min_edge))


visited[u] = True


for v in range(n):


if graph[u][v] and not visited[v] and graph[u][v] < min_edge[v]:


min_edge[v] = graph[u][v]


parent[v] = u


return parent

示例


graph = [


[0, 2, 0, 6, 0],


[2, 0, 3, 8, 5],


[0, 3, 0, 0, 7],


[6, 8, 0, 0, 9],


[0, 5, 7, 9, 0]


]


parent = prim(graph)


print(parent)


2. Kruskal算法

Kruskal算法是一种基于并查集的最小生成树算法。其基本思想是将所有边按照权值从小到大排序,然后依次选择边,如果选择该边不会形成环,则将其加入生成树。

python

def find(parent, i):


if parent[i] == i:


return i


return find(parent, parent[i])

def union(parent, rank, x, y):


xroot = find(parent, x)


yroot = find(parent, y)


if rank[xroot] < rank[yroot]:


parent[xroot] = yroot


elif rank[xroot] > rank[yroot]:


parent[yroot] = xroot


else:


parent[yroot] = xroot


rank[xroot] += 1

def kruskal(graph):


n = len(graph)


parent = [i for i in range(n)]


rank = [0] n


result = []


for i in range(n):


for j in range(i + 1, n):


if graph[i][j]:


result.append((i, j, graph[i][j]))


result.sort(key=lambda x: x[2])


for edge in result:


x = find(parent, edge[0])


y = find(parent, edge[1])


if x != y:


union(parent, rank, x, y)


result.append(edge)


return result

示例


graph = [


[0, 2, 0, 6, 0],


[2, 0, 3, 8, 5],


[0, 3, 0, 0, 7],


[6, 8, 0, 0, 9],


[0, 5, 7, 9, 0]


]


result = kruskal(graph)


print(result)


三、最短路径

最短路径问题可以通过Dijkstra算法和Bellman-Ford算法解决。

1. Dijkstra算法

Dijkstra算法是一种基于贪心策略的最短路径算法。其基本思想是从源节点开始,逐步扩展最短路径,每次选择与已扩展路径连接的最短权值边。

python

import heapq

def dijkstra(graph, src):


n = len(graph)


min_heap = [(0, src)]


dist = [float('inf')] n


dist[src] = 0


while min_heap:


d, u = heapq.heappop(min_heap)


if d > dist[u]:


continue


for v, weight in enumerate(graph[u]):


if weight and dist[u] + weight < dist[v]:


dist[v] = dist[u] + weight


heapq.heappush(min_heap, (dist[v], v))


return dist

示例


graph = [


[0, 4, 0, 0, 0, 0, 0, 8, 0],


[4, 0, 8, 0, 0, 0, 0, 11, 0],


[0, 8, 0, 7, 0, 4, 0, 0, 2],


[0, 0, 7, 0, 9, 14, 0, 0, 0],


[0, 0, 0, 9, 0, 10, 0, 0, 0],


[0, 0, 4, 14, 10, 0, 2, 0, 0],


[0, 0, 0, 0, 0, 2, 0, 1, 6],


[8, 11, 0, 0, 0, 0, 1, 0, 7],


[0, 0, 2, 0, 0, 0, 6, 7, 0]


]


dist = dijkstra(graph, 0)


print(dist)


2. Bellman-Ford算法

Bellman-Ford算法是一种基于动态规划的最短路径算法。其基本思想是从源节点开始,逐步扩展最短路径,每次检查是否有更短的路径。

python

def bellman_ford(graph, src):


n = len(graph)


dist = [float('inf')] n


dist[src] = 0


for _ in range(n - 1):


for u in range(n):


for v, weight in enumerate(graph[u]):


if weight and dist[u] + weight < dist[v]:


dist[v] = dist[u] + weight


return dist

示例


graph = [


[0, 4, 0, 0, 0, 0, 0, 8, 0],


[4, 0, 8, 0, 0, 0, 0, 11, 0],


[0, 8, 0, 7, 0, 4, 0, 0, 2],


[0, 0, 7, 0, 9, 14, 0, 0, 0],


[0, 0, 0, 9, 0, 10, 0, 0, 0],


[0, 0, 4, 14, 10, 0, 2, 0, 0],


[0, 0, 0, 0, 0, 2, 0, 1, 6],


[8, 11, 0, 0, 0, 0, 1, 0, 7],


[0, 0, 2, 0, 0, 0, 6, 7, 0]


]


dist = bellman_ford(graph, 0)


print(dist)


四、总结

本文介绍了图数据结构在最小生成树和最短路径问题中的应用。Prim算法和Kruskal算法可以解决最小生成树问题,而Dijkstra算法和Bellman-Ford算法可以解决最短路径问题。在实际应用中,可以根据具体问题选择合适的算法。