python | 算法-图-邻接表,邻接矩阵以及自定义数据结构
针对b站视频左神算法与数据结构,自己练习对应的python代码
相关链接:
1️⃣b站视频地址
2️⃣视频笔记(其实主要是题目截图)
分类:有向图、无向图
存储:邻接表、邻接矩阵
1️⃣ 无向图+邻接表法,参考链接
# undirected graph -> 无向图
# Adjacency Lists -> 邻接表
# Implementation of an undirected graph using Adjacency Lists
class Vertex: # 节点数据结构
def __init__(self, n):
self.name = n # 节点的名字
self.neighbors = list() # 邻接点的集合
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph:
vertices = {} # 节点名字:节点 的映射
def add_vertex(self, vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices: # 输入对象是图节点的结构且还没有在字典里出现过
self.vertices[vertex.name] = vertex # 在字典里添加 节点名字:节点 的映射
return True
else:
return False
def add_edge(self, u, v): # 在图中添加新的边, u, v 是边的两个端点
if u in self.vertices and v in self.vertices: # 只有端点在点的集合里才可以添加该边
for key, value in self.vertices.items():
if key == u:
value.add_neighbor(v)
if key == v:
value.add_neighbor(u)
return True
else:
return False
def print_graph(self):
for key in sorted(list(self.vertices.keys())):
print(key + str(self.vertices[key].neighbors))
# 实例测试
g = Graph()
print(str(len(g.vertices)))
a = Vertex('A')
g.add_vertex(a)
g.add_vertex(Vertex('B'))
for i in range(ord('A'), ord('K')):
g.add_vertex(Vertex(chr(i)))
edges = ['AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI']
for edge in edges:
g.add_edge(edge[:1], edge[1:])
g.print_graph()
输出结果:
0 # 原始字典为空
A['E']
B['F']
C['G']
D['E', 'H']
E['A', 'D', 'H']
F['B', 'G', 'I', 'J']
G['C', 'F', 'J']
H['D', 'E', 'I']
I['F', 'H']
J['F', 'G']
2️⃣ 无向图+邻接矩阵法
import numpy as np
# 用list创建数组会有一些问题https://zhuanlan.zhihu.com/p/88197389
# 不如直接使用numpy工具,方便快捷
class Graph():
# 无向图的邻接矩阵表示法
def __init__(self):
self.vexs = [] # 点集
self.vexnum = 0 # 点数
self.edgnum= 0 # 边数
self.matrix = None # 邻接矩阵
def create_graph(self, vexs, edges):
# 需要输入点集vexs和边集edges
# 初始化图的点数和边数
self.vexnum = len(vexs)
self.edgnum = len(edges)
# 初始化邻接矩阵
self.matrix = np.zeros(shape=(self.vexnum, self.vexnum), dtype=int)
# 创建”点集“
for vex in vexs:
self.vexs.append(vex)
# 创建”边集“
for i in range(self.edgnum):
p1 = self.get_position(edges[i][0])
p2 = self.get_position(edges[i][1])
self.matrix[p1][p2] = 1
self.matrix[p2][p1] = 1
def get_position(self, ch):
# 返回顶点在矩阵中的位置
for position in range(self.vexnum):
if self.vexs[position] == ch:
return position
return -1
def print_graph(self):
# 输出该无向图的点集和邻接矩阵
print("该图点集:" + '\n' + str(self.vexs))
print("对应的邻接矩阵为:")
for i in range(self.vexnum):
print(str(self.matrix[i]))
if __name__ == '__main__':
# 给定点集
vexs = ['A', 'B', 'C', 'D', 'E']
# 给定边集
edges = [['A', 'B'],
['A', 'E'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['C', 'D'],
['D', 'E']]
# 实例化一个图g
g = Graph()
# 用给定的点集和边集创建一个图
g.create_graph(vexs, edges)
# 打印刚刚创建的图的邻接矩阵形式
g.print_graph()
# 该图点集:
# ['A', 'B', 'C', 'D', 'E']
# 对应的邻接矩阵为:
# [0 1 0 0 1]
# [1 0 1 1 1]
# [0 1 0 1 0]
# [0 1 1 0 1]
# [1 1 0 1 0]
3️⃣ 有向图+邻接表法
# 有向图-邻接表
class Vertex:
def __init__(self, n):
self.name = n
self.neighbors = list()
self.in_num = 0
self.out_num = 0
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph:
vertices = {}
def add_vertex(self, vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices:
self.vertices[vertex.name] = vertex
return True
else:
return False
def add_edge(self, v_from, v_to):
if v_from in self.vertices and v_to in self.vertices:
for key, value in self.vertices.items():
if key == v_from:
value.add_neighbor(v_to)
value.out_num += 1
if key == v_to:
value.in_num += 1
return True
else:
return False
def print_graph(self):
for key in sorted(list(self.vertices.keys())):
print(key+str(self.vertices[key].neighbors))
# 实例测试
g = Graph()
print(str(len(g.vertices)))
a = Vertex('A')
g.add_vertex(a)
g.add_vertex(Vertex('B'))
for i in range(ord('A'), ord('K')):
g.add_vertex(Vertex(chr(i)))
edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI']
for edge in edges:
g.add_edge(edge[:1], edge[1:])
g.print_graph()
输出结果:
# 0
# A['B', 'E']
# B['F']
# C['G']
# D['E', 'H']
# E['H']
# F['G', 'I', 'J']
# G['J']
# H['I']
# I[]
# J[]
4️⃣ 有向图+邻接矩阵
import numpy as np
# 用list创建数组会有一些问题https://zhuanlan.zhihu.com/p/88197389
# 不如直接使用numpy工具,方便快捷
class Graph():
# 无向图的邻接矩阵表示法
def __init__(self):
self.vexs = [] # 点集
self.vexnum = 0 # 点数
self.edgnum= 0 # 边数
self.matrix = None # 邻接矩阵
def create_graph(self, vexs, edges):
# 需要输入点集vexs和边集edges
# 初始化图的点数和边数
self.vexnum = len(vexs)
self.edgnum = len(edges)
# 初始化邻接矩阵
self.matrix = np.zeros(shape=(self.vexnum, self.vexnum), dtype=int)
# 创建”点集“
for vex in vexs:
self.vexs.append(vex)
# 创建”边集“
for i in range(self.edgnum):
p1 = self.get_position(edges[i][0])
p2 = self.get_position(edges[i][1])
self.matrix[p1][p2] = 1
def get_position(self, ch):
# 返回顶点在矩阵中的位置
for position in range(self.vexnum):
if self.vexs[position] == ch:
return position
return -1
def print_graph(self):
# 输出该无向图的点集和邻接矩阵
print("该图点集:" + '\n' + str(self.vexs))
print("对应的邻接矩阵为:")
for i in range(self.vexnum):
print(str(self.matrix[i]))
if __name__ == '__main__':
# 给定点集
vexs = ['A', 'B', 'C', 'D', 'E']
# 给定边集
edges = [['A', 'B'],
['A', 'E'],
['B', 'C'],
['B', 'D'],
['B', 'E'],
['C', 'D'],
['D', 'E']]
# 实例化一个图g
g = Graph()
# 用给定的点集和边集创建一个图
g.create_graph(vexs, edges)
# 打印刚刚创建的图的邻接矩阵形式
g.print_graph()
输出结果:
# 该图点集:
# ['A', 'B', 'C', 'D', 'E']
# 对应的邻接矩阵为:
# [0 1 0 0 1]
# [0 0 1 1 1]
# [0 0 0 1 0]
# [0 0 0 0 1]
# [0 0 0 0 0]
也可以创建自己顺手的数据结构,遇到实际问题就用接口函数转化为自己很熟悉的这个数据结构,然后再快速解决问题
# 参考: https://github.com/algorithmzuo/algorithmbasic2020/tree/master/src/class16
# 点结构的描述
class Node:
def __init__(self, value):
self.value = value
self.in_num = 0 # 入度
self.out_num = 0 # 出度
self.nexts = [] # 邻接点
self.edges = [] # 邻接边
# 边结构的描述
class Edge:
def __init__(self, weight, n_from, n_to):
self.weight = weight # 权重
self.n_from = n_from # 起点
self.n_to = n_to # 终点
# 图结构的描述
class Graph:
def __init__(self):
self.nodes = {} # 点集, 保存 点上值-点 的映射
self.edges = [] # 边集, 保存所有边信息
class GraphGenerator:
"""
这相当于一个接口函数,将各种条件统一转化为上面的图的结构,根据具体情况改写此类即可。
"""
# 下面是一个例子
# matrix -> 所有的边
# N*3的矩阵
# [weight, from节点上的值, to节点上的值]
#
# [5, 0, 7]
# [3, 0, 1]
#
def createGraph(self, matrix):
graph = Graph()
for i in range(len(matrix)):
weight = matrix[i][0]
n_from = matrix[i][1]
n_to = matrix[i][2]
if n_from not in graph.nodes.keys():
graph.nodes[n_from] = Node(n_from)
if n_to not in graph.nodes.keys():
graph.nodes[n_to] = Node(n_to)
fromNode = graph.nodes[n_from] # 起点
toNode = graph.nodes[n_to] # 终点
edge = Edge(weight, n_from, n_to) # 记录下该边的信息
fromNode.nexts.append(toNode) # 记录节点的邻接点信息
fromNode.out_num += 1 # 更新起点的出度
toNode.in_num += 1 # 更新终点的入度
fromNode.edges.append(edge) # 更新节点邻接边的信息
graph.edges.append(edge) # 更新图的边信息
return graph
# test
m = [[5, 0, 7], [3, 0, 1]]
g = GraphGenerator()
graph = g.createGraph(m)
print(str(graph.nodes.keys()))
for i in range(len(graph.edges)):
print(str([graph.edges[i].weight, graph.edges[i].n_from, graph.edges[i].n_to]))
# 输出结果
# dict_keys([0, 7, 1])
# [5, 0, 7]
# [3, 0, 1]