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 7/23/2025, 6:24:59 AM