master > master: src-py tarjan alg

This commit is contained in:
RD 2022-04-07 16:41:26 +02:00
parent 4b4634994c
commit cd265e4ee9
1 changed files with 91 additions and 0 deletions

View File

@ -0,0 +1,91 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from enum import Enum;
from src.local.typing import *;
from src.stacks.stack import *;
from src.graphs.graph import *
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# EXPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
__all__ = [
'tarjan_algorithm',
];
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class State(Enum):
UNTOUCHED = 0;
PENDING = 1;
FINISHED = 2;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Tarjan Algorithm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class NodeInformation:
root: int;
index: int;
state: State;
def __init__(self):
self.root = self.index = 0;
self.state = State.UNTOUCHED;
def tarjan_algorithm(G: Graph) -> List[Any]:
'''
runs the Tarjan-Algorithm to compute the strongly connected components
'''
# sonst Stack erstellen und Bearbeitungszustand der Knoten im Speicher notieren:
S = Stack();
index = 0;
infos = { u: NodeInformation() for u in G.nodes };
components = [];
def tarjan_visit(v: Any):
'''
recursive depth-first search algorithm to compute components
'''
nonlocal G, S, index, components;
if not(infos[v].state == State.UNTOUCHED):
return;
index += 1;
infos[v].index = infos[v].root = index;
S.push(v);
infos[v].state = State.PENDING;
# depth first search:
for u in G.successor(v):
tarjan_visit(u);
# remains relevant for v, provided u still in Stack:
if u in S:
infos[v].root = min(infos[v].root, infos[u].root);
infos[v].state = State.FINISHED;
# if at root of component pop everything from stack up to root and add component:
if infos[v].index == infos[v].root:
component = [];
condition_reached_root = False;
while not condition_reached_root:
u = S.pop();
component.append(u);
condition_reached_root = (u == v);
components.append(component);
return;
for v in G.nodes:
tarjan_visit(v);
return components;