本篇学习笔记内容为图的各项性质、图的表示方法、图ADT的python实现
图(Graph)
是数据结构和算法学中最强大的框架之一(或许没有之一)。图几乎可以用来表现所有类型的结构或系统,从交通网络到通信网络,从下棋游戏到最优流程,从任务分配到人际交互网络,图都有广阔的用武之地。
我们会把图视为一种由“顶点”组成的抽象网络,网络中的各顶点可以通过“边”实现彼此的连接,表示两顶点有关联。我们要知道最基础最基本的2个概念,顶点(vertex)和边(edge)。
图可以分为有向图和无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。
首先是链表、树与图的对比图:
圆为顶点、线为边
图的术语
图 G 是顶点V 和边 E的集合
两个顶点之间:边
如果顶点 x 和 y 共享边,则它们相邻,或者它们是相邻的
无向图 :无向图中的一个边可以在任一方向上遍历
路径::通过边连接的顶点序列
周期:第一个和最后一个顶点相同的路径
入度::顶点的度数V是以V为端点的边数
出度: 顶点的出度v是以v为起点的边的数量
度:顶点的度数是其入度和出度的总和
图的ADT
数据成员 :
顶点 (vertex)
边缘 (edge)
操作 :
有多少顶点?
有多少个边缘?
添加一个新的顶点
添加一个新的边缘
获取所有邻居? (进出)
U,V连接吗?
反转所有边缘?
获取2跳邻居
图表示法:邻接矩阵
classVertex:def __init__(self, node):
self.id=node#Mark all nodes unvisited
self.visited =FalsedefaddNeighbor(self, neighbor, G):
G.addEdge(self.id, neighbor)defgetConnections(self, G):returnG.adjMatrix[self.id]defgetVertexID(self):returnself.iddefsetVertexID(self, id):
self.id=iddefsetVisited(self):
self.visited=Truedef __str__(self):returnstr(self.id)classGraph:def __init__(self, numVertices=10, directed=False):
self.adjMatrix= [[None] * numVertices for _ inrange(numVertices)]
self.numVertices=numVertices
self.vertices=[]
self.directed=directedfor i inrange(0, numVertices):
newVertex=Vertex(i)
self.vertices.append(newVertex)def addVertex(self, vtx, id): #增加点,这个function没有扩展功能
if 0 <= vtx
self.vertices[vtx].setVertexID(id)defgetVertex(self, n):for vertxin inrange(0, self.numVertices):if n ==self.vertices[vertxin].getVertexID():returnvertxinreturnNonedef addEdge(self, frm, to, cost=0): #返回全部连线/航线
#print("from",frm, self.getVertex(frm))
#print("to",to, self.getVertex(to))
if self.getVertex(frm) is not None and self.getVertex(to) is notNone:
self.adjMatrix[self.getVertex(frm)][self.getVertex(to)]=costif notself.directed:#For directed graph do not add this
self.adjMatrix[self.getVertex(to)][self.getVertex(frm)] =costdefgetVertices(self):
vertices=[]for vertxin inrange(0, self.numVertices):
vertices.append(self.vertices[vertxin].getVertexID())returnverticesdefprintMatrix(self):for u inrange(0, self.numVertices):
row=[]for v inrange(0, self.numVertices):
row.append(str(self.adjMatrix[u][v])if self.adjMatrix[u][v] is not None else '/')print(row)defgetEdges(self):
edges=[]for v inrange(0, self.numVertices):for u inrange(0, self.numVertices):if self.adjMatrix[u][v] is notNone:
vid=self.vertices[v].getVertexID()
wid=self.vertices[u].getVertexID()
edges.append((vid, wid, self.adjMatrix[u][v]))returnedgesdefgetNeighbors(self, n):
neighbors=[]for vertxin inrange(0, self.numVertices):if n ==self.vertices[vertxin].getVertexID():for neighbor inrange(0, self.numVertices):if (self.adjMatrix[vertxin][neighbor] is notNone):
neighbors.append(self.vertices[neighbor].getVertexID())returnneighborsdefisConnected(self, u, v):
uidx=self.getVertex(u)
vidx=self.getVertex(v)return self.adjMatrix[uidx][vidx] is notNonedef get2Hops(self, u): #转一次机可以到达哪里
neighbors =self.getNeighbors(u)print(neighbors)
hopset=set()for v inneighbors:
hops=self.getNeighbors(v)
hopset|=set(hops)return list(hopset)
图表示法:邻接表
用邻接矩阵来表示,每一行表示一个节点与其他所有节点是否相连,但对于邻接表来说,一行只代表和他相连的节点:
可见邻接表在空间上是更省资源的。
邻接表适合表示稀疏图,邻接矩阵适合表示稠密图。
importsysclassVertex:def __init__(self, node):
self.id=node
self.adjacent={}#为所有节点设置距离无穷大
self.distance =sys.maxsize#标记未访问的所有节点
self.visited =False#Predecessor
self.previous =Nonedef addNeighbor(self, neighbor, weight=0):
self.adjacent[neighbor]=weight#returns a list
def getConnections(self): #neighbor keys
returnself.adjacent.keys()defgetVertexID(self):returnself.iddefgetWeight(self, neighbor):returnself.adjacent[neighbor]defsetDistance(self, dist):
self.distance=distdefgetDistance(self):returnself.distancedefsetPrevious(self, prev):
self.previous=prevdefsetVisited(self):
self.visited=Truedef __str__(self):return str(self.id) + 'adjacent:' + str([x.id for x inself.adjacent])def __lt__(self, other):return self.distance < other.distance and self.id
#value is Vertex
self.vertDictionary ={}
self.numVertices=0
self.directed=directeddef __iter__(self):returniter(self.vertDictionary.values())defisDirected(self):returnself.directeddefvectexCount(self):returnself.numVerticesdefaddVertex(self, node):
self.numVertices= self.numVertices + 1newVertex=Vertex(node)
self.vertDictionary[node]=newVertexreturnnewVertexdefgetVertex(self, n):if n inself.vertDictionary:returnself.vertDictionary[n]else:returnNonedef addEdge(self, frm, to, cost=0):if frm not inself.vertDictionary:
self.addVertex(frm)if to not inself.vertDictionary:
self.addVertex(to)
self.vertDictionary[frm].addNeighbor(self.vertDictionary[to], cost)if notself.directed:#For directed graph do not add this
self.vertDictionary[to].addNeighbor(self.vertDictionary[frm], cost)defgetVertices(self):returnself.vertDictionary.keys()defsetPrevious(self, current):
self.previous=currentdefgetPrevious(self, current):returnself.previousdefgetEdges(self):
edges=[]for key, currentVert inself.vertDictionary.items():for nbr incurrentVert.getConnections():
currentVertID=currentVert.getVertexID()
nbrID=nbr.getVertexID()
edges.append((currentVertID, nbrID, currentVert.getWeight(nbr)))#tuple
returnedgesdefgetNeighbors(self, v):
vertex=self.vertDictionary[v]return vertex.getConnections()