Content deleted Content added
mNo edit summary |
→Stack invariant: ce: attempt to fix one gibberish sentence and removing a second Tags: Mobile edit Mobile web edit |
||
(68 intermediate revisions by 42 users not shown) | |||
Line 1:
{{Short description|Graph algorithm}}
{{CS1 config|mode=cs2}}
{{Infobox algorithm
|class=
|image= [[File:Tarjan's Algorithm Animation.gif|250px]]
|caption = Tarjan's algorithm
|data=[[Graph (data structure)|Graph]]
|time= <math>O(|V|+|E|)</math>
Line 11 ⟶ 13:
|complete=
}}
'''Tarjan's strongly connected components algorithm'''
== Overview ==
The algorithm takes a [[directed graph]] as input, and produces a [[Partition of a set|partition]] of the graph's [[Vertex (graph theory)|vertices]] into the graph's strongly connected components. Each vertex of the graph appears in exactly one of the strongly connected components. Any vertex that is not on a directed cycle forms a strongly connected component all by itself: for example,
The basic idea of the algorithm is this: a depth-first search (DFS) begins from an arbitrary start node (and subsequent depth-first searches are conducted on any nodes that have not yet been found). As usual with depth-first search, the search visits every node of the graph exactly once,
=== Stack invariant ===
Nodes are placed on a [[Stack (data structure)|stack]] in the order in which they are visited. When the depth-first search recursively visits a node <
At the end of the call that visits <
=== Bookkeeping ===
Each node <code>v</code> is assigned a unique integer <
The lowlink is different from the lowpoint, which is the smallest index reachable from <code>v</code> through any part of the graph.<ref name=Tarjan/>{{rp|156}}<ref name="CMU2018"/>
== The algorithm in pseudocode ==
'''input:''' graph ''G'' = (''V'', ''E'')
'''output:''' set of strongly connected components (sets of vertices)
''index'' := 0
''S'' := empty
'''for each''' ''v'' '''in''' ''V'' '''do'''
'''if'''
strongconnect(''v'')
'''
''// Set the depth index for v to the smallest unused index''
''
''
''
''
''// Consider successors of v''▼
'''for each''' (''v'', ''w'') '''in''' ''E'' '''do'''▼
▲ ''// Consider successors of v''
''// Successor w has not yet been visited; recurse on it''
▲ '''for each''' (''v'', ''w'') '''in''' ''E'' '''do'''
strongconnect(''w'')
▲ '''if''' (''w''.index is undefined) '''then'''
''// Successor w is in stack S and hence in the current SCC''
''// If ''w'' is not on stack, then (''v'', ''w'') is an edge pointing to an SCC already found and must be ignored
'''else if''' (''w''.onStack) '''then'''▼
''//
'''if''' ''v''.lowlink
start a new strongly connected component▼
'''
''w'' := ''S''.pop()▼
add ''w'' to current strongly connected component▼
▲ start a new strongly connected component
output the current strongly connected component▼
▲ ''w'' := ''S''.pop()
▲ add ''w'' to current strongly connected component
▲ output the current strongly connected component
The <
The outermost loop searches each node that has not yet been visited, ensuring that nodes which are not reachable from the first node are still eventually traversed. The function <
When each node finishes recursing, if its lowlink is still set to its index, then it is the root node of a strongly connected component, formed by all of the nodes above it on the stack. The algorithm pops the stack up to and including the current node, and presents all of these nodes as a strongly connected component.
In Tarjan's paper, when <code>''w''</code> is on the stack, <code>''v''.lowlink</code> is updated with the assignment <code>''v''.lowlink := min(''v''.lowlink, ''w''.index)</code>.<ref name=Tarjan/>{{rp|157}} A common variation is to instead use <code>''v''.lowlink := min(''v''.lowlink, ''w''.lowlink)</code>.<ref>{{cite conference
| last1 = Kordy | first1 = Piotr
| last2 = Langerak | first2 = Rom
| last3 = Mauw | first3 = Sjouke
| last4 = Polderman | first4 = Jan Willem
| editor1-last = Jones | editor1-first = Cliff B.
| editor2-last = Pihlajasaari | editor2-first = Pekka
| editor3-last = Sun | editor3-first = Jun
| contribution = A symbolic algorithm for the analysis of robust timed automata
| contribution-url = https://satoss.uni.lu/members/sjouke/papers/KLMP14.pdf
| doi = 10.1007/978-3-319-06410-9_25
| isbn = 978-3-319-06409-3
| pages = 351–366
| publisher = Springer
| series = Lecture Notes in Computer Science
| title = FM 2014: Formal Methods – 19th International Symposium, Singapore, May 12–16, 2014. Proceedings
| volume = 8442
| year = 2014}}</ref><ref>{{cite web |title=Lecture 19: Tarjan's Algorithm for Identifying Strongly Connected Components in the Dependency Graph |url=http://courses.cms.caltech.edu/cs130/lectures-2024wi/CS130-Wi2024-Lec19.pdf |website=CS130 Software Engineering |publisher=Caltech |date=Winter 2024}}</ref> This modified algorithm does not compute the lowlink numbers as Tarjan defined them, but the test <code>''v''.lowlink = ''v''.index</code> still identifies root nodes of strongly connected components, and therefore the overall algorithm remains valid.<ref name="CMU2018">{{cite web |title=Lecture #19: Depth First Search and Strong Components |url=https://www.cs.cmu.edu/~15451-f18/lectures/lec19-DFS-strong-components.pdf |website=15-451/651: Design & Analysis of Algorithms |publisher=Carnegie Mellon |date=1 November 2018}}</ref>
== Complexity ==
''Time Complexity'': The Tarjan procedure is called once for each node; the forall statement considers each edge at most once. The algorithm's running time is therefore linear in the number of edges and nodes in G, i.e. <math>O(|V|+|E|)</math>.
In order to achieve this complexity, the test for whether <
This
''Space Complexity'': The Tarjan procedure requires two words of supplementary data per vertex for the <
==Additional remarks==
While there is nothing special about the order of the nodes within each strongly connected component, one useful property of the algorithm is that no strongly connected component will be identified before any of its successors. Therefore, the order in which the strongly connected components are identified constitutes a reverse [[Topological sorting|topological sort]] of the [[Directed acyclic graph|DAG]] formed by the strongly connected components.<ref>{{cite web|last=Harrison|first=Paul|title=Robust topological sorting and Tarjan's algorithm in Python|url=http://www.logarithmic.net/pfh/blog/01208083168|
[[Donald Knuth]] described Tarjan's SCC algorithm as one of
He also wrote:<ref>{{cite
== References ==
<references />
== External links ==▼
*[https://github.com/bwesterb/py-tarjan/ Another implementation of Tarjan's Algorithm in Python]▼
[[Category:Graph algorithms]]
[[Category:Graph connectivity]]
[[Category:Articles with example pseudocode]]
* [https://rosettacode.org/wiki/Tarjan Rosetta Code], showing implementations in different languages
▲* [https://github.com/
* [https://github.com/Vacilando/js-tarjan JavaScript implementation of Tarjan's strongly connected components algorithm]
|