Reputation: 461
Given that I have an initially empty graph, to which will, incrementally, be added edges (one by one), what would be the best way to detect and identify appearing cycles?
Would I have to check for cycles in the entire graph every time a new edge is added? This approach doesn't take advantage of computations already made. Is there an algorithm that I still haven't found?
Thanks.
Upvotes: 3
Views: 687
Reputation: 7476
implemented the algo that @Abhishek linked in python ..
q=QFUF(10)
In [131]: q.is_cycle([(0,1),(1,3),(2,3),(0,3)])
Out[131]: True
In [132]: q.is_cycle([0,1,4,3,1])
Out[132]: True
only cares about first two elements of the tuple
In [134]: q.is_cycle([(0,1,0.3),(1,3,0.7),(2,3,0.4),(0,3,0.2)])
Out[134]: True
here
import numpy as np
class QFUF:
""" Detect cycles using Union-Find algorithm """
def __init__(self, n):
self.n = n
self.reset()
def reset(self): self.ids = np.arange(self.n)
def find(self, a): return self.ids[a]
def union(self, a, b):
#assign cause can be updated in the for loop
aid = self.ids[a]
bid = self.ids[b]
if aid == bid : return
for x in range(self.n) :
if self.ids[x] == aid : self.ids[x] = bid
#given next ~link/pair check if it forms a cycle
def step(self, a, b):
# print(f'{a} => {b}')
if self.find(a) == self.find(b) : return True
self.union(a, b)
return False
def is_cycle(self, seq):
self.reset()
#if not seq of pairs, make them
if not isinstance(seq[0], tuple) :
seq = zip(seq[:-1], seq[1:])
for tpl in seq :
a,b = tpl[0], tpl[1]
if self.step(a, b) : return True
return False
Upvotes: 0
Reputation: 12715
You can use the Quick Union Find algorithm here to 1st check whether the two ends of the new edge are already connected.
EDIT:
As noted in the comment, this solution works only for an undirected graph. For a directed graph, following link may help https://cs.stackexchange.com/questions/7360/directed-union-find.
Upvotes: 5