簡體   English   中英

Python中計算圖的連通分量的算法

[英]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()則兩組xy相同

這是最幼稚的實現(最糟糕的情況是復雜性很差),但是在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM