Python 如何根据图形数据标记作为循环中初始顶点的节点
我需要实现一个算法,这样在一组唯一且有序的图边中,我可以找到一个循环节点 例如,对于Python 如何根据图形数据标记作为循环中初始顶点的节点,python,algorithm,Python,Algorithm,我需要实现一个算法,这样在一组唯一且有序的图边中,我可以找到一个循环节点 例如,对于a->b,b->c,c->a,则'a'是一个循环节点,因此我想在该边缘用'a@'对其进行注释,其他节点则类似 作为示例数据,我使用以下内容: a = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')] 那么这将成为: [('a', 'b'), ('b', 'c'), ('c', 'd'), ('
a->b,b->c,c->a
,则'a'
是一个循环节点,因此我想在该边缘用'a@'
对其进行注释,其他节点则类似
作为示例数据,我使用以下内容:
a = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')]
那么这将成为:
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a@'), ('a', 'e'), ('e', 'a@'), ('f', 'e')]
如何在python中实现这一点
这就是我所尝试的:
collection={}
数据,结果=[],[]
对于a中的i,j:
如果我在collection.keys()中:
集合[i]。追加(j)
其他:
集合[i]=[j]
如果j在collection.keys()中:
对于范围内的项目(len(集合[i]):
如果集合[i][item]==j:
nr+=1
集合[i][item]=j+'@'
打印(收集)
此解决方案构建它在边缘列表中遇到的所有可能路径,因为我们不知道循环从何处开始。如果图形很大,它还会修剪创建的路径列表,以防止内存膨胀。这是丑陋的,但工作的基础上,你的需要
a = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')]
annotated = []
paths = []
for edge in a:
new_paths = []
paths.append(''.join(edge))
annotated.append(edge)
cycle = ''
for path in paths[:]:
if path.endswith(edge[0]):
if path.startswith(edge[1]):
annotated[-1] = (annotated[-1][0], annotated[-1][1]+'@')
cycle = path + edge[1]
else:
new_paths.append(path + edge[1])
else:
new_paths.append(path)
paths = [x for x in new_paths if x not in cycle]
print(paths)
print(f'Result: {annotated}')
"""
Out:
['ab']
['abc', 'bc']
['abcd', 'bcd', 'cd']
[]
['ae']
[]
['fe']
Result: [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a@'), ('a', 'e'), ('e', 'a@'), ('f', 'e')]
"""
问题:对于a->b,b->c,c->a
,那么'a'
是一个循环节点,因此我想在这一边缘用'a@
对其进行注释,其他节点则类似
如果找到有效的节点链,例如a->b,b->c,c->a
,则用'@'
标记最后一个节点
def mark_cycle_end(nodes, initial, marker='@'):
chained = None, None
cycle_start = None
for i, node in enumerate(nodes):
if cycle_start is not None \
and chained[0] == chained[1]:
chained = nodes[i - 1][1], node[0]
if node[0] == initial:
cycle_start = i
chained = None, None
elif node[1] == initial:
start, end, end_ = cycle_start, i, i + 1
if chained == (None, None):
print('missing start node, end is: {}'
.format(nodes[end:end_]))
elif not chained[0] == chained[1]:
print('missing link {} in {}'
.format(chained, nodes[start:end_]))
else: # is chained
print('mark:{}'
.format((start, end, nodes[start:end_])))
nodes[end] = (nodes[end][0], nodes[end][1] + marker)
cycle_start = None
chained = None, None
用法:
mark:(0, 3, [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a')])
mark:(4, 5, [('a', 'e'), ('e', 'a')])
MATCH:[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a@'), ('a', 'e'), ('e', 'a@'), ('f', 'e')]
missing link ('z', 'b') in [('a', 'z'), ('b', 'z'), ('c', 'd'), ('d', 'a')]
missing start node, end is: [('z', 'a')]
MATCH:[('a', 'b'), ('a', 'c'), ('a', 'z'), ('b', 'z'), ('c', 'd'), ('d', 'a'), ('d', 'z'), ('z', 'd'), ('z', 'c'), ('z', 'a'), ('z', 'y'), ('z', 'b')]
输出:
mark:(0, 3, [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a')])
mark:(4, 5, [('a', 'e'), ('e', 'a')])
MATCH:[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a@'), ('a', 'e'), ('e', 'a@'), ('f', 'e')]
missing link ('z', 'b') in [('a', 'z'), ('b', 'z'), ('c', 'd'), ('d', 'a')]
missing start node, end is: [('z', 'a')]
MATCH:[('a', 'b'), ('a', 'c'), ('a', 'z'), ('b', 'z'), ('c', 'd'), ('d', 'a'), ('d', 'z'), ('z', 'd'), ('z', 'c'), ('z', 'a'), ('z', 'y'), ('z', 'b')]
就我从你们的例子、定义和问题中可以看出,连接两个已经间接连接的节点的任何边都会导致循环节点 因此,如果跟踪连接的节点,则可以确定边是否连接新节点。如果它没有连接新节点,则边连接到循环节点(在这种情况下,可能说它是循环边更有用吗?) 编辑:我在这里假设图是,因为没有提到边的方向。如果这个问题是针对有向图的,那么我的答案是无效的,因为你根本无法使用有向图中的集合来计算循环 以下是函数:
def markcyclicnodes(edges):
groups = []
result = []
for edge in edges:
cyclicnode = False
newlink = False
newnode = False
group1count = 0
group2count = 0
tolink = 0
todelete = 0
for group1 in groups:
if cyclicnode == False and newlink == False and newnode == False:
if edge[0] in group1 and edge[1] in group1:
cyclicnode = True
elif edge[0] in group1:
tolink = group1count
for group2 in groups:
if edge[1] in group2:
newlink = True
todelete = group2count
group2count += 1
if newlink == False:
groups[group1count].append(edge[1])
newnode = True
elif edge[1] in group1:
tolink = group1count
for group2 in groups:
if edge[0] in group2:
newlink = True
todelete = group2count
group2count += 1
if newlink == False:
groups[group1count].append( edge[0])
newnode = True
group1count += 1
if newlink == False and cyclicnode == False and newnode == False :
groups.append([edge[0],edge[1]])
if newlink == True:
for node in groups[todelete]:
groups[tolink].append (node)
del groups[todelete]
if cyclicnode == True:
result.append ((edge[0], edge[1]+'@'))
else:
result.append(edge)
return result
这是我的测试数据:
edges1 = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')]
edges2 = [('a', 'b'), ('a', 'c'), ('a', 'z'), ('b', 'z'), ('c', 'd'), ('d', 'a'), ('d', 'z'), ('z', 'd'), ('z', 'c'), ('z', 'a'), ('z', 'y'), ('z', 'b')]
edges3 = [('a', 'b'), ('b', 'c'),('z', 'bye'), ('bye', 'c'), ('hi', 'shy'),('shy','a'),('shy','z')]
以下是每组测试数据的结果
[('a', 'b'),
('b', 'c'),
('c', 'd'),
('d', 'a@'),
('a', 'e'),
('e', 'a@'),
('f', 'e')]
简短的变体:
a = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')]
repeated_nodes = set()
result = []
for edge in a:
if edge[1] not in repeated_nodes:
result.append(edge)
else:
result.append((edge[0], f'@{edge[1]}'))
repeated_nodes.add(edge[0])
print(result)
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', '@a'), ('a', 'e'), ('e', '@a'), ('f', '@e')]
或者如果你喜欢理解,那么:
repeated_nodes = set()
result = []
for edge in a:
result.append(edge if edge[1] not in repeated_nodes else (edge[0], f'@{edge[1]}'))
repeated_nodes.add(edge[0])
print(result)
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', '@a'), ('a', 'e'), ('e', '@a'), ('f', '@e')]
为什么要注释第二个和第四个
a
,而不是第一个和第三个?因为在这些边上,特定的“a”也将表示作为循环源的初始“a”。因此,对于a->b,b->c,c->d,d->a,我只想注释最后一个“a”。我这样做是为了将图形数据转换为树数据。我想说你应该注释第三个,然后第二个a
就结束了循环。无论如何,您可能需要查看图形分析。为什么在您的示例中,a
是唯一注释的节点?是什么让它成为周期的“初始”顶点?看起来没人理解你。你能在你的问题中加入你的其他例子和它们的预期结果吗?我指的是你上一份副本中的例子和@Ivan Popov answer下的例子。你能确切地解释一下哪个节点应该被标记为循环节点以及为什么吗?对于[('a','b'),('a','c'),('a','z'),('b','z'),('c','d'),('d','z'),('z','c'),('z','a'),('z','y'),('z','b'),它将失败。('z','a')和('z','b')不存在true。然而,在这个例子中(z,c@)也应该存在,因为我们有序列(c,d),(d,z),(z,c)
。您对周期的开始和结束的定义是任意的,并且这些边不是以逻辑方式“排序”的。序列(c,d)、(z,c)、(d,z)
的输出是什么?如果测试数据是[('a','b'),('a','c'),('a','z'),('b','z')]
,我想你会在没有循环的情况下将'z@'标记为再次到达。我站在我的评论中,如果你把任何东西连接到集合中的集合,然后创建一个循环,请把你的答案编辑成是否考虑有向或无向图——我希望这个问题是明确的。
a = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'a'), ('a', 'e'), ('e', 'a'), ('f', 'e')]
repeated_nodes = set()
result = []
for edge in a:
if edge[1] not in repeated_nodes:
result.append(edge)
else:
result.append((edge[0], f'@{edge[1]}'))
repeated_nodes.add(edge[0])
print(result)
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', '@a'), ('a', 'e'), ('e', '@a'), ('f', '@e')]
repeated_nodes = set()
result = []
for edge in a:
result.append(edge if edge[1] not in repeated_nodes else (edge[0], f'@{edge[1]}'))
repeated_nodes.add(edge[0])
print(result)
[('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', '@a'), ('a', 'e'), ('e', '@a'), ('f', '@e')]