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: #若待查詢(xún)頂點(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)文章
python實(shí)現(xiàn)進(jìn)度條的多種實(shí)現(xiàn)
這篇文章主要介紹了python實(shí)現(xiàn)進(jìn)度條的多種實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
python中文分詞+詞頻統(tǒng)計(jì)的實(shí)現(xiàn)步驟
詞頻統(tǒng)計(jì)就是輸入一段句子或者一篇文章,然后統(tǒng)計(jì)句子中每個(gè)單詞出現(xiàn)的次數(shù),下面這篇文章主要給大家介紹了關(guān)于python中文分詞+詞頻統(tǒng)計(jì)的相關(guān)資料,需要的朋友可以參考下2022-06-06
python爬蟲(chóng)之生活常識(shí)解答機(jī)器人
這篇文章主要介紹了python爬蟲(chóng)之生活常識(shí)解答機(jī)器人,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
Python使用sftp實(shí)現(xiàn)上傳和下載功能(實(shí)例代碼)
在Python中可以使用paramiko模塊中的sftp登陸遠(yuǎn)程主機(jī),實(shí)現(xiàn)上傳和下載功能。接下來(lái)通過(guò)本文給大家介紹Python使用sftp實(shí)現(xiàn)上傳和下載功能,需要的朋友參考下2017-03-03
Python?Asyncio中Coroutines,Tasks,Future可等待對(duì)象的關(guān)系及作用
這篇文章主要介紹了Python?Asyncio中Coroutines,Tasks,Future可等待對(duì)象的關(guān)系及作用,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,需要的小伙伴可以參考一下2022-06-06
Python使用captcha制作驗(yàn)證碼的實(shí)現(xiàn)示例
本文主要介紹了Python使用captcha制作驗(yàn)證碼的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08

