Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
57
Task/Tarjan/Python/tarjan-1.py
Normal file
57
Task/Tarjan/Python/tarjan-1.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
from collections import defaultdict
|
||||
|
||||
def from_edges(edges):
|
||||
'''translate list of edges to list of nodes'''
|
||||
|
||||
class Node:
|
||||
def __init__(self):
|
||||
# root is one of:
|
||||
# None: not yet visited
|
||||
# -1: already processed
|
||||
# non-negative integer: what Wikipedia pseudo code calls 'lowlink'
|
||||
self.root = None
|
||||
self.succ = []
|
||||
|
||||
nodes = defaultdict(Node)
|
||||
for v,w in edges:
|
||||
nodes[v].succ.append(nodes[w])
|
||||
|
||||
for i,v in nodes.items(): # name the nodes for final output
|
||||
v.id = i
|
||||
|
||||
return nodes.values()
|
||||
|
||||
def trajan(V):
|
||||
def strongconnect(v, S):
|
||||
v.root = pos = len(S)
|
||||
S.append(v)
|
||||
|
||||
for w in v.succ:
|
||||
if w.root is None: # not yet visited
|
||||
yield from strongconnect(w, S)
|
||||
|
||||
if w.root >= 0: # still on stack
|
||||
v.root = min(v.root, w.root)
|
||||
|
||||
if v.root == pos: # v is the root, return everything above
|
||||
res, S[pos:] = S[pos:], []
|
||||
for w in res:
|
||||
w.root = -1
|
||||
yield [r.id for r in res]
|
||||
|
||||
for v in V:
|
||||
if v.root is None:
|
||||
yield from strongconnect(v, [])
|
||||
|
||||
|
||||
tables = [ # table 1
|
||||
[(1,2), (3,1), (3,6), (6,7), (7,6), (2,3), (4,2),
|
||||
(4,3), (4,5), (5,6), (5,4), (8,5), (8,7), (8,6)],
|
||||
|
||||
# table 2
|
||||
[('A', 'B'), ('B', 'C'), ('C', 'A'), ('A', 'Other')]]
|
||||
|
||||
for table in (tables):
|
||||
for g in trajan(from_edges(table)):
|
||||
print(g)
|
||||
print()
|
||||
85
Task/Tarjan/Python/tarjan-2.py
Normal file
85
Task/Tarjan/Python/tarjan-2.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
from collections import defaultdict
|
||||
|
||||
|
||||
class Graph:
|
||||
"Directed Graph Tarjan's strongly connected components algorithm"
|
||||
|
||||
def __init__(self, name, connections):
|
||||
self.name = name
|
||||
self.connections = connections
|
||||
g = defaultdict(list) # map node vertex to direct connections
|
||||
for n1, n2 in connections:
|
||||
if n1 != n2:
|
||||
g[n1].append(n2)
|
||||
else:
|
||||
g[n1]
|
||||
for _, n2 in connections:
|
||||
g[n2] # For leaf nodes having no edges from themselves
|
||||
self.graph = dict(g)
|
||||
self.tarjan_algo()
|
||||
|
||||
def _visitor(self, this, low, disc, stack):
|
||||
'''
|
||||
Recursive function that finds SCC's
|
||||
using DFS traversal of vertices.
|
||||
|
||||
Arguments:
|
||||
this --> Vertex to be visited in this call.
|
||||
disc{} --> Discovery order of visited vertices.
|
||||
low{} --> Connected vertex of earliest discovery order
|
||||
stack --> Ancestor node stack during DFS.
|
||||
'''
|
||||
|
||||
disc[this] = low[this] = self._order
|
||||
self._order += 1
|
||||
stack.append(this)
|
||||
|
||||
for neighbr in self.graph[this]:
|
||||
if neighbr not in disc:
|
||||
# neighbour not visited so do DFS recurrence.
|
||||
self._visitor(neighbr, low, disc, stack)
|
||||
low[this] = min(low[this], low[neighbr]) # Prior connection?
|
||||
|
||||
elif neighbr in stack:
|
||||
# Update low value of this only if neighbr in stack
|
||||
low[this] = min(low[this], disc[neighbr])
|
||||
|
||||
if low[this] == disc[this]:
|
||||
# Head node found of SCC
|
||||
top, new = None, []
|
||||
while top != this:
|
||||
top = stack.pop()
|
||||
new.append(top)
|
||||
self.scc.append(new)
|
||||
|
||||
def tarjan_algo(self):
|
||||
'''
|
||||
Recursive function that finds strongly connected components
|
||||
using the Tarjan Algorithm and function _visitor() to visit nodes.
|
||||
'''
|
||||
|
||||
self._order = 0 # Visitation order counter
|
||||
disc, low = {}, {}
|
||||
stack = []
|
||||
|
||||
self.scc = [] # SCC result accumulator
|
||||
for vertex in sorted(self.graph):
|
||||
if vertex not in disc:
|
||||
self._visitor(vertex, low, disc, stack)
|
||||
self._disc, self._low = disc, low
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
for n, m in [('Tx1', '10 02 21 03 34'.split()),
|
||||
('Tx2', '01 12 23'.split()),
|
||||
('Tx3', '01 12 20 13 14 16 35 45'.split()),
|
||||
('Tx4', '01 03 12 14 20 26 32 45 46 56 57 58 59 64 79 89 98 AA'.split()),
|
||||
('Tx5', '01 12 23 24 30 42'.split()),
|
||||
]:
|
||||
print(f"\n\nGraph({repr(n)}, {m}):\n")
|
||||
g = Graph(n, m)
|
||||
print(" : ", ' '.join(str(v) for v in sorted(g._disc)))
|
||||
print(" DISC of", g.name + ':', [v for _, v in sorted(g._disc.items())])
|
||||
print(" LOW of", g.name + ':', [v for _, v in sorted(g._low.items())])
|
||||
scc = repr(g.scc if g.scc else '').replace("'", '').replace(',', '')[1:-1]
|
||||
print("\n SCC's of", g.name + ':', scc)
|
||||
Loading…
Add table
Add a link
Reference in a new issue