Python如何自定義鄰接表圖類(lèi)
Python自定義鄰接表圖類(lèi)
圖抽象數(shù)據(jù)類(lèi)型(ADT)的術(shù)語(yǔ)
頂點(diǎn)(Vertex):也稱(chēng)節(jié)點(diǎn)(node),是圖的基礎(chǔ)部分。具有名稱(chēng)標(biāo)識(shí)“key”。頂點(diǎn)也可以有附加信息項(xiàng)“playload”。
邊(Edge):也稱(chēng)弧(arc),也是圖的基礎(chǔ)組成部分。如果一條邊連接兩個(gè)頂點(diǎn),則表示兩者具有聯(lián)系。邊可以是單向的,也可以是雙向的。如果圖中的邊都是單向的,則稱(chēng)這個(gè)圖是“有向圖(directed graph/digraph)”。
權(quán)重(Weight):為了表達(dá)從一個(gè)頂點(diǎn)到另一個(gè)頂點(diǎn)的“代價(jià)”,可以給邊賦權(quán)。
路徑(Path):圖中的路徑,是由邊依次連接起來(lái)的頂點(diǎn)序列。無(wú)權(quán)路徑的長(zhǎng)度為邊的數(shù)量。帶權(quán)路徑的長(zhǎng)度為所有邊的權(quán)重之和。
圈(Cycle):有向圖里的圈是首尾頂點(diǎn)相同的路徑。沒(méi)有圈的圖稱(chēng)為“無(wú)圈圖(acyclic graph)”,沒(méi)有圈的有向圖稱(chēng)為“有向無(wú)圈圖(directed acyclic graph 或 DAG)”。
實(shí)現(xiàn)圖的兩個(gè)著名方法:鄰接矩陣(adjacency matrix)和鄰接表(adjacency list)。
鄰接矩陣和鄰接表的優(yōu)缺點(diǎn)
二維矩陣中,每行和每列都代表圖中的頂點(diǎn)。如果頂點(diǎn)v到頂點(diǎn)w之間有邊相連,則將值儲(chǔ)存在矩陣的v行、w列。每一格的值代表了從頂點(diǎn)v到頂點(diǎn)w邊的權(quán)重。
鄰接矩陣的優(yōu)點(diǎn):是簡(jiǎn)單,然而,大部分的矩陣是空的,這種情況則稱(chēng)矩陣是“稀疏”的。矩陣并不是一個(gè)儲(chǔ)存稀疏數(shù)據(jù)的有效途徑。
實(shí)現(xiàn)稀疏圖的更高效方法是使用鄰接表(adjacency list)。
在這個(gè)實(shí)現(xiàn)方法中,包含一個(gè)含有所有頂點(diǎn)的主列表(master list),主列表中的每個(gè)頂點(diǎn),再關(guān)聯(lián)一個(gè)與自身有邊連接的所有頂點(diǎn)的列表。
在實(shí)現(xiàn)頂點(diǎn)類(lèi)的方法中使用字典而不是列表,字典中的鍵(key)對(duì)應(yīng)頂點(diǎn),值(value)則保存頂點(diǎn)連接邊的權(quán)重。
鄰接表的優(yōu)點(diǎn):是能高效地表示一個(gè)稀疏圖。鄰接表還能很容易的找到某個(gè)頂點(diǎn)與其他頂點(diǎn)的所有連接。
自定義頂點(diǎn)類(lèi)
class Vertex(object): # 初始化頂點(diǎn) def __init__(self, key): self.id = key #初始化頂點(diǎn)的鍵 self.connectedTo = {} #初始化頂點(diǎn)的值 # 添加鄰居頂點(diǎn),參數(shù)nbr是鄰居頂點(diǎn)的鍵,默認(rèn)權(quán)重為0 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]) # 獲取該頂點(diǎn)所有鄰居頂點(diǎn)的鍵 def getConnections(self): return self.connectedTo.keys() # 獲取頂點(diǎn)的鍵 def getId(self): return self.id # 獲取到某鄰居頂點(diǎn)的權(quán)重 def getWeight(self, nbr): return self.connectedTo[nbr] # 自定義圖類(lèi) class Graph(object): # 初始化圖 def __init__(self): self.vertList = {} #初始化鄰接表 self.numVertices = 0 #初始化頂點(diǎn)數(shù) # 添加頂點(diǎn) def addVertex(self, key): newVertex = Vertex(key) #創(chuàng)建頂點(diǎn) self.vertList[key] = newVertex #將新頂點(diǎn)添加到鄰接表中 self.numVertices = self.numVertices + 1 #鄰接表中頂點(diǎn)數(shù)+1 return newVertex # 獲取頂點(diǎn) def getVertex(self, n): if n in self.vertList: #若待查詢頂點(diǎn)在鄰接表中,則 return self.vertList[n] #返回該頂點(diǎn) else: return None # 使之可用in方法 def __contains__(self, n): return n in self.vertList # 添加邊,參數(shù)f為起始頂點(diǎn)的鍵,t為目標(biāo)頂點(diǎn)的鍵,cost為權(quán)重 def addEdge(self, f, t, cost=0): if f not in self.vertList: #起始頂點(diǎn)不在鄰接表中,則 self.addVertex(f) #添加起始頂點(diǎn) if t not in self.vertList: #目標(biāo)頂點(diǎn)不在鄰接表中,則 self.addVertex(t) #添加目標(biāo)頂點(diǎn) self.vertList[f].addNeighbor(self.vertList[t], cost)#在鄰接表中添加起始點(diǎn)的目標(biāo)點(diǎn)及權(quán)重 # 獲取鄰接表中所有頂點(diǎn)的鍵 def getVertices(self): return self.vertList.keys() # 迭代顯示鄰接表的每個(gè)頂點(diǎn)的鄰居節(jié)點(diǎn) def __iter__(self): return iter(self.vertList.values()) g = Graph() #實(shí)例化圖類(lèi) for i in range(6): g.addVertex(i) #給鄰接表添加節(jié)點(diǎn) print(g.vertList) #打印鄰接表 g.addEdge(0, 1, 5) #給鄰接表添加邊及權(quán)重 g.addEdge(0, 5, 2) g.addEdge(1, 2, 4) g.addEdge(2, 3, 9) g.addEdge(3, 4, 7) g.addEdge(3, 5, 3) g.addEdge(4, 0, 1) g.addEdge(5, 4, 8) g.addEdge(5, 2, 1) for v in g: #循環(huán)每個(gè)頂點(diǎn) for w in v.getConnections(): #循環(huán)每個(gè)頂點(diǎn)的所有鄰居節(jié)點(diǎn) print("(%s, %s)" % (v.getId(), w.getId())) #打印頂點(diǎn)和其鄰居節(jié)點(diǎn)的鍵
結(jié)果為:
{0: <__main__.Vertex object at 0x00000000021BF828>, 1: <__main__.Vertex object at 0x00000000021BF860>, 2: <__main__.Vertex object at 0x00000000021BF898>, 3: <__main__.Vertex object at 0x00000000021BF8D0>, 4: <__main__.Vertex object at 0x00000000021BF908>, 5: <__main__.Vertex object at 0x00000000021BF940>}
(0, 1)
(0, 5)
(1, 2)
(2, 3)
(3, 4)
(3, 5)
(4, 0)
(5, 4)
(5, 2)
python圖的鄰接表表示
我就廢話不多說(shuō)了,上代碼
"""圖的鄰接表表示""" class GraphNode(object): """節(jié)點(diǎn)類(lèi)""" def __init__(self,_elem=None): self._elem = _elem # 數(shù)據(jù)域 self._next = None # 指針域 class Graph(object): """圖類(lèi)""" def __init__(self): """初始化一個(gè)序列""" self._graph = [] def createPeak(self,newNode): """創(chuàng)建一個(gè)圖頂點(diǎn)""" self._graph.append(newNode) return self._graph def createSide(self): """創(chuàng)建圖的邊""" for node in self._graph: graphNode = node print(f"請(qǐng)輸入{graphNode._elem}的鄰接點(diǎn),以-1結(jié)束") while True: _graphNode = GraphNode() # 初始化每個(gè)節(jié)點(diǎn)的鄰接點(diǎn) end = input("請(qǐng)輸入: ") if end == '-1': self.printGraph() break else: """臨時(shí)列表圖中的節(jié)點(diǎn)值,用來(lái)后續(xù)判斷""" temp = [] for item in self._graph: temp.append(item._elem) if end not in temp: """輸入的鄰接節(jié)點(diǎn)不在頂點(diǎn)中""" print("輸入的節(jié)點(diǎn)不屬于圖中的頂點(diǎn),重新輸入") continue elif end == graphNode._elem: """輸入的頂點(diǎn)就是當(dāng)前頂點(diǎn)""" print("輸入的是當(dāng)前節(jié)點(diǎn),重新輸入") continue else: # 新建節(jié)點(diǎn) _graphNode._elem = end # 指針向后移 _graphNode._next = graphNode._next graphNode._next = _graphNode graphNode = graphNode._next def printGraph(self): """遍歷當(dāng)前節(jié)點(diǎn)列表""" for node in self._graph: print(f"頂點(diǎn){node._elem}的鄰接鏈表: ",end='') while node != None: if node._next != None: print(f'{node._elem}-->',end='') else: print(f'{node._elem}', end='') node = node._next print() # 換節(jié)點(diǎn),換行 if __name__ == '__main__': count = int(input('請(qǐng)輸入頂點(diǎn)個(gè)數(shù): ')) s = Graph() # 創(chuàng)建節(jié)點(diǎn) peakNodeStr = input('請(qǐng)輸入頂點(diǎn): ') peakNodes = peakNodeStr.split(' ') # 將輸入的節(jié)點(diǎn)實(shí)例化之后添加到圖的鏈表中 for peakNode in peakNodes: peak = GraphNode(peakNode) s.createPeak(peak) print('圖中的節(jié)點(diǎn):',end='') for peak in s._graph: print(peak._elem,end=' ') print() # 創(chuàng)建邊 s.createSide()
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
用sqlalchemy構(gòu)建Django連接池的實(shí)例
今天小編就為大家分享一篇用sqlalchemy構(gòu)建Django連接池的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-08-08使用matplotlib畫(huà)散點(diǎn)圖的方法
今天小編就為大家分享一篇使用matplotlib畫(huà)散點(diǎn)圖的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Python爬取當(dāng)當(dāng)、京東、亞馬遜圖書(shū)信息代碼實(shí)例
這篇文章主要介紹了Python爬取當(dāng)當(dāng)、京東、亞馬遜圖書(shū)信息代碼實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12cmd運(yùn)行python文件時(shí)對(duì)結(jié)果進(jìn)行保存的方法
今天小編就為大家分享一篇cmd運(yùn)行python文件時(shí)對(duì)結(jié)果進(jìn)行保存的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Python元類(lèi)編程實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ORM
本文主要介紹了Python元類(lèi)編程實(shí)現(xiàn)一個(gè)簡(jiǎn)單的ORM,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03基于Keras的格式化輸出Loss實(shí)現(xiàn)方式
這篇文章主要介紹了基于Keras的格式化輸出Loss實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06django處理select下拉表單實(shí)例(從model到前端到post到form)
這篇文章主要介紹了django處理select下拉表單實(shí)例(從model到前端到post到form),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03Python MySQL 日期時(shí)間格式化作為參數(shù)的操作
這篇文章主要介紹了Python MySQL 日期時(shí)間格式化作為參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03TensorFlow神經(jīng)網(wǎng)絡(luò)創(chuàng)建多層感知機(jī)MNIST數(shù)據(jù)集
這篇文章主要為大家介紹了TensorFlow神經(jīng)網(wǎng)絡(luò)如何創(chuàng)建多層感知機(jī)MNIST數(shù)據(jù)集的實(shí)現(xiàn)過(guò)程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-11-11