Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
Depth-first search
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
{{short description|Search algorithm}} {{Refimprove|date=July 2010}} {{Infobox algorithm |class=[[Search algorithm]] |image=Depth-first-tree.svg |caption=A tree labeled by the order in which DFS expands its nodes |data=[[Graph (data structure)|Graph]] |time=<math>O(|V| + |E|)</math> for explicit graphs traversed without repetition, <math>O(b^d)</math> for implicit graphs with branching factor ''b '' searched to depth ''d'' |space=<math>O(|V|)</math> if entire graph is traversed without repetition, O(longest path length searched) = <math>O(bd)</math>for implicit graphs without elimination of duplicate nodes |complete=yes (unless infinite paths are possible) |optimal=no (does not generally find shortest paths) }} '''Depth-first search''' ('''DFS''') is an [[algorithm]] for traversing or searching [[tree data structure|tree]] or [[graph (data structure)|graph]] data structures. The algorithm starts at the [[tree (data structure)#Terminology|root node]] (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking. Extra memory, usually a [[Stack (abstract data type)|stack]], is needed to keep track of the nodes discovered so far along a specified branch which helps in backtracking of the graph. A version of depth-first search was investigated in the 19th century by French mathematician [[Charles Pierre Trémaux]]<ref>[[Charles Pierre Trémaux]] (1859–1882) École polytechnique of Paris (X:1876), French engineer of the telegraph <br /> in Public conference, December 2, 2010 – by professor [[Jean Pelletier-Thibert]] in Académie de Macon (Burgundy – France) – (Abstract published in the Annals academic, March 2011 – {{ISSN|0980-6032}})</ref> as a strategy for [[Maze solving algorithm|solving mazes]].<ref>{{citation|title=Graph Algorithms|first=Shimon|last=Even|author-link=Shimon Even|edition=2nd|publisher=Cambridge University Press|year=2011|isbn=978-0-521-73653-4|pages=46–48|url=https://books.google.com/books?id=m3QTSMYm5rkC&pg=PA46}}.</ref><ref>{{citation|title=Algorithms in C++: Graph Algorithms|first=Robert|last=Sedgewick|edition=3rd|publisher=Pearson Education|year=2002|isbn=978-0-201-36118-6}}.</ref> ==Properties== The [[Time complexity|time]] and [[Memory management|space]] analysis of DFS differs according to its application area. In theoretical computer science, DFS is typically used to traverse an entire graph, and takes time {{nowrap|1=<math>O(|V| + |E|)</math>,<ref> Cormen, Thomas H., Charles E. Leiserson, and Ronald L. Rivest. p.606</ref>}} where <math>|V|</math> is the number of [[Vertex (graph theory)|vertices]] and <math>|E|</math> the number of [[Edge (graph theory)|edges]]. This is linear in the size of the graph. In these applications it also uses space <math>O(|V|)</math> in the worst case to store the [[Stack (abstract data type)|stack]] of vertices on the current search path as well as the set of already-visited vertices. Thus, in this setting, the time and space bounds are the same as for [[breadth-first search]] and the choice of which of these two algorithms to use depends less on their complexity and more on the different properties of the vertex orderings the two algorithms produce. For applications of DFS in relation to specific domains, such as searching for solutions in [[artificial intelligence]] or web-crawling, the graph to be traversed is often either too large to visit in its entirety or infinite (DFS may suffer from [[Halting problem|non-termination]]). In such cases, search is only performed to a [[Depth-limited search|limited depth]]; due to limited resources, such as memory or disk space, one typically does not use data structures to keep track of the set of all previously visited vertices. When search is performed to a limited depth, the time is still linear in terms of the number of expanded vertices and edges (although this number is not the same as the size of the entire graph because some vertices may be searched more than once and others not at all) but the space complexity of this variant of DFS is only proportional to the depth limit, and as a result, is much smaller than the space needed for searching to the same depth using breadth-first search. For such applications, DFS also lends itself much better to [[heuristics|heuristic]] methods for choosing a likely-looking branch. When an appropriate depth limit is not known a priori, [[iterative deepening depth-first search]] applies DFS repeatedly with a sequence of increasing limits. In the artificial intelligence mode of analysis, with a [[branching factor]] greater than one, iterative deepening increases the running time by only a constant factor over the case in which the correct depth limit is known due to the geometric growth of the number of nodes per level. DFS may also be used to collect a [[Sample (statistics)|sample]] of graph nodes. However, incomplete DFS, similarly to incomplete [[Breadth-first search#Bias towards nodes of high degree|BFS]], is [[bias]]ed towards nodes of high [[Degree (graph theory)|degree]]. ==Example== [[File:Depth-First-Search.gif|thumb|Animated example of a depth-first search]] For the following graph: [[File:graph.traversal.example.svg|200px|alt=An undirected graph with edges AB, BD, BF, FE, AC, CG, AE]] A depth-first search starting at the node A, assuming that the left edges in the shown graph are chosen before right edges, and assuming the search remembers previously visited nodes and will not repeat them (since this is a small graph), will visit the nodes in the following order: A, B, D, F, E, C, G. The edges traversed in this search form a [[Trémaux tree]], a structure with important applications in [[graph theory]]. Performing the same search without remembering previously visited nodes results in visiting the nodes in the order A, B, D, F, E, A, B, D, F, E, etc. forever, caught in the A, B, D, F, E cycle and never reaching C or G. [[Iterative deepening depth-first search|Iterative deepening]] is one technique to avoid this infinite loop and would reach all nodes. ==Output of a depth-first search== [[File:Tree edges.svg|thumb|upright=1.2|The four types of edges defined by a spanning tree]] The result of a depth-first search of a graph can be conveniently described in terms of a [[spanning tree (mathematics)|spanning tree]] of the vertices reached during the search. Based on this spanning tree, the edges of the original graph can be divided into three classes: '''forward edges''', which point from a node of the tree to one of its descendants, '''back edges''', which point from a node to one of its ancestors, and '''cross edges''', which do neither. Sometimes '''tree edges''', edges which belong to the spanning tree itself, are classified separately from forward edges. If the original graph is undirected then all of its edges are tree edges or back edges. ===Vertex orderings=== It is also possible to use depth-first search to linearly order the vertices of a graph or tree. There are four possible ways of doing this: * A '''preordering''' is a list of the vertices in the order that they were first visited by the depth-first search algorithm. This is a compact and natural way of describing the progress of the search, as was done earlier in this article. A preordering of an [[parse tree|expression tree]] is the expression in [[Polish notation]]. * A '''postordering''' is a list of the vertices in the order that they were ''last'' visited by the algorithm. A postordering of an expression tree is the expression in [[reverse Polish notation]]. * A '''reverse preordering''' is the reverse of a preordering, i.e. a list of the vertices in the opposite order of their first visit. Reverse preordering is not the same as postordering. * A '''reverse postordering''' is the reverse of a postordering, i.e. a list of the vertices in the opposite order of their last visit. Reverse postordering is not the same as preordering. For [[binary trees]] there is additionally '''in-ordering''' and '''reverse in-ordering'''. For example, when searching the directed graph below beginning at node A, the sequence of traversals is either A B D B A C A or A C D C A B A (choosing to first visit B or C from A is up to the algorithm). Note that repeat visits in the form of backtracking to a node, to check if it has still unvisited neighbors, are included here (even if it is found to have none). Thus the possible preorderings are A B D C and A C D B, while the possible postorderings are D B C A and D C B A, and the possible reverse postorderings are A C B D and A B C D. : [[File:If-then-else-control-flow-graph.svg|alt=A directed graph with edges AB, BD, AC, CD]] Reverse postordering produces a [[topological sorting]] of any [[directed acyclic graph]]. This ordering is also useful in [[control-flow graph|control-flow analysis]] as it often represents a natural linearization of the control flows. The graph above might represent the flow of control in the code fragment below, and it is natural to consider this code in the order A B C D or A C B D but not natural to use the order A B D C or A C D B. if ('''A''') then { '''B''' } else { '''C''' } '''D''' ==Pseudocode== {{Tree traversal demo|method=pre-order|noselectmethod=1|caption=Interactive depth-first search demonstration}} A recursive implementation of DFS:<ref>Goodrich and Tamassia; Cormen, Leiserson, Rivest, and Stein</ref> '''procedure''' DFS(''G'', ''v'') '''is''' label ''v'' as discovered '''for all''' directed edges from ''v'' to ''w that are'' '''in''' ''G''.adjacentEdges(''v'') '''do''' '''if''' vertex ''w'' is not labeled as discovered '''then''' recursively call DFS(''G'', ''w'') A non-recursive implementation of DFS with worst-case space complexity <math>O(|E|)</math>, with the possibility of duplicate vertices on the stack:<ref>Page 93, Algorithm Design, Kleinberg and Tardos</ref> '''procedure''' DFS_iterative(''G'', ''v'') '''is''' let ''S'' be a stack ''S''.push(''v'') '''while''' ''S'' is not empty '''do''' ''v'' = ''S''.pop() '''if''' ''v'' is not labeled as discovered '''then''' label ''v'' as discovered '''for all''' edges from ''v'' to ''w'' '''in''' ''G''.adjacentEdges(''v'') '''do''' ''S''.push(''w'') [[File:Graph.traversal.example.svg|alt=An undirected graph with edges AB, BD, BF, FE, AC, CG, AE|right|200x200px|The example graph, copied from above]] These two variations of DFS visit the neighbors of each vertex in the opposite order from each other: the first neighbor of ''v'' visited by the recursive variation is the first one in the list of adjacent edges, while in the iterative variation the first visited neighbor is the last one in the list of adjacent edges. The recursive implementation will visit the nodes from the example graph in the following order: A, B, D, F, E, C, G. The non-recursive implementation will visit the nodes as: A, E, F, B, D, C, G. The non-recursive implementation is similar to [[breadth-first search]] but differs from it in two ways: # it uses a stack instead of a queue, and # it delays checking whether a vertex has been discovered until the vertex is popped from the stack rather than making this check before adding the vertex. If {{mvar|G}} is a [[Tree (data structure)|tree]], replacing the queue of the breadth-first search algorithm with a stack will yield a depth-first search algorithm. For general graphs, replacing the stack of the iterative depth-first search implementation with a queue would also produce a breadth-first search algorithm, although a somewhat nonstandard one.<ref>{{Cite web|title=Stack-based graph traversal ≠ depth first search|url=https://11011110.github.io/blog/2013/12/17/stack-based-graph-traversal.html|access-date=2020-06-10|website=11011110.github.io}}</ref> Another possible implementation of iterative depth-first search uses a stack of [[Iterator|iterators]] of the list of neighbors of a node, instead of a stack of nodes. This yields the same traversal as recursive DFS.<ref>{{Cite book|last=Sedgewick, Robert|url=http://worldcat.org/oclc/837386973|title=Algorithms in Java.|date=2010|publisher=Addison-Wesley|isbn=978-0-201-36121-6|oclc=837386973}}</ref> '''procedure''' DFS_iterative(''G'', ''v'') '''is''' let ''S'' be a stack label ''v'' as discovered ''S''.push(iterator of ''G''.adjacentEdges(''v'')) '''while''' ''S'' is not empty '''do''' '''if''' ''S''.peek().hasNext() '''then''' ''w'' = ''S''.peek().next() '''if''' ''w'' is not labeled as discovered '''then''' label ''w'' as discovered ''S''.push(iterator of ''G''.adjacentEdges(''w'')) '''else''' ''S''.pop() ==Applications== [[File:MAZE 30x20 DFS.ogv|thumb|upright=1.5|Randomized algorithm similar to depth-first search used in generating a maze.]] Algorithms that use depth-first search as a building block include: * Finding [[Connected component (graph theory)|connected components]]. * [[Topological sorting]]. * Finding 2-(edge or vertex)-connected components. * Finding 3-(edge or vertex)-connected components. * Finding the [[Bridge (graph theory)#Bridge-finding algorithm|bridges]] of a graph. * Generating words in order to plot the [[limit set]] of a [[Group (mathematics)|group]]. * Finding [[strongly connected components]]. * Determining whether a species is closer to one species or another in a phylogenetic tree. * [[Planarity testing]].<ref>{{citation | last1 = Hopcroft | first1 = John | author1-link = John Hopcroft | last2 = Tarjan | first2 = Robert E. | author2-link = Robert Tarjan | doi = 10.1145/321850.321852 | issue = 4 | journal = [[Journal of the ACM|Journal of the Association for Computing Machinery]] | pages = 549–568 | title = Efficient planarity testing | volume = 21 | year = 1974| url = https://ecommons.cornell.edu/bitstream/1813/6011/1/73-165.pdf | hdl = 1813/6011 | s2cid = 6279825 | hdl-access = free }}.</ref><ref>{{citation | last1 = de Fraysseix | first1 = H. | last2 = Ossona de Mendez | first2 = P. | author2-link = Patrice Ossona de Mendez | last3 = Rosenstiehl | first3 = P. | author3-link = Pierre Rosenstiehl | journal = International Journal of Foundations of Computer Science | pages = 1017–1030 | title = Trémaux Trees and Planarity | volume = 17 | year = 2006 | doi = 10.1142/S0129054106004248 | issue = 5| arxiv=math/0610935| bibcode = 2006math.....10935D | s2cid = 40107560 }}.</ref> * Solving puzzles with only one solution, such as [[maze]]s. (DFS can be adapted to find all solutions to a maze by only including nodes on the current path in the visited set.) * [[Maze generation]] may use a randomized DFS. * Finding [[Biconnected graph|biconnectivity in graphs]]. * [[Primogeniture#Absolute_primogeniture|Succession]] to the throne shared by the [[Commonwealth realms]].<ref>{{citation|last1=Baccelli|first1=Francois|last2=Haji-Mirsadeghi|first2=Mir-Omid|last3=Khezeli|first3=Ali|editor-last=Sobieczky|editor-first=Florian|contribution=Eternal family trees and dynamics on unimodular random graphs|doi=10.1090/conm/719/14471|location=Providence, Rhode Island|mr=3880014|pages=85–127|publisher=American Mathematical Society|series=Contemporary Mathematics|title=Unimodularity in Randomly Generated Graphs: AMS Special Session, October 8–9, 2016, Denver, Colorado|volume=719|year=2018|arxiv=1608.05940 |isbn=978-1-4704-3914-9 |s2cid=119173820 }}; see [https://books.google.com/books?id=7dV7DwAAQBAJ&pg=PA93 Example 3.7, p. 93]</ref> ==Complexity== The [[Analysis of algorithms|computational complexity]] of DFS was investigated by [[John Reif]]. More precisely, given a graph <math>G</math>, let <math>O=(v_1,\dots,v_n)</math> be the ordering computed by the standard recursive DFS algorithm. This ordering is called the lexicographic depth-first search ordering. John Reif considered the complexity of computing the lexicographic depth-first search ordering, given a graph and a source. A [[decision problem|decision version]] of the problem (testing whether some vertex {{mvar|u}} occurs before some vertex {{mvar|v}} in this order) is [[P-complete|'''P'''-complete]],<ref>{{Cite journal| doi = 10.1016/0020-0190(85)90024-9| title = Depth-first search is inherently sequential| journal = Information Processing Letters| volume = 20| issue = 5| year = 1985| last1 = Reif | first1 = John H. | pages = 229–234}}</ref> meaning that it is "a nightmare for [[parallel algorithm|parallel processing]]".<ref name="mehlhorn">{{cite book |last1=Mehlhorn |first1=Kurt |author1-link=Kurt Mehlhorn|first2=Peter |last2=Sanders|author2-link=Peter Sanders (computer scientist) |title=Algorithms and Data Structures: The Basic Toolbox |publisher=Springer |year=2008 |url=http://people.mpi-inf.mpg.de/~mehlhorn/ftp/Toolbox/GraphTraversal.pdf |archive-url=https://web.archive.org/web/20150908084757/http://people.mpi-inf.mpg.de/~mehlhorn/ftp/Toolbox/GraphTraversal.pdf |archive-date=2015-09-08 |url-status=live}}</ref>{{rp|189}} A depth-first search ordering (not necessarily the lexicographic one), can be computed by a randomized parallel algorithm in the complexity class [[NC (complexity)|RNC]].<ref>{{citation | last1 = Aggarwal | first1 = A. | last2 = Anderson | first2 = R. J. | doi = 10.1007/BF02122548 | issue = 1 | journal = [[Combinatorica]] | mr = 951989 | pages = 1–12 | title = A random ''NC'' algorithm for depth first search | volume = 8 | year = 1988| s2cid = 29440871 }}.</ref> As of 1997, it remained unknown whether a depth-first traversal could be constructed by a deterministic parallel algorithm, in the complexity class [[NC (complexity)|NC]].<ref>{{citation | last1 = Karger | first1 = David R. | author1-link = David Karger | last2 = Motwani | first2 = Rajeev | author2-link = Rajeev Motwani | doi = 10.1137/S0097539794273083 | issue = 1 | journal = [[SIAM Journal on Computing]] | mr = 1431256 | pages = 255–272 | title = An ''NC'' algorithm for minimum cuts | volume = 26 | year = 1997| citeseerx = 10.1.1.33.1701}}.</ref> ==See also== *[[Tree traversal]] (for details about pre-order, in-order and post-order depth-first traversal) *[[Breadth-first search]] *[[Iterative deepening depth-first search]] *[[Search game]] ==Notes== {{reflist}} ==References== {{refbegin}} * [[Thomas H. Cormen]], [[Charles E. Leiserson]], [[Ronald L. Rivest]], and [[Clifford Stein]]. ''[[Introduction to Algorithms]]'', Second Edition. MIT Press and McGraw-Hill, 2001. {{ISBN|0-262-03293-7}}. Section 22.3: Depth-first search, pp. 540–549. * {{Citation | last1=Goodrich | first1=Michael T. | author1-link=Michael T. Goodrich | last2=Tamassia | first2=Roberto | author2-link = Roberto Tamassia | title=Algorithm Design: Foundations, Analysis, and Internet Examples | publisher=Wiley | year=2001 | isbn=0-471-38365-1 }} *{{citation|title=Algorithm Design|first1=Jon|last1=Kleinberg|author1-link=Jon Kleinberg|first2=Éva|last2=Tardos|author2-link=Éva Tardos|publisher=Addison Wesley|year=2006|pages=92–94}} * {{Citation | last=Knuth | first=Donald E. | author-link=Donald Knuth | title=The Art of Computer Programming Vol 1. 3rd ed | publisher=Addison-Wesley | place=Boston | year=1997 | isbn=0-201-89683-4 | url=http://www-cs-faculty.stanford.edu/~knuth/taocp.html | oclc=155842391 | access-date=2008-02-12 | archive-date=2008-09-04 | archive-url=https://web.archive.org/web/20080904163709/http://www-cs-faculty.stanford.edu/~knuth/taocp.html | url-status=dead }} {{refend}} ==External links== {{Commons category|Depth-first search}} * [http://opendatastructures.org/versions/edition-0.1e/ods-java/12_3_Graph_Traversal.html#SECTION001532000000000000000 Open Data Structures - Section 12.3.2 - Depth-First-Search], [[Pat Morin]] * [http://www.boost.org/libs/graph/doc/depth_first_search.html C++ Boost Graph Library: Depth-First Search] * [http://www.cs.duke.edu/csed/jawaa/DFSanim.html Depth-First Search Animation (for a directed graph)] * [http://www.kirupa.com/developer/actionscript/depth_breadth_search.htm Depth First and Breadth First Search: Explanation and Code] * [http://www.algolist.net/Algorithms/Graph_algorithms/Undirected/Depth-first_search Depth-first search algorithm illustrated explanation (Java and C++ implementations)] * [https://code.google.com/p/yagsbpl/ YAGSBPL – A template-based C++ library for graph search and planning] {{Graph traversal algorithms}} {{DEFAULTSORT:Depth-First Search}} [[Category:Graph algorithms]] [[Category:Search algorithms]] [[Category:Articles with example pseudocode]] [[Category:Articles containing video clips]]
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)
Pages transcluded onto the current version of this page
(
help
)
:
Template:Catalog lookup link
(
edit
)
Template:Citation
(
edit
)
Template:Cite book
(
edit
)
Template:Cite journal
(
edit
)
Template:Cite web
(
edit
)
Template:Commons category
(
edit
)
Template:Error-small
(
edit
)
Template:Graph traversal algorithms
(
edit
)
Template:ISBN
(
edit
)
Template:ISSN
(
edit
)
Template:Infobox algorithm
(
edit
)
Template:Main other
(
edit
)
Template:Mvar
(
edit
)
Template:Nowrap
(
edit
)
Template:Refbegin
(
edit
)
Template:Refend
(
edit
)
Template:Refimprove
(
edit
)
Template:Reflist
(
edit
)
Template:Rp
(
edit
)
Template:Short description
(
edit
)
Template:Sister project
(
edit
)
Template:Tree traversal demo
(
edit
)
Template:Trim
(
edit
)
Template:Yesno-no
(
edit
)