1.图(Graph)
graph:重在由一些基本元素构造而来的图,如点、线段等
图(Graph)是比树更为一般的结构,也是由边节点和边构成。实际上,树是一种具有特殊性质的图
图可以用来表示现实世界中很多事物,如道路交通系统、航班线路、互联网连接、大学中课程的先修次序
2.图中常用术语
- 顶点Vertex(也称“节点Node”)
是图的基本组成部分,顶点具有名称标识key,也可以携带数据项payload - 边Edge(也称“弧Arc”)
作为2个顶点之间关系的表示,边连接两个顶点。边可以是无向或者有向的,相应的图称作“无向图”和“有向图” - 权重Weight
为了表达从一个顶点到另一个顶点的“代价”,可以给边赋权;假如公交网络中两个站点之间的“距离”、“通行时间”和“票价”都可以作为权重。
一个图G可以定义为G=(V,E)
其中V是顶点的集合,E是边的集合,E中的每条边e=(v,w),v和w都是V中的顶点;如果是赋权图,则可以在e中添加权重分量
下图为一个有向赋权图,权重为整数,有6个顶点及9条边 - 路径Path
图中的路径,是由边依次连接起来的顶点序列;无权路径的长度为边的数量;带权路径的长度为所有边权重的和。如下图的一条路径(v3,v4,v0,v1),路径长度为7+1+5=13 - 圈Cycle
圈是首尾顶点相同的路径,如下图中(v5,v2,v3,v5)是一个圈。如果有向图中不存在任何圈,则称作“有向无圈图(directed acyclic graph:DAG)”
3.抽象数据类型:ADT Graph
抽象数据类型ADT Graph定义如下:
- Graph():创建一个空图
- addVertex(vert):将顶点vert加入图中
- addEdge(fromVert,toVert):添加有向边
- addEdge(fromVert,toVert,weight):添加带权的有向边
- getVertex(vKey):查找名称为vKey的顶点
- getVertices():返回图中所有顶点列表
- in:按照vert in graph的语句形式,返回顶点是否存在图中True/False
4.ADT Graph的实现方法
ADT Graph的实现方法有两种主要形式:
(1)邻接矩阵adjacency matrix
(2)邻接表adjacency list
两种方法各有优劣,需要在不同应用中加以选择
4.1 邻接矩阵adjacency matrix
矩阵的每行和每列都代表图中的顶点。如果两个顶点之间有边相连,设定行列值。无权边则将矩阵分量标注为1或者0;带权便则将权重保存为矩阵分量值。
邻接矩阵实现法的优点是简单,可以很容易得到定点是如何相连的。但如果图中的边数很少,则效率低下,成为“稀疏(sparse)”矩阵。而大多数问题所对应的图都是稀疏的,边远远少于V2这个量级。
4.2 邻接列表Adjacency List
邻接列表Adjacency List可以成为稀疏图的更高效实现方案。维护一个包含所有顶点的主列表(master list),主列表中的每个顶点再关联一个与自身有边连接的所有顶点的列表。
临界列表法的存储空间紧凑高效,很容易获得顶点所连接的所有顶点,以及连接边的信息。
5.图抽象数据类型的python实现
5.1 ADT Graph的实现:顶点Vertex类
Vertex包含了顶点信息以及顶点连接边信息。
#顶点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]
5.2 ADT Graph的实现:图Graph类
Graph保存了包含所有顶点的主表
#Graph类
class Graph:
def __init__(self):
self.vertList={}
self.numVertices=0
#新加顶点
def addVertex(self,key):
self.numVertices=self.numVertices+1#顶点数加1
newVertex=Vertex(key)
self.vertList[key]=newVertex
return newVertex
#通过key查找顶点
def getVertex(self,n):
if n in self.vertList:
return self.vertList[n]
else:
return None
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())