邻接表与邻接矩阵

介绍

邻接表和邻接矩阵是图的两种常用存储表示方式,用于记录图中任意两个顶点之间的连通关系,包括权值。

对于图 G = ( V , E ) G=(V, E) G=(V,E)而言,其中 V V V表示顶点集合, E E E表示边集合。

对于无向图 g r a p h graph graph,图的顶点集合和边集合如下:
V = 1 , 2 , 3 , 4 , 5 V = {1,2,3,4,5} V=1,2,3,4,5
E = ( 1 , 2 ) , ( 1 , 3 ) , ( 1 , 4 ) , ( 2 , 3 ) , ( 3 , 4 ) , ( 3 , 5 ) E ={(1,2),(1,3),(1,4),(2,3),(3,4),(3,5)} E=(1,2),(1,3),(1,4),(2,3),(3,4),(3,5)
在这里插入图片描述
对于有向图 d i g r a p h digraph digraph,图的顶点集合和边集合如下:
V = 1 , 2 , 3 , 4 , 5 V = {1,2,3,4,5} V=1,2,3,4,5
E = < 1 , 2 > , < 1 , 3 > , < 1 , 4 > , < 2 , 3 > , < 3 , 1 > , < 3 , 5 > , < 4 , 3 > E ={<1,2>,<1,3>,<1,4>,<2,3>,<3,1>,<3,5>,<4,3>} E=<1,2>,<1,3>,<1,4>,<2,3>,<3,1>,<3,5>,<4,3>
在这里插入图片描述

邻接表

无向图 g r a p h graph graph 表示
在这里插入图片描述
有向图 d i g r a p h digraph digraph 表示
在这里插入图片描述
若采用邻接表表示,则需要申请 ∣ V ∣ |V| V 个列表,每个列表存储一个顶点出发的所有相邻顶点。如果图 G G G 为有向图,则 个列表存储的总顶点个数为 ∣ E ∣ |E| E ;如果图 G G G 为无向图,则 ∣ V ∣ |V| V 个列表存储的总顶点个数为 ∣ 2 E ∣ |2E| ∣2E(暂不考虑自回路)。因为需要申请大小为 ∣ V ∣ |V| V 的数组来保存节点,对节点分配序号,所以需要申请大小为 ∣ V ∣ |V| V 的额外存储空间,即邻接表方式的存储空间复杂度为 O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E)

邻接矩阵

无向图 g r a p h graph graph 表示
在这里插入图片描述
有向图 d i g r a p h digraph digraph 表示
在这里插入图片描述
若采用邻接矩阵表示,则需要申请空间大小为 ∣ V ∣ 2 |V|^2 V2 的二维数组,在二位数组中保存每两个顶点之间的连通关系,则无论有向图或无向图,邻接矩阵方式的存储空间复杂度皆为 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2) 。若只记录图中顶点是否连通,不记录权值大小,则可以使用一个二进制位来表示二维数组的每个元素,并且根据无向图的特点可知,无向图的邻接矩阵沿对角线对称,所以可以选择记录一半邻接矩阵的形式来节省空间开销。

示例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

两种存储结构对比

邻接矩阵 VS 邻接表 :
邻接矩阵的大小只与节点数量有关,即 N 2 N^2 N2 ,其中 N N N 为节点数量。因此,当边数量明显少于节点数量时,使用邻接矩阵存储图会造成较大的内存浪费。
因此,邻接表 适合存储稀疏图(顶点较多、边较少); 邻接矩阵 适合存储稠密图(顶点较少、边较多)。

代码附录

邻接表结构

# graph node definition
class Node(object):
    def __init__(self, index, weight, next = None):
        self.index = index
        self.weight = weight
        self.next = next

# adjacency list definition
class AdjacencyList(object):
    def __init__(self, number):
        self.number = number
        self.list = [None] * number

    # insert node
    def insert(self, origin, index, weight = 1):
        node = Node(index, weight, self.list[origin - 1])
        self.list[origin - 1] = node

测试代码:

if __name__ == '__main__':
    graph = AdjacencyList(5)
    graph.insert(1, 2)
    graph.insert(1, 3)
    graph.insert(1, 4)
    graph.insert(2, 3)
    graph.insert(3, 1)
    graph.insert(3, 5)
    graph.insert(4, 3)
    for i in range(graph.number):
        print('node', (i + 1), 'links:', end = ' ')
        node = graph.list[i]
        while node:
            print(node.index, end = ' ')
            node = node.next
        print()

输出结果:

node 1 links: 4 3 2 
node 2 links: 3 
node 3 links: 5 1 
node 4 links: 3 
node 5 links: 

邻接矩阵结构

# adjacency list definition
class AdjacencyMatrix(object):
    def __init__(self, number):
        self.number = number
        self.list = [[None] * number for i in range(number)]

    # insert node
    def insert(self, origin, index, weight = 1):
        self.list[origin - 1][index - 1] = weight

测试代码:

if __name__ == '__main__':
    graph = AdjacencyMatrix(5)
    graph.insert(1, 2)
    graph.insert(1, 3)
    graph.insert(1, 4)
    graph.insert(2, 3)
    graph.insert(3, 1)
    graph.insert(3, 5)
    graph.insert(4, 3)
    for i in range(graph.number):
        print('node', (i + 1), 'links:', end = ' ')
        j = 0
        while j < graph.number:
            print(j + 1, end = ' ') if graph.list[i][j] else None
            j += 1
        print()

输出结果:

node 1 links: 2 3 4 
node 2 links: 3 
node 3 links: 1 5 
node 4 links: 3 
node 5 links: 

猜你喜欢

转载自blog.csdn.net/weixin_54546190/article/details/125796835
今日推荐