前言
大家好,最近我在美丽的重庆度过了一段美好的学习时光。重庆以其独特的山城地貌和美食闻名,而在火锅和享受美食之余,这里的项目学习激发了我对图论的兴趣。图论是一门既古老又新兴的学科,它在计算机科学、网络分析、社会网络、物流优化等领域有着广泛的应用。而 Python 的 NetworkX 库,则是进行图论算法研究和应用的利器。今天,我将带大家一起探讨如何利用 NetworkX 库进行图论算法的入门学习,并通过丰富的实际应用实例,帮助大家更好地理解和掌握这门技术。
如果你对图论感兴趣,或者在工作中需要处理网络数据,那么这篇文章绝对不容错过。记得收藏本文,并关注我的博客,让我们一起探索图论的奇妙世界!
图论简介
图论是一门研究图(Graph)的数学分支,图是由顶点(Vertex)和边(Edge)组成的结构。顶点可以表示各种实体,如人、城市、计算机等,边则表示这些实体之间的关系或连接。
图论的研究内容包括但不限于:
- 路径问题:寻找从一个顶点到另一个顶点的路径。
- 最短路径问题:寻找从一个顶点到另一个顶点的最短路径。
- 最大流问题:寻找从源点到汇点的最大流量。
- 图的连通性:判断图是否连通,即是否存在从任一顶点到任一其他顶点的路径。
- 图的遍历:如深度优先搜索(DFS)和广度优先搜索(BFS)。
NetworkX 库简介
NetworkX 是一个用于创建、操作和研究图和网络的 Python 库。它提供了丰富的图论算法,可以帮助我们轻松地进行图的操作和分析。NetworkX 支持多种类型的图,如无向图、有向图、多重图等,并提供了方便的图可视化功能。
安装和配置
首先,我们需要安装 NetworkX 库,可以通过以下命令安装:
pip install networkx
安装完成后,我们可以通过以下代码导入 NetworkX 库并创建一个简单的图:
import networkx as nx
import matplotlib.pyplot as plt
# 创建一个空的无向图
G = nx.Graph()
# 添加节点
G.add_node(1)
G.add_node(2)
G.add_node(3)
# 添加边
G.add_edge(1, 2)
G.add_edge(2, 3)
# 绘制图
nx.draw(G, with_labels=True)
plt.show()
以上代码创建了一个简单的无向图,并绘制了该图。
常见的算法应用举例
接下来,我们将介绍 20 个常见的图论算法应用,并提供相应的完整代码示例。每个示例都将包含详细的代码注释和算法介绍,帮助大家更好地理解和应用这些算法。
1. 图的遍历 - 深度优先搜索(DFS)
深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历节点,并在到达叶子节点后回溯。
算法介绍
DFS 算法的基本思想是尽可能深入图的分支。以下是 DFS 算法的伪代码:
DFS(G, v):
标记 v 为已访问
对于每个相邻节点 w:
如果 w 未被访问:
DFS(G, w)
代码示例
import networkx as nx
def dfs(graph, start):
visited, stack = set(), [start]
while stack:
vertex = stack.pop()
if vertex not in visited:
visited.add(vertex)
stack.extend(set(graph[vertex]) - visited)
return visited
# 创建一个示例图
G = nx.Graph()
edges = [(1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]
G.add_edges_from(edges)
# 执行深度优先搜索
visited_nodes = dfs(G, 1)
print("深度优先搜索访问的节点:", visited_nodes)
代码详解
dfs(graph, start)
:定义一个深度优先搜索函数,接受图和起始节点作为参数。visited, stack = set(), [start]
:初始化一个已访问节点集合和一个堆栈,将起始节点加入堆栈。while stack
:循环遍历堆栈,直到堆栈为空。vertex = stack.pop()
:弹出堆栈顶端的节点。if vertex not in visited
:如果节点未被访问,则进行以下操作:visited.add(vertex)
:将节点标记为已访问。stack.extend(set(graph[vertex]) - visited)
:将未访问的相邻节点加入堆栈。
2. 图的遍历 - 广度优先搜索(BFS)
广度优先搜索(BFS)是一种用于遍历或搜索树或图的算法。从起始节点开始,先访问其所有邻节点,然后再依次访问这些邻节点的邻节点,以此类推。
算法介绍
BFS 算法的基本思想是按层次遍历节点。以下是 BFS 算法的伪代码:
BFS(G, v):
创建一个队列 Q
标记 v 为已访问并将 v 入队 Q
while Q 非空:
u = Q 出队
对于每个相邻节点 w:
如果 w 未被访问:
标记 w 为已访问并将 w 入队 Q
代码示例
import networkx as nx
from collections import deque
def bfs(graph, start):
visited, queue = set(), deque([start])
visited.add(start)
while queue:
vertex = queue.popleft()
for neighbor in graph[vertex]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
return visited
# 创建一个示例图
G = nx.Graph()
edges = [(1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]
G.add_edges_from(edges)
# 执行广度优先搜索
visited_nodes = bfs(G, 1)
print("广度优先搜索访问的节点:", visited_nodes)
代码详解
bfs(graph, start)
:定义一个广度优先搜索函数,接受图和起始节点作为参数。visited, queue = set(), deque([start])
:初始化一个已访问节点集合和一个队列,将起始节点加入队列。while queue
:循环遍历队列,直到队列为空。vertex = queue.popleft()
:从队列头部弹出节点。for neighbor in graph[vertex]
:遍历当前节点的所有相邻节点。if neighbor not in visited
:如果相邻节点未被访问,则进行以下操作:visited.add(neighbor)
:将相邻节点标记为已访问。queue.append(neighbor)
:将相邻节点加入队列。
3. 最短路径算法 - Dijkstra 算法
Dijkstra 算法用于找到图中从一个节点到其他节点的最短路径。它假设图中的边权重为非负值。
算法介绍
Dijkstra 算法的基本思想是逐步扩展已知最短路径的节点集合。以下是 Dijkstra 算法的伪代码:
Dijkstra(G, s):
初始化
dist[s] = 0
对于每个顶点 v:
如果 v ≠ s:
dist[v] = ∞
while 未处理的顶点集合非空:
u = 未处理顶点中具有最小 dist[u] 值的顶点
标记 u 为已处理
对于每个相邻节点 v:
如果 v 未被处理:
通过 u 的路径比 dist[v] 短:
dist[v] = dist[u] + weight(u, v)
前驱[v] = u
代码示例
import networkx as nx
import heapq
def dijkstra(graph, start):
# 初始化距离字典和优先队列
distances = {
node: float('inf') for node in graph.nodes}
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['weight']
if distance < distances[neighbor]:
distances[neighbor]
= distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
# 创建一个示例图
G = nx.Graph()
edges = [(1, 2, 1), (1, 3, 4), (2, 3, 2), (2, 4, 7), (3, 4, 3)]
G.add_weighted_edges_from(edges)
# 执行 Dijkstra 算法
shortest_paths = dijkstra(G, 1)
print("Dijkstra 算法求得的最短路径:", shortest_paths)
代码详解
dijkstra(graph, start)
:定义一个 Dijkstra 算法函数,接受图和起始节点作为参数。distances = {node: float('inf') for node in graph.nodes}
:初始化每个节点到起始节点的距离为无穷大。distances[start] = 0
:设置起始节点到自身的距离为 0。priority_queue = [(0, start)]
:初始化优先队列,将起始节点加入队列。while priority_queue
:循环遍历优先队列,直到队列为空。current_distance, current_node = heapq.heappop(priority_queue)
:从优先队列中弹出距离最小的节点。for neighbor, weight in graph[current_node].items()
:遍历当前节点的所有相邻节点。distance = current_distance + weight['weight']
:计算从当前节点到相邻节点的距离。if distance < distances[neighbor]
:如果通过当前节点的路径比已知最短路径更短,则更新最短路径。
4. 最短路径算法 - Bellman-Ford 算法
Bellman-Ford 算法用于找到图中从一个节点到其他节点的最短路径。它允许图中存在负权重边,但不允许负权重回路。
算法介绍
Bellman-Ford 算法的基本思想是逐步松弛图中的边。以下是 Bellman-Ford 算法的伪代码:
Bellman-Ford(G, s):
初始化
dist[s] = 0
对于每个顶点 v:
如果 v ≠ s:
dist[v] = ∞
对于每个顶点 v:
对于每条边 (u, v) ∈ G:
如果 dist[u] + weight(u, v) < dist[v]:
dist[v] = dist[u] + weight(u, v)
检测负权重回路
对于每条边 (u, v) ∈ G:
如果 dist[u] + weight(u, v) < dist[v]:
报告负权重回路
代码示例
import networkx as nx
def bellman_ford(graph, start):
# 初始化距离字典
distances = {
node: float('inf') for node in graph.nodes}
distances[start] = 0
# 松弛边
for _ in range(len(graph.nodes) - 1):
标签:图论,Python,graph,queue,start,算法,NetworkX,visited,节点
From: https://blog.csdn.net/oLawrencedon/article/details/140264770