1. 程式人生 > >python數據結構之圖論

python數據結構之圖論

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數據結構之圖論