算法导论(22.1):图的表示

对图算法进行讨论需要引入一些约定。
给定 图G = (V, E)
当对此图上的算法的运行时间进行描述时,我们通常以
图的结点数|V| 和 边的条数|E|作为输入规模
仅在渐进记号中可用符号V、E代替
此外,伪码中用G.V表示图G的结点集,G.E表示图G的边集

两种表示方法

邻接链表和邻接矩阵,都可用于表示有向图和无向图。

邻接链表

通常使用邻接链表表示稀疏图,即 |E| << |V|^2 的图。

无论表示有向图还是无向图,邻接链表的存储空间需求都是 Θ(V+E)

邻接链表的一个缺陷是无法快速判断一条 边(u, v)是否存在于图中
唯一的办法是在邻接链表Adj[u]中查找结点v

邻接矩阵

通常使用邻接矩阵表示稠密图。

无论一个图有多少条边,邻接矩阵的存储空间需求都是 Θ(V^2)
在表示无向图时可利用压缩矩阵来存储,其存储空间需求减少为邻接矩阵需求的一半

邻接矩阵克服了上述邻接链表的缺陷,但付出的存储代价增大。

在图规模比较小时,一般用邻接矩阵表示法更优
一是较简单,二是每个记录项仅需1位空间

无向图

在这里插入图片描述

以2号结点为例,在图上与1 5 4 3 相连
则邻接链表中,代表2号结点的链表由指向1 5 4 3结点的指针组成
邻接矩阵为对称矩阵
其他类似

所有邻接链表的长度和等于 2|E|,因为每条边都被计算了两次

有向图

在这里插入图片描述

以2号结点为例
邻接链表中,边 (2, 5)的5结点出现在2的链表中,而边(4, 2)的2结点会出现在4的链表中
邻接矩阵中,坐标为(2, 5)即代表边(2, 5)
其他类似

所有邻接链表的长度等于|E|,每条边在邻接链表表示法中仅计算一次

权重图

权重图是图中每条边都带有一个相关权重的图

用邻接链表表示时
边(u, v)的权重可以放在u的邻接链表里

用邻接矩阵表示时
边(u, v)的权重可以放在坐标为(u, v)的位置,如不存在则放None或0或…

图属性的表示

算法表示:如u.d表示结点u的属性d

程序实现:依赖因素较多。
如使用邻接链表表示图时,可以使用额外的数组表示结点属性。
如增设一个与Adj数组对应的数组d[1...|V|],如果与u邻接的结点都在Adj[u]中,则可将结点u的属性存放到d[u]的位置

原装Python实现

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author: 无名Joker
@time:2020/02/29
Purpose:
有向图和无向图的Python实现,每种图都使用邻接链表和邻接矩阵分别实现

Arguments:
Outputs:
本模块对外提供:
基于邻接链表的有向图类:DirectedGraphAL
基于邻接矩阵的有向图类:DirectedGraphAM
基于邻接链表的无向图类:UndirectedGraphAL
基于邻接矩阵的无向图类:UndirectedGraphAM

