python數據結構之圖論
阿新 • • 發佈:2018-06-30
ict nodes print 我們 connect directed bubuko 數據結構 是否
本篇學習筆記內容為圖的各項性質、圖的表示方法、圖ADT的python實現
圖(Graph)
是數據結構和算法學中最強大的框架之一(或許沒有之一)。圖幾乎可以用來表現所有類型的結構或系統,從交通網絡到通信網絡,從下棋遊戲到最優流程,從任務分配到人際交互網絡,圖都有廣闊的用武之地。
我們會把圖視為一種由“頂點”組成的抽象網絡,網絡中的各頂點可以通過“邊”實現彼此的連接,表示兩頂點有關聯。我們要知道最基礎最基本的2個概念,頂點(vertex)和邊(edge)。
首先是鏈表、樹與圖的對比圖:
圓為頂點、線為邊
圖的術語
圖 G 是頂點V 和邊 E的集合
兩個頂點之間:邊
如果頂點 x 和 y 共享邊,則它們相鄰,或者它們是相鄰的
無向圖 :無向圖中的一個邊可以在任一方向上遍歷
路徑::通過邊連接的頂點序列
周期:第一個和最後一個頂點相同的路徑
入度::頂點的度數V是以V為端點的邊數
出度: 頂點的出度v是以v為起點的邊的數量
度:頂點的度數是其入度和出度的總和
圖的ADT
數據成員 :
頂點 (vertex)
邊緣 (edge)
操作 :
有多少頂點?
有多少個邊緣?
添加一個新的頂點
添加一個新的邊緣
獲取所有鄰居? (進出)
U,V連接嗎?
反轉所有邊緣?
獲取2跳鄰居
圖表示法:鄰接矩陣
class Vertex: def __init__(self, node): self.id= node # Mark all nodes unvisited self.visited = False def addNeighbor(self, neighbor, G): G.addEdge(self.id, neighbor) def getConnections(self, G): return G.adjMatrix[self.id] def getVertexID(self): return self.id def setVertexID(self, id): self.id= id def setVisited(self): self.visited = True def __str__(self): return str(self.id) class Graph: def __init__(self, numVertices=10, directed=False): self.adjMatrix = [[None] * numVertices for _ in range(numVertices)] self.numVertices = numVertices self.vertices = [] self.directed = directed for i in range(0, numVertices): newVertex = Vertex(i) self.vertices.append(newVertex) def addVertex(self, vtx, id): #增加點,這個function沒有擴展功能 if 0 <= vtx < self.numVertices: self.vertices[vtx].setVertexID(id) def getVertex(self, n): for vertxin in range(0, self.numVertices): if n == self.vertices[vertxin].getVertexID(): return vertxin return None def 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 not None: self.adjMatrix[self.getVertex(frm)][self.getVertex(to)] = cost if not self.directed: # For directed graph do not add this self.adjMatrix[self.getVertex(to)][self.getVertex(frm)] = cost def getVertices(self): vertices = [] for vertxin in range(0, self.numVertices): vertices.append(self.vertices[vertxin].getVertexID()) return vertices def printMatrix(self): for u in range(0, self.numVertices): row = [] for v in range(0, self.numVertices): row.append(str(self.adjMatrix[u][v]) if self.adjMatrix[u][v] is not None else ‘/‘) print(row) def getEdges(self): edges = [] for v in range(0, self.numVertices): for u in range(0, self.numVertices): if self.adjMatrix[u][v] is not None: vid = self.vertices[v].getVertexID() wid = self.vertices[u].getVertexID() edges.append((vid, wid, self.adjMatrix[u][v])) return edges def getNeighbors(self, n): neighbors = [] for vertxin in range(0, self.numVertices): if n == self.vertices[vertxin].getVertexID(): for neighbor in range(0, self.numVertices): if (self.adjMatrix[vertxin][neighbor] is not None): neighbors.append(self.vertices[neighbor].getVertexID()) return neighbors def isConnected(self, u, v): uidx = self.getVertex(u) vidx = self.getVertex(v) return self.adjMatrix[uidx][vidx] is not None def get2Hops(self, u): #轉一次機可以到達哪裏 neighbors = self.getNeighbors(u) print(neighbors) hopset = set() for v in neighbors: hops = self.getNeighbors(v) hopset |= set(hops) return list(hopset)
圖表示法:鄰接表
用鄰接矩陣來表示,每一行表示一個節點與其他所有節點是否相連,但對於鄰接表來說,一行只代表和他相連的節點:
可見鄰接表在空間上是更省資源的。
鄰接表適合表示稀疏圖,鄰接矩陣適合表示稠密圖。
import sys class Vertex: def __init__(self, node): self.id = node self.adjacent = {} #為所有節點設置距離無窮大 self.distance = sys.maxsize # 標記未訪問的所有節點 self.visited = False # Predecessor self.previous = None def addNeighbor(self, neighbor, weight=0): self.adjacent[neighbor] = weight # returns a list def getConnections(self): # neighbor keys return self.adjacent.keys() def getVertexID(self): return self.id def getWeight(self, neighbor): return self.adjacent[neighbor] def setDistance(self, dist): self.distance = dist def getDistance(self): return self.distance def setPrevious(self, prev): self.previous = prev def setVisited(self): self.visited = True def __str__(self): return str(self.id) + ‘ adjacent: ‘ + str([x.id for x in self.adjacent]) def __lt__(self, other): return self.distance < other.distance and self.id < other.id class Graph: def __init__(self, directed=False): # key is string, vertex id # value is Vertex self.vertDictionary = {} self.numVertices = 0 self.directed = directed def __iter__(self): return iter(self.vertDictionary.values()) def isDirected(self): return self.directed def vectexCount(self): return self.numVertices def addVertex(self, node): self.numVertices = self.numVertices + 1 newVertex = Vertex(node) self.vertDictionary[node] = newVertex return newVertex def getVertex(self, n): if n in self.vertDictionary: return self.vertDictionary[n] else: return None def addEdge(self, frm, to, cost=0): if frm not in self.vertDictionary: self.addVertex(frm) if to not in self.vertDictionary: self.addVertex(to) self.vertDictionary[frm].addNeighbor(self.vertDictionary[to], cost) if not self.directed: # For directed graph do not add this self.vertDictionary[to].addNeighbor(self.vertDictionary[frm], cost) def getVertices(self): return self.vertDictionary.keys() def setPrevious(self, current): self.previous = current def getPrevious(self, current): return self.previous def getEdges(self): edges = [] for key, currentVert in self.vertDictionary.items(): for nbr in currentVert.getConnections(): currentVertID = currentVert.getVertexID() nbrID = nbr.getVertexID() edges.append((currentVertID, nbrID, currentVert.getWeight(nbr))) # tuple return edges def getNeighbors(self, v): vertex = self.vertDictionary[v] return vertex.getConnections()
python數據結構之圖論