|
1 |
| -"""The DFS function simply calls itself recursively for every unvisited child of |
2 |
| -its argument. We can emulate that behaviour precisely using a stack of iterators. |
3 |
| -Instead of recursively calling with a node, we'll push an iterator to the node's |
4 |
| -children onto the iterator stack. When the iterator at the top of the stack |
5 |
| -terminates, we'll pop it off the stack. |
6 |
| -
|
7 |
| -Pseudocode: |
8 |
| - all nodes initially unexplored |
9 |
| - mark s as explored |
10 |
| - for every edge (s, v): |
11 |
| - if v unexplored: |
12 |
| - DFS(G, v) |
13 |
| -""" |
14 |
| -from typing import Dict, Set |
| 1 | +"""Non recursive implementation of a DFS algorithm.""" |
| 2 | + |
| 3 | +from typing import Set, Dict |
15 | 4 |
|
16 | 5 |
|
17 | 6 | def depth_first_search(graph: Dict, start: str) -> Set[int]:
|
18 | 7 | """Depth First Search on Graph
|
19 | 8 |
|
20 |
| - :param graph: directed graph in dictionary format |
21 |
| - :param vertex: starting vectex as a string |
22 |
| - :returns: the trace of the search |
23 |
| - >>> G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], |
24 |
| - ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], |
25 |
| - ... "F": ["C", "E", "G"], "G": ["F"] } |
26 |
| - >>> start = "A" |
27 |
| - >>> output_G = list({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) |
28 |
| - >>> all(x in output_G for x in list(depth_first_search(G, "A"))) |
29 |
| - True |
30 |
| - >>> all(x in output_G for x in list(depth_first_search(G, "G"))) |
31 |
| - True |
| 9 | + :param graph: directed graph in dictionary format |
| 10 | + :param vertex: starting vertex as a string |
| 11 | + :returns: the trace of the search |
| 12 | + >>> G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], |
| 13 | + ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], |
| 14 | + ... "F": ["C", "E", "G"], "G": ["F"] } |
| 15 | + >>> start = "A" |
| 16 | + >>> output_G = list({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) |
| 17 | + >>> all(x in output_G for x in list(depth_first_search(G, "A"))) |
| 18 | + True |
| 19 | + >>> all(x in output_G for x in list(depth_first_search(G, "G"))) |
| 20 | + True |
32 | 21 | """
|
33 | 22 | explored, stack = set(start), [start]
|
| 23 | + |
34 | 24 | while stack:
|
35 | 25 | v = stack.pop()
|
36 |
| - # one difference from BFS is to pop last element here instead of first one |
37 |
| - for w in graph[v]: |
38 |
| - if w not in explored: |
39 |
| - explored.add(w) |
40 |
| - stack.append(w) |
| 26 | + explored.add(v) |
| 27 | + # Differences from BFS: |
| 28 | + # 1) pop last element instead of first one |
| 29 | + # 2) add adjacent elements to stack without exploring them |
| 30 | + for adj in reversed(graph[v]): |
| 31 | + if adj not in explored: |
| 32 | + stack.append(adj) |
41 | 33 | return explored
|
42 | 34 |
|
43 | 35 |
|
|
0 commit comments