""" 无向图:边表示两顶点之间的双向链接关系,如 A---B,即仅通过一条边,A 可达到 B,B 也可达到 A 有向图:边具有方向性,如 A --> B 或 B <-- A,即通过一条边,只能由 A 向 B 或 B 向 A 连通图:从某个顶点出发,可以到达其余任意顶点。 非连通图:从某个顶点出发,至少有一个顶点无法到达。 邻接(adjacency):当两顶点之间存在边相连时,称这两顶点“邻接“ 路径(path):从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径 度(degree):一个顶点拥有的边数 有权图:每条边都具有一个值(权重),表示从一个顶点到另一个顶点之间的代价/开销等.... """ """ 邻接矩阵:设图的顶点数量为 n,邻接矩阵使用一个 n*n大小的矩阵来表示图,行(列)表示一个顶点 矩阵元素代表边,用1或0表示两个顶点之间是否存在边,如: 1 3 5 6 顶点 1 0 1 1 0 3 1 0 1 0 5 1 1 0 1 6 0 1 0 0 注意这里表示的是无向图,关于矩阵关于主对角线对称 将 1 和 0 替换为其他的值,则可表示有权图 """ # 实现一个邻接矩阵 class GraphAdjMat: def __init__(self, vertices: list[int], edges: list[list[int]]): self.vertices: list[int] = [] self.adj_mat: list[list[int]] = [] # 添加顶点 for val in vertices: self.add_vertex(val) for e in edges: self.add_edge(e[0], e[1]) def size(self) -> int: return len(self.vertices) def add_vertex(self, val: int): n = self.size() self.vertices.append(val) # 在邻接矩阵中添加一行 new_row = [0] * n self.adj_mat.append(new_row) # 向邻接矩阵中添加一列 for row in self.adj_mat: row.append(0) def add_edge(self, i:int, j:int): # 参数 i, j 对应 vertices 元素索引 if i < 0 or j < 0 or i >= self.size() or j >= self.size(): raise IndexError() # 无向图中,邻接矩阵关于主对角线对称 self.adj_mat[i][j] = 1 self.adj_mat[j][i] = 1 def remove_vertex(self, index: int): if index >= self.size(): raise IndexError() self.vertices.pop(index) # 删除对应索引的行 self.adj_mat.pop(index) # 删除对应索引的列 for row in self.adj_mat: row.pop(index) def remove_edge(self, i: int, j: int): if i < 0 or j < 0 or i >= self.size() or j >= self.size() or i == j: raise IndexError() self.adj_mat[i][j] = 0 self.adj_mat[j][i] = 0 """ 设无向图的顶点总数为 n、边总数为 m,则: 添加边:在顶点对应链表的末尾添加边即可,因为是无向图,所以需要同时添加两个方向的边。 删除边:在顶点对应链表中查找并删除指定边,在无向图中,需要同时删除两个方向的边 添加顶点:在邻接表中添加一个链表,并将新增顶点作为链表头节点 删除顶点:需遍历整个邻接表,删除包含指定顶点的所有边 初始化:在邻接表中创建 n 个顶点和 2m 条边 """ class Vertex: """顶点类""" def __init__(self, val: int): self.val = val def vals_to_vets(vals: list[int]) -> list["Vertex"]: """输入值列表 vals ,返回顶点列表 vets""" return [Vertex(val) for val in vals] def vets_to_vals(vets: list["Vertex"]) -> list[int]: """输入顶点列表 vets ,返回值列表 vals""" return [vet.val for vet in vets] class GraphAdjList: def __init__(self, edges: list[list[Vertex]]): self.adj_list = dict[Vertex, list[Vertex]]() for edge in edges: self.add_vertex(edge[0]) self.add_vertex(edge[1]) self.add_edge(edge[0], edge[1]) def size(self): return len(self.adj_list) def add_edge(self, vet1: Vertex, vet2: Vertex): if vet1 not in self.adj_list or vet2 not in self.adj_list or vet1 == vet2: raise ValueError() # 无向表,两边都需添加 self.adj_list[vet1].append(vet2) self.adj_list[vet2].append(vet1) def remove_edge(self, vet1: Vertex, vet2: Vertex): if vet1 not in self.adj_list or vet2 not in self.adj_list: raise ValueError() self.adj_list[vet1].remove(vet2) self.adj_list[vet2].remove(vet1) def add_vertex(self, vet: Vertex): """添加顶点""" if vet in self.adj_list: return # 在邻接表中添加一个新链表 self.adj_list[vet] = [] def remove_vertex(self, vet: Vertex): """删除顶点""" if vet not in self.adj_list: raise ValueError() # 在邻接表中删除顶点 vet 对应的链表 self.adj_list.pop(vet) # 遍历其他顶点的链表,删除所有包含 vet 的边 for vertex in self.adj_list: if vet in self.adj_list[vertex]: self.adj_list[vertex].remove(vet) def print(self): print("邻接表 =") for vertex in self.adj_list: tmp = [v.val for v in self.adj_list[vertex]] print(f'{vertex.val}: {tmp}')