"""


# 基于邻接链表(AdjacencyList)的有向图(DirectedGraph)实现
class DirectedGraphAL:
    def __init__(self):
        # 使用字典内嵌集合的数据结构存放所有的邻接链表
        # 每个邻接链表以 结点名: {其他结点名, 其他结点名} 的形式存放
        self.adj = dict()

    # 返回本图中所有邻接链表的key,即结点名
    def get_vertices(self):
        all_vertex_key = list()
        for key in self.adj:
            all_vertex_key.append(key)
        return all_vertex_key

    # 向图中添加新结点,u为结点名
    def add_vertex(self, u):
        if u in self.adj:
            print("%r is already in the graph" % u)
        else:
            # 用set存放所有有向边(u, v)的v的结点名
            self.adj[u] = set()

    # 传入结点名,移除某结点及相关所有边
    def remove_vertex(self, u):
        if u not in self.adj:
            print("%r is not in the graph" % u)
        else:
            # 移除本结点
            del self.adj[u]
            # 移除其他结点和本结点的边
            for vtx in self.adj:
                if u in self.adj[vtx]:
                    self.adj[vtx].remove(u)

    # 增加一条有向边 (u, v)
    def add_edge(self, u, v):
        if u not in self.adj or v not in self.adj:
            print("at least one vertex is not in the graph, failed to add this edge")
        else:
            self.adj[u].add(v)

    # 移除有向边
    def remove_edge(self, u, v):
        if u not in self.adj or v not in self.adj:
            print("this edge doesn't exist, failed to remove it")
        else:
            self.adj[u].remove(v)

    # 返回某结点的所有邻接结点名
    def get_neighbors(self, u):
        if u not in self.adj:
            print("%r is not in the graph" % u)
        else:
            return self.adj[u]


# 基于邻接矩阵的有向图类
class DirectedGraphAM:
    def __init__(self):
        # 用二重字典做邻接矩阵的存储
        """格式如
        {
        '1': {'1': 0, '2': 1},
        '2': {'1': 1, '2': 0}
        }
        """
        self.matrix = dict()

    # 返回所有结点名称
    def get_vertices(self):
        all_vertex_key = list()
        for k in iter(self.matrix):
            all_vertex_key.append(k)
        return all_vertex_key

    # 添加结点
    def add_vertex(self, u):
        if u not in self.matrix:
            self.matrix[u] = dict()
        else:
            print("%r is already in the graph" % u)

    # 删除结点
    def remove_vertex(self, u):
        if u not in self.matrix:
            print("%r is not in the graph" % u)
        else:
            # 删除行
            del self.matrix[u]
            for v in self.matrix:
                # 删除列
                del self.matrix[v][u]

    # 初始化邻接矩阵
    def init_matrix(self):
        for u in self.matrix:
            for v in self.matrix:
                # 每个结点与其他结点的距离初始化为无穷
                self.matrix[u][v] = float("inf")

    # 添加有向边(u, v)
    def add_edge(self, u, v):
        if u not in self.matrix or v not in self.matrix:
            print("at least one vertex is not in the graph, failed to add this edge")
        else:
            self.matrix[u][v] = True

    # 删除有向边
    def remove_edge(self, u, v):
        if u not in self.matrix or v not in self.matrix:
            print("this edge doesn't exist, failed to remove it")
        else:
            self.matrix[u][v] = float("inf")

    # 返回某结点的所有邻接结点名,有向
    def get_neighbors(self, u):
        if u not in self.matrix:
            print("%r is not in the graph" % u)
        else:
            u_neighbors = list()
            for nb in self.matrix[u]:
                if self.matrix[u][nb] is True:
                    u_neighbors.append(nb)
            return u_neighbors


# 基于邻接链表的无向图
class UndirectedGraphAL(DirectedGraphAL):
    # 重写添加边的方法
    def add_edge(self, u, v):
        if u not in self.adj or v not in self.adj:
            print("at least one vertex is not in the graph, failed to add this edge")
        else:
            # 双向添加
            self.adj[u].add(v)
            self.adj[v].add(u)

    # 重写移除边的方法
    def remove_edge(self, u, v):
        if u not in self.adj or v not in self.adj:
            print("this edge doesn't exist, failed to remove it")
        else:
            self.adj[u].remove(v)
            self.adj[v].remove(u)


# 基于邻接矩阵的无向图
class UndirectedGraphAM(DirectedGraphAM):
    # 重写 添加无向边(u, v)
    def add_edge(self, u, v):
        if u not in self.matrix or v not in self.matrix:
            print("at least one vertex is not in the graph, failed to add this edge")
        else:
            self.matrix[u][v] = True
            self.matrix[v][u] = True

    # 重写 删除无向边
    def remove_edge(self, u, v):
        if u not in self.matrix or v not in self.matrix:
            print("this edge doesn't exist, failed to remove it")
        else:
            self.matrix[u][v] = float("inf")
            self.matrix[v][u] = float("inf")


if __name__ == '__main__':
    """
    # 1.基于邻接链表的有向图

    dgal = DirectedGraphAL()

    # 添加六个结点
    dgal.add_vertex("1")
    dgal.add_vertex("2")
    dgal.add_vertex("3")
    dgal.add_vertex("4")
    dgal.add_vertex("5")
    dgal.add_vertex("6")
    print(dgal.get_vertices())

    # 删除结点时一并删除相关所有边
    dgal.add_vertex("7")
    dgal.add_edge("6", "7")
    for ver in range(1, 7):
        print(str(ver), dgal.get_neighbors(str(ver)))
    print()
    dgal.remove_vertex("7")
    for ver in range(1, 7):
        print(str(ver), dgal.get_neighbors(str(ver)))
    print()

    # 添加有向边
    dgal.add_edge("1", "2")
    dgal.add_edge("1", "4")
    dgal.add_edge("2", "5")
    dgal.add_edge("3", "5")
    dgal.add_edge("3", "6")
    dgal.add_edge("4", "2")
    dgal.add_edge("5", "4")
    dgal.add_edge("6", "6")
    for ver in range(1, 7):
        print(str(ver), dgal.get_neighbors(str(ver)))
    print()
    
    # 删除有向边
    dgal.remove_edge("6", "6")
    for ver in range(1, 7):
        print(str(ver), dgal.get_neighbors(str(ver)))
    """

    """
    # 2.基于邻接矩阵的有向图
    dgam = DirectedGraphAM()
    dgam.add_vertex("1")
    dgam.add_vertex("2")
    dgam.add_vertex("3")
    dgam.add_vertex("4")
    dgam.add_vertex("5")
    dgam.add_vertex("6")

    print(dgam.get_vertices())

    print(dgam.matrix)
    dgam.init_matrix()
    for k in dgam.matrix:
        print(k, dgam.matrix[k])

    dgam.remove_vertex("1")
    for k in dgam.matrix:
        print(k, dgam.matrix[k])

    print(dgam.get_neighbors('4'))

    dgam.add_edge('4', '5')
    print(dgam.get_neighbors('4'))

    dgam.remove_edge('4', '5')
    print(dgam.get_neighbors('4'))
    """

    """
    # 3.基于邻接链表的无向图
    ugal = UndirectedGraphAL()
    ugal.add_vertex("1")
    ugal.add_vertex("2")
    ugal.add_vertex("3")

    # 添加无向边
    ugal.add_edge("1", "2")
    ugal.add_edge("1", "3")
    ugal.add_edge("2", "3")
    for ver in range(1, 4):
        print(str(ver), ugal.get_neighbors(str(ver)))
    print()

    # 删除无向边
    ugal.remove_edge("2", "3")
    for ver in range(1, 4):
        print(str(ver), ugal.get_neighbors(str(ver)))
    print()
    """

    """
    # 4.基于邻接矩阵的无向图
    ugam = UndirectedGraphAM()
    ugam.add_vertex("1")
    ugam.add_vertex("2")
    ugam.add_vertex("3")
    ugam.init_matrix()

    ugam.add_edge("1", "2")
    ugam.add_edge("1", "3")
    ugam.add_edge("2", "3")
    for k in ugam.matrix:
        print(k, ugam.matrix[k])
    print()

    ugam.remove_edge("2", "3")
    for k in ugam.matrix:
        print(k, ugam.matrix[k])
    print()
    """

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值