📅  最后修改于: 2023-12-03 14:54:56.160000             🧑  作者: Mango
在计算机科学中,图是一种非常有用的数据结构,它由节点(或称为顶点)和连接这些节点的边组成。图在各种应用场景中都有广泛的应用,例如社交网络、物流路线规划等等。
图可以通过多种方式来表示,其中最常用的两种是邻接矩阵和邻接表。
邻接矩阵是一个二维数组,其中每个元素代表两个节点之间是否存在一条边。
# 一个邻接矩阵的例子
graph = [
[0, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 1],
[0, 1, 1, 0]
]
在上面的例子中,节点1和节点2之间有一条边,节点2和节点4之间有一条边,其余的节点之间没有边。
邻接表是一个字典,其中每个键代表一个节点,值则是一个列表,列表中包含了该节点所连接的所有节点。
# 一个邻接表的例子
graph = {
1: [2, 3],
2: [1, 4],
3: [1, 4],
4: [2, 3],
}
在上面的例子中,节点1和节点2之间有一条边,节点2和节点4之间有一条边,其余的节点之间没有边。
图的问题2,也称为图的二分问题,指的是将图中的节点分成两个独立的集合,并使同一集合中的节点没有边相连。如果图无法被二分,则说明此图不是二分图。
例如,下图是一个二分图的例子:
我们可以将图中的所有节点分成两个独立的集合:
可以看出,被分在同一集合的节点之间没有边相连,因此这是一个二分图。
我们可以使用深度优先搜索(DFS)来进行判断,判断的过程中需要将节点分成两个集合,并保证同一集合中的节点没有边相连。
def isBipartite(graph):
"""
:type graph: List[List[int]]
:rtype: bool
"""
# 首先将所有节点标记为未访问
# 这里使用字典来实现,键为节点编号,值为'U'表示未访问
# 'A'和'B'表示节点属于哪个集合
status = {i: 'U' for i in range(len(graph))}
# 递归地遍历每个节点
for i in range(len(graph)):
if status[i] == 'U':
if not dfs(graph, status, i, 'A'):
return False
return True
def dfs(graph, status, node, group):
# 如果该节点已经被访问过了,判断它是否属于同一集合
if status[node] != 'U':
return status[node] == group
# 标记该节点为当前集合
status[node] = group
# 递归处理该节点相邻的节点
for neighbor in graph[node]:
if not dfs(graph, status, neighbor, 'B' if group == 'A' else 'A'):
return False
return True
在上面的代码中,我们首先初始化一个字典来存储每个节点的状态(未访问、属于集合A、属于集合B),然后递归地遍历每个节点,在遍历过程中进行深度优先搜索。
对于每一个节点,如果它还未被访问过,那么我们先将其标记为当前集合,然后递归处理它相邻的节点。如果递归过程中发现相邻的节点已经被访问过了,那么我们就需要判断它和当前节点是否属于同一集合。如果它们属于同一集合,则说明该图不是二分图。否则,我们将该节点标记为另一个集合,继续递归处理它相邻的节点。最终,如果每个节点都被访问过,并且没有相邻的节点属于同一集合,那么该图就是一个二分图。
图是一种非常有用的数据结构,它可以用于各种应用场景,例如社交网络、物流路线规划等等。此外,图的二分问题也是一个非常重要的问题,它可以通过深度优先搜索来解决。在实际开发中,我们可以使用邻接矩阵或邻接表来表示图,并实现各种基本操作。