📌  相关文章
📜  邻接表(1)

📅  最后修改于: 2023-12-03 15:12:27.679000             🧑  作者: Mango

邻接表(Adjacency List)

邻接表是表示图的一种常见数据结构,用于存储图中每个顶点的所有邻居(即与该顶点直接相连的其他顶点)。

原理

邻接表由一个数组和一个链表组成。数组中的每个元素表示一个顶点,对应的链表存储了该顶点的所有邻居。

例如,下面这张图:

    A -- B
    |    |
    C -- D

可以用以下邻接表表示:

A: B -> C
B: A -> D
C: A -> D
D: B -> C
实现

实现一个邻接表需要定义两个类:一个表示图,另一个表示顶点。

Graph 类
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 类

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