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]
posted @ 2022-09-26 22:19  万国码aaa  阅读(228)  评论(0编辑  收藏  举报