📅  最后修改于: 2023-12-03 15:12:27.679000             🧑  作者: Mango
邻接表是表示图的一种常见数据结构,用于存储图中每个顶点的所有邻居(即与该顶点直接相连的其他顶点)。
邻接表由一个数组和一个链表组成。数组中的每个元素表示一个顶点,对应的链表存储了该顶点的所有邻居。
例如,下面这张图:
A -- B
| |
C -- D
可以用以下邻接表表示:
A: B -> C
B: A -> D
C: A -> D
D: B -> C
实现一个邻接表需要定义两个类:一个表示图,另一个表示顶点。
from typing import List
class Graph:
def __init__(self, vertices: List[str]):
self.vertices = vertices
self.adj_list = {}
for vertex in vertices:
self.adj_list[vertex] = []
def add_edge(self, v1: str, v2: str):
self.adj_list[v1].append(v2)
self.adj_list[v2].append(v1)
Graph 类有两个属性:vertices 表示图中的所有顶点,adj_list 为邻接表,初始化时将每个顶点对应的链表初始化为空。
add_edge() 方法用于添加一条边,将两个顶点加入对方的邻居链表。
Vertex 类表示顶点,主要保存顶点的名称和邻居链表。
class Vertex:
def __init__(self, name: str):
self.name = name
self.neighbors = []
def add_neighbor(self, neighbor):
self.neighbors.append(neighbor)
Vertex 类只有两个属性:name 表示顶点的名称,neighbors 表示邻居链表。
add_neighbor() 方法用于将一个顶点加入邻居链表。
vertices = ['A', 'B', 'C', 'D']
graph = Graph(vertices)
graph.add_edge('A', 'B')
graph.add_edge('A', 'C')
graph.add_edge('B', 'D')
graph.add_edge('C', 'D')
以上代码创建了一个图,共四个顶点,分别为 A、B、C、D,每个顶点的邻居链表如下:
A: B -> C
B: A -> D
C: A -> D
D: B -> C
邻接表可以用于遍历图,因为每个顶点的邻居链表已经保存了和该顶点相连的所有其他顶点。常用的遍历方法包括深度优先搜索和广度优先搜索。
深度优先搜索(Depth First Search,DFS)在递归过程中不断访问当前节点的邻居节点,直到没有未被访问的邻居节点为止,然后回溯到上一个节点继续搜索。
def depth_first_search(vertex: Vertex, visited: set):
visited.add(vertex)
print(vertex.name)
for neighbor in vertex.neighbors:
if neighbor not in visited:
depth_first_search(neighbor, visited)
visited = set()
depth_first_search(graph.adj_list['A'], visited)
以上代码从 A 点开始进行深度优先搜索,visited 用于记录哪些点已经被访问过了。对于每个没有被访问过的邻居节点,递归地进行深度优先搜索。
输出为:
A
B
D
C
广度优先搜索(Breadth First Search,BFS)从起点开始,逐层遍历图中所有的节点,直到与起点相遇或者遍历完所有节点。
from collections import deque
def breadth_first_search(vertex: Vertex):
visited = set()
queue = deque()
queue.append(vertex)
visited.add(vertex)
while queue:
curr_vertex = queue.popleft()
print(curr_vertex.name)
for neighbor in curr_vertex.neighbors:
if neighbor not in visited:
queue.append(neighbor)
visited.add(neighbor)
breadth_first_search(graph.adj_list['A'])
以上代码从 A 点开始进行广度优先搜索,使用队列存储待访问的节点。访问当前节点后,将其所有未访问过的邻居节点加入队列。
输出为:
A
B
C
D