[英]Algorithm for counting connected components of a graph in Python
我嘗試編寫一個腳本來計算圖形的連接組件,但我無法獲得正確的解決方案。 我有一個帶有 6 個節點(頂點)的簡單圖,節點 1 和 2 相連,節點 3 和 4 相連(6 個頂點;1-2,3-4,5,6)。 因此該圖包含 4 個連通分量。 我使用以下腳本來計算連接的組件,但我得到錯誤的結果 (2)。
nodes = [[1, [2], False], [2, [1], False], [3, [4], False], [4, [3], False], [5, [], False], [6, [], False]]
# 6 nodes, every node has an id, list of connected nodes and boolean whether the node has already been visited
componentsCount = 0
def mark_nodes( list_of_nodes):
global componentsCount
componentsCount = 0
for node in list_of_nodes:
node[2] = False
mark_node_auxiliary( node)
def mark_node_auxiliary( node):
global componentsCount
if not node[2] == True:
node[2] = True
for neighbor in node[1]:
nodes[neighbor - 1][2] = True
mark_node_auxiliary( nodes[neighbor - 1])
else:
unmarkedNodes = []
for neighbor in node[1]:
if not nodes[neighbor - 1][2] == True: # This condition is never met. WHY???
unmarkedNodes.append( neighbor)
componentsCount += 1
for unmarkedNode in unmarkedNodes:
mark_node_auxiliary( nodes[unmarkedNode - 1])
def get_connected_components_number( graph):
result = componentsCount
mark_nodes( graph)
for node in nodes:
if len( node[1]) == 0: # For every vertex without neighbor...
result += 1 # ... increment number of connected components by 1.
return result
print get_connected_components_number( nodes)
任何人都可以幫我找出錯誤嗎?
不相交的數據結構將真正幫助您在此處編寫清晰的代碼,請參閱Wikipedia 。
基本思想是,將集合與圖形中的每個節點相關聯,並為每個邊合並其兩個端點的集合。 如果x.find() == y.find()
則兩組x
和y
相同
這是最幼稚的實現(最糟糕的情況是復雜性很差),但是在Wikipedia頁面上對DisjointSet類進行了一些優化,在上面的一些額外代碼行中使此效率更高。 為了清楚起見,我省略了它們。
nodes = [[1, [2]], [2, [1]], [3, [4]], [4, [3]], [5, []], [6, []]]
def count_components(nodes):
sets = {}
for node in nodes:
sets[node[0]] = DisjointSet()
for node in nodes:
for vtx in node[1]:
sets[node[0]].union(sets[vtx])
return len(set(x.find() for x in sets.itervalues()))
class DisjointSet(object):
def __init__(self):
self.parent = None
def find(self):
if self.parent is None: return self
return self.parent.find()
def union(self, other):
them = other.find()
us = self.find()
if them != us:
us.parent = them
print count_components(nodes)
有時,編寫代碼比閱讀代碼容易。
通過一些測試,我很確定只要每個連接都是雙向的(例如您的示例),它將一直有效。
def recursivelyMark(nodeID, nodes):
(connections, visited) = nodes[nodeID]
if visited:
return
nodes[nodeID][1] = True
for connectedNodeID in connections:
recursivelyMark(connectedNodeID, nodes)
def main():
nodes = [[[1], False], [[0], False], [[3], False], [[2], False], [[], False], [[], False]]
componentsCount = 0
for (nodeID, (connections, visited)) in enumerate(nodes):
if visited == False:
componentsCount += 1
recursivelyMark(nodeID, nodes)
print(componentsCount)
if __name__ == '__main__':
main()
請注意,我從節點信息中刪除了ID,因為它在數組中的位置就是其ID。 讓我知道該程序是否無法滿足您的需求。
我把我的答案放在這里是為了緩存我的學習。 我用深度優先搜索解決。
給定一個鄰接表,它的圖如下所示:
深度優先搜索,遞歸地接觸圖中的所有節點。 這部分很簡單:
count=0
# I touch all the nodes and if dfs returns True, count+=1
for node in graph:
if dfs(node):
count+=1
現在我們應該在 dfs 中編寫邏輯。 如果我們從節點 0 開始,我們將它標記為已訪問,然后我們訪問它的鄰居。 當我們訪問鄰居時,最終我們會訪問節點 2,如果我們到達節點 2,則意味着圖已連接,因此我們返回 True。
def dfs(node):
if node in visited:
return False
visited.add(node)
for neighbor in graph[node]:
dfs(neighbor)
# If I get here that means i explored all
return True
我們從節點 0 開始,訪問到節點 2,返回 True。 由於我for node in graph:
編寫,現在它將從 node 1 開始,但由於 node 1 已經訪問過,它將返回 False。
這是完整的代碼:
class Solution:
def count_connected(self,graph):
visited=set()
count=0
def dfs(node):
if node in visited:
return False
visited.add(node)
for neighbor in graph[node]:
dfs(neighbor)
# If I get here that means i explored all
return True
# explore all the neightbors of nodes
for node in graph:
if dfs(node):
count+=1
return count
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.