图
基本介绍
表示方式
图的创建
from typing import Listclass Graph:vertex_list: List[str] = [] # 存储顶点的数组edges: List[list] = [] # 存储图中各条边的邻接矩阵num_edges: int = 0 # 边的数总数def __init__(self, n: int):"""根据传入的顶点个数初始化顶点数组和邻接矩阵n: 图中的顶点个数"""for i in range(n):arr = []for j in range(n):arr.append(0)self.edges.append(arr)def insert_vertex(self, vertex_val: str):"""添加顶点vertex_val: 顶点的值"""self.vertex_list.append(vertex_val)def insert_edge(self, v1: int, v2: int, weight: int = 0):"""添加边v1: 边的起始顶点的下标,从0开始v2: 边的结束顶点的下标,从0开始weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,AB之间存在边,所以weight=1"""# 因为是无向图,所以两个顶点对应的位置都要设置边self.edges[v1][v2] = weightself.edges[v2][v1] = weightself.num_edges += 1 # 边的数量加1def show_graph(self):"""遍历邻接矩阵"""for arr in self.edges:for i in arr:print(i, end=' ')print()def get_num_vertex(self) -> int:"""返回图中的顶点个数"""return len(self.vertex_list)def get_num_edge(self) -> int:"""返回图中边的数量"""return self.num_edgesdef get_vertex_val_by_index(self, i: int) -> str:"""根据顶点下标返回顶点的值如传入下标0,返回A"""return self.vertex_list[i]def get_weight(self, v1: int, v2: int) -> int:"""返回两个顶点之间边的权值"""return self.edges[v1][v2]def test_graph():n = 5vertex_arr = ['A', 'B', 'C', 'D', 'E']graph = Graph(n)# 向图中循环添加顶点for i in vertex_arr:graph.insert_vertex(i)# 添加边graph.insert_edge(0, 1, 1)graph.insert_edge(0, 2, 1)graph.insert_edge(1, 2, 1)graph.insert_edge(1, 3, 1)graph.insert_edge(1, 4, 1)# 显示图的邻接矩阵graph.show_graph()test_graph()
图的深度优先遍历
基本介绍
代码实现
from typing import Listclass Graph:vertex_list: List[str] = [] # 存储顶点的数组edges: List[list] = [] # 存储图中各条边的邻接矩阵num_edges: int = 0 # 边的数总数is_visited: List[bool] = [] # 标记一个节点是否被访问def __init__(self, n: int):"""根据传入的顶点个数初始化顶点数组和邻接矩阵n: 图中的顶点个数"""for i in range(n):arr = []for j in range(n):arr.append(0)self.edges.append(arr)self.is_visited.append(False)def get_first_neighbor(self, index: int):"""返回节点第一个邻接节点的下标,如果节点没有邻接节点则返回-1"""for i in range(len(self.vertex_list)):if self.edges[index][i] > 0:return ireturn -1def get_next_neighbor(self, v1: int, v2: int):"""根据节点v1的前一个邻接节点的下标v2获取节点v1的下一个邻接节点的下标"""for i in range(v2 + 1, len(self.vertex_list)):if self.edges[v1][i] > 0:return ireturn -1def dfs(self, i: int):"""深度优先遍历:param i: 从节点i开始遍历:return:"""# 访问节点i,即输出它print(self.vertex_list[i], end=' -> ')self.is_visited[i] = True# 获取节点i的下一个邻接节点w = self.get_first_neighbor(i)# 如果节点i的下一个邻接节点w存在while w != -1:if not self.is_visited[w]: # 如果w没有被访问过,则从节点w开始继续深度遍历self.dfs(w)# 如果w已经被访问过,则从节点i的另一个邻接点开始遍历w = self.get_next_neighbor(i, w)# 如果w不存在,则回退到节点v,遍历节点v的下一个邻接点# 所谓的回溯,就是返回到调用dfs()的地方继续执行def for_dfs(self):"""遍历所有顶点,看是否存在没有访问过的节点"""for i in range(self.get_num_vertex()):if not self.is_visited[i]: # 存在没有访问过的节点,以该节点进行深度优先遍历self.dfs(i)def insert_vertex(self, vertex_val: str):"""添加顶点vertex_val: 顶点的值"""self.vertex_list.append(vertex_val)def insert_edge(self, v1: int, v2: int, weight: int = 0):"""添加边v1: 边的起始顶点的下标,从0开始v2: 边的结束顶点的下标,从0开始weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,AB之间存在边,所以weight=1"""# 因为是无向图,所以两个顶点对应的位置都要设置边self.edges[v1][v2] = weightself.edges[v2][v1] = weightself.num_edges += 1 # 边的数量加1def show_graph(self):"""遍历邻接矩阵"""for arr in self.edges:for i in arr:print(i, end=' ')print()def get_num_vertex(self) -> int:"""返回图中的顶点个数"""return len(self.vertex_list)def test_graph():n = 5vertex_arr = ['A', 'B', 'C', 'D', 'E']graph = Graph(n)# 向图中循环添加顶点for i in vertex_arr:graph.insert_vertex(i)# 添加边graph.insert_edge(0, 1, 1)graph.insert_edge(0, 2, 1)graph.insert_edge(1, 2, 1)graph.insert_edge(1, 3, 1)graph.insert_edge(1, 4, 1)# 显示图的邻接矩阵graph.show_graph()print("深度优先遍历:", end='')graph.for_dfs()test_graph()
图的广度优先遍历
基本介绍
代码实现
from typing import Listclass Graph:vertex_list: List[str] = [] # 存储顶点的数组edges: List[list] = [] # 存储图中各条边的邻接矩阵num_edges: int = 0 # 边的数总数is_visited: List[bool] = [] # 标记一个节点是否被访问def __init__(self, n: int):"""根据传入的顶点个数初始化顶点数组和邻接矩阵n: 图中的顶点个数"""for i in range(n):arr = []for j in range(n):arr.append(0)self.edges.append(arr)self.is_visited.append(False)def get_first_neighbor(self, index: int):"""返回节点第一个邻接节点的下标,如果节点没有邻接节点则返回-1"""for i in range(len(self.vertex_list)):if self.edges[index][i] > 0:return ireturn -1def get_next_neighbor(self, v1: int, v2: int):"""根据节点v1的前一个邻接节点的下标v2获取节点v1的下一个邻接节点的下标"""for i in range(v2 + 1, len(self.vertex_list)):if self.edges[v1][i] > 0:return ireturn -1def bfs(self, i: int):"""对一个节点进行广度优先遍历:param i: 节点的下标"""que = [] # 用列表模拟队列,存储已访问过的节点# 输出节点信息print(self.vertex_list[i], end=' -> ')# 标记节点为已访问self.is_visited[i] = Trueque.append(i) # 将已访问过的节点的下标加入队列while que: # 队列不为空,对节点i的广度优先遍历就继续# 取出队头节点的下标uu = que.pop(0)# 获取节点u的第一个邻接节点的下标ww = self.get_first_neighbor(u)# 如果节点w存在while w != -1:# 如果节点w未被访问,则访问并将节点w入队if not self.is_visited[w]:print(self.vertex_list[w], end=' -> ')self.is_visited[w] = Trueque.append(w)# 查找节点u继节点w后的另一个邻接节点w = self.get_next_neighbor(u, w)def for_bfs(self):"""遍历所有顶点,看还有哪一个没有访问过,如果有,则从没有访问过的顶点开始广度优先遍历:return:"""for i in range(len(self.vertex_list)):if not self.is_visited[i]:self.bfs(i)def insert_vertex(self, vertex_val: str):"""添加顶点vertex_val: 顶点的值"""self.vertex_list.append(vertex_val)def insert_edge(self, v1: int, v2: int, weight: int = 0):"""添加边v1: 边的起始顶点的下标,从0开始v2: 边的结束顶点的下标,从0开始weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,AB之间存在边,所以weight=1"""# 因为是无向图,所以两个顶点对应的位置都要设置边self.edges[v1][v2] = weightself.edges[v2][v1] = weightself.num_edges += 1 # 边的数量加1def show_graph(self):"""遍历邻接矩阵"""for arr in self.edges:for i in arr:print(i, end=' ')print()def test_graph():n = 5vertex_arr = ['A', 'B', 'C', 'D', 'E']graph = Graph(n)# 向图中循环添加顶点for i in vertex_arr:graph.insert_vertex(i)# 添加边graph.insert_edge(0, 1, 1)graph.insert_edge(0, 2, 1)graph.insert_edge(1, 2, 1)graph.insert_edge(1, 3, 1)graph.insert_edge(1, 4, 1)# 显示图的邻接矩阵graph.show_graph()print("广度优先遍历:", end='')graph.for_bfs()test_graph()