我尝试编写一个计算图表连接组件的脚本,但我无法获得正确的解决方案。 我有一个简单的图形,有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)
任何人都可以帮我找到错误吗?
答案 0 :(得分:6)
不相交的数据结构将真正帮助您在此处编写清晰的代码,请参阅Wikipedia。
基本思想是将一个集合与图形中的每个节点相关联,并为每个边缘合并其两个端点的集合。如果x
y
和x.find() == y.find()
两组相同
这是最天真的实现(具有糟糕的最坏情况复杂性),但是维基百科页面上的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)
答案 1 :(得分:4)
有时编写代码比阅读代码更容易。
通过一些测试,我很确定只要每个连接都是双向的(例如在你的例子中)它就会一直工作。
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。如果这个程序不能满足您的需求,请告诉我。