86 阅读2分钟

图的概念及相关术语

概念

painting:用画刷画的油画

drawing:用硬笔画的素描/线条画

picture:真实形象所反映的画,如照片等,如take picture

image:由印象而来的画,遥感影像做image,因是经过传感器印象而来

figure:轮廓图的意思,某个侧面的轮廓,所以有figure out的说法

diagram:抽象的概念关系图,如电路图、海洋环流图、类层次图

chart:由数字统计来的柱状图、饼图、折线图

map:地图

plot:地图上的一小块

graph:重在由一些基本元素构造而来的图,如点、线段等

图Graph是比树更为一般的结构,也是由节点和边构成。实际上树是一种具有特殊性质的图,图可以用来表示现实世界中很多事物

术语介绍

顶点Vertex: (也称“节点Node”是图的基本组成部分,顶点具有名称标识Key,也可以携带数据项payload

边Edge: (也称"弧Arc"作为2个顶点之间关系的表示,边连接两个顶点;边可以是无向或者有向的,相应的图称作“无向图”和“有向图”

权重Weight: 为了表达从一个顶点到另一个顶点的“代价”,可以给边赋权;例如公交网络中两个站点之间的“距离”’、“通行时间”和“票价”都可以作为权重。

image.png

定义

图在数学中的定义可以是G=(V, E),其中V是顶点的集合,E是边的集合,E中的每条边e=(v, w),v和w都是V中的顶点;如果是赋权图,则可以在e中添加权重分量子图:V和E的子集

image.png

有向赋权图,权重为整数

V={V0,V1,V2,V3,V4,V5}V = \{V0,V1,V2,V3,V4,V5\}

E={(v0,v1,5),(v1,v2,4),(v2,v3,9),(v3,v4,7),(v4,v0,1),(v0,v5,2),(v5,v4,8),(v3,v5,3),(v5,v2,1)}E=\{ (v_0,v_1, 5), (v_1, v_2, 4), (v_2, v_3, 9), (v_3, v_4, 7), (v_4, v_0,1), (v_0, v_5, 2), (v_5, v_4, 8), (v_3, v_5, 3), (v_5, v_2, 1)\}

路径Path: 图中的路径,是由边依次连接起来的顶点序列;无权路径的长度为边的数量;带权路径的长度为所有边权重的和

image.png

圈Cycle: 圈是首尾顶点相同的路径,如果有向图中不存在任何圈,则称作“有向无圈图directed acyclic graph: DAG”

image.png

图的操作

Graph():创建一个空的图;

addVertex(vert):将顶点vert加入图中

addEdge(fromVert, toVert):添加有向边

addEdge ( fromVert,toVert, weight):添加带权的有向边

getVertex(vKey):查找名称为vKey的顶点

getVertices():返回图中所有顶点列表

in:按照vert in graph的语句形式, 返回顶点是否存在图中True/False

图的实现

ADT Graph的实现方法有两种主要形式:邻接矩阵adjacency matrix、邻接表adjacency list

两种方法各有优劣,需要在不同应用中加以选择

邻接矩阵

矩阵的每行和每列都代表图中的顶点。如果两个顶点之间有边相连,设定行列值

无权边则将矩阵分量标注为1,或者0;带权边则将权重保存为矩阵分量值

image.png

邻接矩阵实现法的优点是简单,可以很容易得到顶点是,如何相连,但如果图中的边数很少则效率低下,成为“稀疏sparse”矩阵,而大多数问题所对应的图都是稀疏的,边远远少于V2|V| ^2这个量级

邻接列表

邻接列表adjacency list可以成为稀疏图的更高效实现方案。维护一个包含所有顶点的主列表(master list),主列表中的每个顶点,再关联一个与自身有边连接的所有顶点的列表

image.png

邻接列表法的存储空间紧凑高效,很容易获得顶点所连接的所有顶点,以及连接边的信息

编程实现

Vertex包含了顶点信息,以及顶点连接边信息

class Vertex:
    def __init__(self, key):
        self.id = key
        self.connectedTo = {}

    def addNeighbor(self, nbr, weight = 0):
        self.connectedTo[nbr] = weight

    def __str__(self):
        return str(self.id) + 'connectedTo: ' + str([x.id for x in self.connectedTo])

    def getConnections(self):
        return self.connectedTo.keys()

    def getId(self):
        return self.id

    def getWeight(self, nbr):
        return self.connectedTo[nbr]

Graph保存了包含所有顶点的主表

class Graph:
    def __init__(self):
        self.vertList = {}
        self.numVertices = 0

    def addVertex(self, key):  # 新加顶点
        self.numVertices = self.numVertices + 1
        newVertex = Vertex(key)
        self.vertList[key] = newVertex
        return newVertex

    def getVertex(self, n):  # 通过key查找顶点
        if n in self.vertList:
            return self.vertList[n]
        else:
            return None

    def __contains__(self, n):
        return n in self.vertList
    
    def __contains__(self, n):
        return n in self.vertList

    def addEdge(self, f, t, cost = 0):
        if f not in self.vertList:
            nv = self.addVertex(f)
        if t not in self.vertList:
            nv = self.addVertex(t)
        self.vertList[f].addNeighbor(self.vertList[t], cost)
    
    def getVertices(self):
        return self.vertList.keys()
    
    def __iter__(self):
        return iter(self.vertList.values())