Skip to content

Commit c0e6c61

Browse files
authored
Create README.md
1 parent ba27de7 commit c0e6c61

File tree

1 file changed

+194
-0
lines changed
  • 23 - Graph Data Structure Problems/06 - DFS of Graph

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<h1 align='center'>DFS - of Graph</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [DFS of Graph](https://www.geeksforgeeks.org/problems/depth-first-traversal-for-a-graph/1)
6+
7+
![image](https://github.com/user-attachments/assets/c460c3eb-8212-4d51-80de-ee9f61fef61f)
8+
![image](https://github.com/user-attachments/assets/30768d7b-5665-4e9a-81d3-d536df1997d5)
9+
10+
## Problem Explanation
11+
#### **Problem Description:**
12+
The problem requires you to perform a **Depth First Search (DFS)** traversal of a graph. DFS is a graph traversal algorithm that starts from a given node and explores as far as possible along each branch before backtracking. It's typically implemented using recursion (or a stack).
13+
14+
**DFS Characteristics:**
15+
- It explores as deep as possible before backtracking.
16+
- DFS can be implemented using recursion or a stack.
17+
- It is useful for tasks like finding paths, connected components, and cycles in a graph.
18+
19+
#### **Input:**
20+
- An adjacency list representing an undirected graph, where each node is connected to a list of its neighbors.
21+
22+
#### **Output:**
23+
- A list of nodes in the order they are visited during a DFS traversal.
24+
25+
#### **Example:**
26+
27+
Consider the following graph represented as an adjacency list:
28+
29+
```
30+
0: [1, 2]
31+
1: [0, 3, 4]
32+
2: [0]
33+
3: [1]
34+
4: [1]
35+
```
36+
37+
If we start the DFS from node `0`, the expected order of nodes visited would be:
38+
```
39+
0, 1, 3, 4, 2
40+
```
41+
42+
#### **Approach:**
43+
44+
1. **Recursive DFS Traversal:**
45+
- Start at an arbitrary node (node `0` in this case).
46+
- Mark the current node as visited.
47+
- Visit all unvisited neighbors of the current node (recursive step).
48+
- Backtrack once you’ve visited all neighbors.
49+
50+
2. **Implementation Details:**
51+
- A **visited** map is used to ensure each node is visited only once.
52+
- A **result** vector stores the nodes in the order they are visited.
53+
54+
3. **Process:**
55+
- Start from node `0`.
56+
- Explore neighbors recursively.
57+
- Return the traversal result.
58+
59+
## Problem Solution
60+
```cpp
61+
class Solution {
62+
public:
63+
void dfsUtil(int node, vector<vector<int>>& adj, unordered_map<int, bool>& visited, vector<int>& result){
64+
visited[node] = true;
65+
result.push_back(node);
66+
67+
for(int neighbor : adj[node]){
68+
if(!visited[neighbor]) dfsUtil(neighbor, adj, visited, result);
69+
}
70+
}
71+
72+
vector<int> dfsOfGraph(vector<vector<int>>& adj) {
73+
int V = adj.size();
74+
unordered_map<int, bool> visited;
75+
vector<int> result;
76+
77+
dfsUtil(0, adj, visited, result);
78+
return result;
79+
}
80+
};
81+
```
82+
83+
## Problem Solution Explanation
84+
85+
```cpp
86+
class Solution {
87+
public:
88+
void dfsUtil(int node, vector<vector<int>>& adj, unordered_map<int, bool>& visited, vector<int>& result){
89+
```
90+
- **Line 1:** A class `Solution` is defined, which contains the main logic for DFS.
91+
- **Line 2:** The method `dfsUtil` is defined as a helper function that will recursively traverse the graph. It takes the following parameters:
92+
- `node`: the current node to start DFS from.
93+
- `adj`: the adjacency list representing the graph.
94+
- `visited`: a map to keep track of visited nodes to prevent revisiting.
95+
- `result`: a vector that stores the nodes in the order they are visited.
96+
97+
```cpp
98+
visited[node] = true;
99+
result.push_back(node);
100+
```
101+
- **Line 3:** Mark the current node as visited by setting `visited[node] = true`.
102+
- **Line 4:** Add the current node to the `result` vector to record the DFS traversal order.
103+
104+
```cpp
105+
for(int neighbor : adj[node]){
106+
if(!visited[neighbor]) dfsUtil(neighbor, adj, visited, result);
107+
}
108+
```
109+
- **Line 5-7:** For each neighbor of the current node, check if it is visited.
110+
- If a neighbor has not been visited, recursively call `dfsUtil` on the neighbor. This continues until all neighbors are explored.
111+
112+
```cpp
113+
}
114+
115+
vector<int> dfsOfGraph(vector<vector<int>>& adj) {
116+
int V = adj.size();
117+
unordered_map<int, bool> visited;
118+
vector<int> result;
119+
120+
dfsUtil(0, adj, visited, result);
121+
return result;
122+
}
123+
};
124+
```
125+
- **Line 8-10:** The function `dfsOfGraph` is the main function that initializes the visited map and result vector. It then calls `dfsUtil` starting from node `0`.
126+
- **Line 11:** Finally, the function returns the `result` vector, which contains the DFS traversal order.
127+
128+
129+
130+
### **Step 3: Example with Explanation**
131+
132+
Let's consider the graph:
133+
134+
```
135+
0: [1, 2]
136+
1: [0, 3, 4]
137+
2: [0]
138+
3: [1]
139+
4: [1]
140+
```
141+
142+
**Step-by-Step DFS Traversal:**
143+
144+
1. **Start at node `0`:**
145+
- Mark node `0` as visited.
146+
- Add node `0` to the result: `result = [0]`.
147+
- Visit neighbors of `0`: nodes `1` and `2`.
148+
149+
2. **Move to node `1`:**
150+
- Mark node `1` as visited.
151+
- Add node `1` to the result: `result = [0, 1]`.
152+
- Visit neighbors of `1`: nodes `0`, `3`, and `4`.
153+
- Node `0` is already visited, so we move to node `3`.
154+
155+
3. **Move to node `3`:**
156+
- Mark node `3` as visited.
157+
- Add node `3` to the result: `result = [0, 1, 3]`.
158+
- Visit neighbors of `3`: node `1` is already visited, so we backtrack.
159+
160+
4. **Backtrack to node `1` and move to node `4`:**
161+
- Mark node `4` as visited.
162+
- Add node `4` to the result: `result = [0, 1, 3, 4]`.
163+
- Visit neighbors of `4`: node `1` is already visited, so we backtrack.
164+
165+
5. **Backtrack to node `0` and move to node `2`:**
166+
- Mark node `2` as visited.
167+
- Add node `2` to the result: `result = [0, 1, 3, 4, 2]`.
168+
- Visit neighbors of `2`: node `0` is already visited, so we finish.
169+
170+
The **DFS order** is: `[0, 1, 3, 4, 2]`.
171+
172+
173+
174+
### **Step 4: Time and Space Complexity**
175+
176+
#### **Time Complexity:**
177+
- **DFS Traversal:** Each node is visited once and each edge is checked once. So, the time complexity is proportional to the number of vertices and edges.
178+
- **Time Complexity:** **`O(V + E)`**, where `V` is the number of vertices and `E` is the number of edges in the graph.
179+
180+
#### **Space Complexity:**
181+
- **Visited Map:** We use an unordered map to track visited nodes, which takes `O(V)` space.
182+
- **Recursion Stack:** The depth of the recursion tree is at most `V` in the worst case, so the recursion stack takes `O(V)` space.
183+
- **Result Vector:** The result vector stores all the vertices, which takes `O(V)` space.
184+
- **Space Complexity:** **`O(V)`**.
185+
186+
187+
188+
### **Step 5: Recommendations for Students**
189+
190+
1. **Understand the Graph Representation:** Make sure you understand how graphs can be represented (adjacency list vs adjacency matrix).
191+
2. **Recursive vs Iterative DFS:** While this solution uses recursion, DFS can also be implemented iteratively using an explicit stack. Try implementing both to understand the differences.
192+
3. **Edge Cases:** Consider edge cases like disconnected graphs, graphs with only one node, or graphs with cycles.
193+
4. **Practice on Various Graphs:** Try running DFS on graphs of different structures (e.g., trees, cyclic graphs, and disconnected graphs) to get a solid understanding.
194+
5. **Explore Applications of DFS:** DFS is useful for finding connected components, checking for cycles, topological sorting, etc. Try solving problems involving these concepts to enhance your understanding of DFS.

0 commit comments

Comments
 (0)