图结构
图由节点和边组成,包括有向图和无向图。
节点的构成:节点值、入度、出度、连接的边、邻居节点。
边的构成:出发节点、到达节点、节点。
class Node:
"""
节点结构
"""
def __init__(self, value: int):
self.value = value
self.in_degree = 0
self.out_degree = 0
self.next_nodes = []
self.edges = []
class Edge:
"""
边结构
"""
def __init__(self, weight: int, src: Node, dst: Node):
self.weight = weight
self.src = src
self.dst = dst
def __lt__(self, other):
"""
相当于比较器,为了排序用
:param other:
:return:
"""
if self.weight < other.weight:
return True
else:
return False
class Graph:
"""
图结构
"""
def __init__(self):
self.nodes = dict()
self.edges = set()
创建图
class GraphGenerator:
"""
创建图
"""
def createGraph(self, arr: List[List[int]]):
graph = Graph()
for i in range(len(arr)):
weight = arr[i][0]
src = arr[i][1]
dst = arr[i][2]
if src not in graph.nodes.keys():
graph.nodes[src] = Node(src)
if dst not in graph.nodes.keys():
graph.nodes[dst] = Node(dst)
src_node = graph.nodes.get(src)
dst_node = graph.nodes.get(dst)
edge = Edge(weight, src_node, dst_node)
graph.edges.add(edge)
src_node.out_degree += 1
dst_node.in_degree += 1
src_node.next_nodes.append(dst_node)
src_node.edges.append(edge)
return graph
图的遍历
广度优先搜索
class BFS:
"""
图的宽度优先遍历
"""
def bfs(self, start: Node):
"""
从start这个node出发,进行宽度优先遍历
:param start:
:return:
"""
if not start:
return
queue = list()
node_set = set()
queue.append(start)
node_set.add(start)
while queue:
cur = queue.pop(0)
print(cur.value)
for node in cur.next_nodes:
if node not in node_set:
node_set.add(node)
queue.append(node)
深度优先搜索
class DFS:
"""
图的深度优先遍历
"""
def dfs(self, start: Node):
"""
从start这个node出发,进行深度优先遍历
:param start:
:return:
"""
if not start:
return
stack = []
node_set = set()
stack.append(start)
node_set.add(start)
print(start.value)
while stack:
cur = stack.pop()
for node in cur.next_nodes:
if node not in node_set:
stack.append(cur)
stack.append(node)
node_set.add(node)
print(node.value)
break
图的拓扑排序
拓扑排序:即递归移除入度为0的节点。
class Record:
def __init__(self, n: DirectedGraphNode, o: int):
self.node = n
self.deep = o
class TopologicalOrder:
"""
图的拓扑排序
即递归移除入度为0的节点
"""
def dfs(self, graph: List[DirectedGraphNode]):
"""
深度优先拓扑
"""
def f(cur: DirectedGraphNode, order: Dict[DirectedGraphNode, Record]):
if cur in order.keys():
return order.get(cur)
follow = 0
for node in cur.neighbors:
follow = max(follow, f(node, order).deep)
ans = Record(cur, follow+1)
order[cur] = ans
order = dict()
for cur in graph:
f(cur, order)
recordArr = list()
for r in order.values():
recordArr.append(r)
recordArr.sort(key=lambda x: x.deep, reverse=False)
ans = list()
for r in recordArr:
ans.append(r)
return ans
def bfs(self, graph: List[DirectedGraphNode]):
"""
宽度优先拓扑
等同于sort方法,只是图结构不同
:param graph:
:return:
"""
in_degree_map = dict()
for cur in graph:
in_degree_map[cur] = 0
for cur in graph:
for nei_node in cur.neighbors:
in_degree_map[nei_node] = in_degree_map.get(nei_node) + 1
# 只有剩余入度为0的点,才进入这个队列
zero_queue = list()
for cur in in_degree_map.keys():
if in_degree_map[cur] == 0:
zero_queue.append(cur)
ans = list()
while zero_queue:
cur = zero_queue.pop(0)
ans.append(cur)
for node in cur.neighbors:
in_degree_map[node] = in_degree_map.get(node) - 1
if in_degree_map[node] == 0:
zero_queue.append(node)
return ans
def sort(self, graph: Graph):
# key 某个节点 value 剩余的入度
in_degree_dc = dict()
# 只有剩余入度为0的点,才进入这个队列
zero_queue = list()
for node in graph.nodes.values():
in_degree_dc[node] = node.in_degree
if node.in_degree == 0:
zero_queue.append(node)
res = list()
while zero_queue:
cur = zero_queue.pop(0)
res.append(cur)
for node in cur.next_nodes:
in_degree_dc[node] = in_degree_dc.get(node) - 1
if in_degree_dc.get(node) == 0:
zero_queue.append(node)
return res