Skip to content

Commit 8ecdedd

Browse files
authored
Create README.md
1 parent 978f2d1 commit 8ecdedd

File tree

1 file changed

+219
-0
lines changed
  • 23 - Graph Data Structure Problems/04 - Print Adjacency List

1 file changed

+219
-0
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
<h1 align='center'>Print - Adjacency - List</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [Print Adjacency List](https://www.geeksforgeeks.org/problems/print-adjacency-list-1587115620/1)
6+
7+
![image](https://github.com/user-attachments/assets/55ec5006-0638-4f6b-b2c1-aded189ca8fb)
8+
![image](https://github.com/user-attachments/assets/5efbe223-1c74-4880-bc9f-849796803f4e)
9+
10+
## Problem Explanation
11+
In a graph, the **Adjacency List** is a collection of lists or arrays where each list corresponds to a node in the graph and contains all the neighbors (or connected nodes) of that node. It's a way of representing a graph in a compact format, especially for sparse graphs (graphs with fewer edges).
12+
13+
Here is the problem scenario:
14+
15+
You are given a graph with `V` vertices and `E` edges. Each edge connects two vertices, and the graph can either be **directed** or **undirected**. Your task is to print the **adjacency list** for the graph.
16+
17+
For example:
18+
- **Graph Representation:**
19+
- Vertices: `V = 5`
20+
- Edges: `E = 4`
21+
- Edges list: `[(0, 1), (1, 2), (2, 3), (3, 4)]`
22+
23+
The adjacency list for this graph would look like:
24+
25+
```
26+
0 -> 1
27+
1 -> 0, 2
28+
2 -> 1, 3
29+
3 -> 2, 4
30+
4 -> 3
31+
```
32+
33+
This means:
34+
- Node 0 is connected to node 1.
35+
- Node 1 is connected to nodes 0 and 2.
36+
- Node 2 is connected to nodes 1 and 3, and so on.
37+
38+
**Objective:**
39+
Given the number of vertices (`V`) and a list of edges, print the adjacency list.
40+
41+
#### Approach to Solve:
42+
43+
- **Step 1:** Create a class `Graph` to represent the graph.
44+
- **Step 2:** Use an adjacency list to represent the graph. For each edge in the input, add the destination vertex to the adjacency list of the source vertex.
45+
- **Step 3:** After constructing the graph, print the adjacency list for each vertex.
46+
47+
**Example Walkthrough:**
48+
49+
Given the graph:
50+
- `V = 5`
51+
- `Edges = [(0, 1), (1, 2), (2, 3), (3, 4)]`
52+
53+
The adjacency list would be built as follows:
54+
- Start with an empty list of size `V`.
55+
- For each edge `(u, v)`:
56+
- Add `v` to the adjacency list of `u`.
57+
- If the graph is undirected, also add `u` to the adjacency list of `v`.
58+
59+
Final adjacency list after processing:
60+
```
61+
0 -> 1
62+
1 -> 0, 2
63+
2 -> 1, 3
64+
3 -> 2, 4
65+
4 -> 3
66+
```
67+
68+
#### Approach Steps:
69+
1. **Initialize** a `graph` object with `V` vertices.
70+
2. **Add edges** using the `addEdge` function for both directions (if undirected).
71+
3. **Print adjacency list** by iterating through each vertex and displaying its neighbors.
72+
73+
74+
## Problem Solution
75+
```cpp
76+
template <typename T>
77+
class graph{
78+
public:
79+
vector<vector<int>> adj;
80+
81+
graph(int V){
82+
adj.resize(V);
83+
}
84+
85+
void addEdge(T u, T v, bool direction){
86+
adj[u].push_back(v);
87+
88+
if(direction == 0) adj[v].push_back(u);
89+
}
90+
91+
void printAdj(vector<vector<int>>& ans){
92+
for(int i = 0; i < adj.size(); i++){
93+
for(auto j : adj[i]){
94+
ans[i].push_back(j);
95+
}
96+
}
97+
}
98+
};
99+
100+
class Solution {
101+
public:
102+
vector<vector<int>> printGraph(int V, vector<pair<int, int>>& edges) {
103+
graph<int> g(V);
104+
105+
for(int i = 0; i < edges.size(); i++){
106+
g.addEdge(edges[i].first, edges[i].second, 0);
107+
}
108+
109+
vector<vector<int>> ans(V);
110+
g.printAdj(ans);
111+
112+
return ans;
113+
}
114+
};
115+
```
116+
117+
## Problem Solution Explanation
118+
119+
#### **1. `template <typename T>`**
120+
- This line defines a **template** for the `graph` class.
121+
- **Templates** allow us to write generic code that can be used with different data types.
122+
- `T` represents the type for the vertices (in this case, it could be `int`, but it's generalized).
123+
- This makes the `graph` class reusable with any type of data (e.g., integers, strings, etc.).
124+
125+
#### **2. `class graph {`**
126+
- This starts the definition of the `graph` class.
127+
- A **class** is a blueprint for creating objects that can store and manage data, and define functions to operate on that data.
128+
- In this case, the class will handle graphs and their adjacency lists.
129+
130+
#### **3. `vector<vector<int>> adj;`**
131+
- Here, we declare a **2D vector** `adj`.
132+
- **`vector<vector<int>>`** means the outer vector contains inner vectors, and each inner vector stores integers.
133+
- This is an adjacency list representation of the graph.
134+
- **`adj[u]`** will store a list of neighbors (connected nodes) of vertex `u`.
135+
136+
#### **4. `graph(int V)`**
137+
- This is the **constructor** of the `graph` class.
138+
- The constructor initializes the adjacency list with `V` vertices. `V` is passed as a parameter to the constructor, representing the number of vertices in the graph.
139+
140+
#### **5. `adj.resize(V);`**
141+
- This line **resizes** the adjacency list `adj` to have `V` empty sub-vectors.
142+
- Each sub-vector corresponds to a vertex in the graph and will eventually hold the neighbors of that vertex.
143+
- For example, if `V = 3`, `adj` will have 3 empty sub-vectors: `adj[0]`, `adj[1]`, `adj[2]`.
144+
145+
#### **6. `void addEdge(T u, T v, bool direction)`**
146+
- This method adds an **edge** from vertex `u` to vertex `v`.
147+
- The `direction` parameter determines whether the edge is **directed** or **undirected**:
148+
- If `direction == 1`, the edge is directed from `u` to `v`.
149+
- If `direction == 0`, the edge is undirected, so the method will add both directions (from `u` to `v` and from `v` to `u`).
150+
151+
#### **7. `adj[u].push_back(v);`**
152+
- This line adds the destination vertex `v` to the adjacency list of the source vertex `u`.
153+
- **`adj[u]`** is the list of neighbors of vertex `u`, and **`push_back(v)`** adds `v` as a neighbor of `u`.
154+
155+
#### **8. `if (direction == 0) adj[v].push_back(u);`**
156+
- If the edge is undirected (i.e., `direction == 0`), this line adds the reverse edge from `v` to `u` by adding `u` to the adjacency list of `v`.
157+
- This ensures that the graph is undirected by making sure the edge is bidirectional (i.e., if there's an edge from `u` to `v`, there is also an edge from `v` to `u`).
158+
159+
#### **9. `void printAdj(vector<vector<int>>& ans)`**
160+
- This method prints the **adjacency list** of the graph.
161+
- It takes a reference to a vector `ans`, which will hold the adjacency list for output.
162+
- The function will copy the adjacency list from `adj` into `ans`.
163+
164+
#### **10. `for (int i = 0; i < adj.size(); i++) {`**
165+
- This loop iterates over the entire adjacency list `adj`.
166+
- `adj.size()` gives the total number of vertices in the graph.
167+
- This loop will go through each vertex and print its neighbors.
168+
169+
#### **11. `for (auto j : adj[i]) {`**
170+
- This loop iterates through the list of neighbors of the `i`th vertex.
171+
- `auto` is used for automatic type deduction, so `j` represents each neighbor of vertex `i`.
172+
- The inner loop processes each neighbor of the current vertex.
173+
174+
#### **12. `ans[i].push_back(j);`**
175+
- This line copies each neighbor `j` of vertex `i` into the `ans` vector.
176+
- **`ans[i].push_back(j)`** adds each neighbor of vertex `i` to the corresponding list in `ans`.
177+
178+
#### **13. `}`**
179+
- This closes the inner loop that processes neighbors.
180+
181+
#### **14. `}`**
182+
- This closes the outer loop that processes each vertex in the adjacency list.
183+
184+
### **Example and Explanation:**
185+
186+
Let's consider an example with `V = 3` vertices and edges between them.
187+
188+
- **Edges**:
189+
- `0 -> 1`
190+
- `1 -> 2`
191+
- `2 -> 0`
192+
193+
- **Adjacency List** after adding edges:
194+
- Vertex `0` has neighbors: `1` (i.e., `adj[0] = {1}`)
195+
- Vertex `1` has neighbors: `0`, `2` (i.e., `adj[1] = {0, 2}`)
196+
- Vertex `2` has neighbors: `1` (i.e., `adj[2] = {1}`)
197+
198+
### **Time and Space Complexity Analysis:**
199+
200+
#### **Time Complexity:**
201+
- **Adding an edge** takes constant time `O(1)`, as we're simply adding a neighbor to a vector.
202+
- **Printing the adjacency list** involves iterating through all vertices and their neighbors:
203+
- If there are `V` vertices and the total number of edges is `E`, the time complexity of printing the adjacency list is `O(V + E)`.
204+
- For each vertex, we go through all its neighbors, so the total time complexity for printing all vertices and their neighbors is proportional to the number of vertices and edges.
205+
206+
Thus, the overall **time complexity** for the code is **O(V + E)**.
207+
208+
#### **Space Complexity:**
209+
- **Adjacency List**: The space required for storing the adjacency list is proportional to the number of vertices and edges. We store a list of neighbors for each vertex, and the space complexity is **O(V + E)**.
210+
- **Answer vector `ans`**: The space used by the `ans` vector is also **O(V + E)** since it stores the same adjacency information as the `adj` vector.
211+
212+
Thus, the overall **space complexity** is **O(V + E)**.
213+
214+
### **Recommendations for Students:**
215+
- Always keep track of the type of graph you're working with (directed vs. undirected) and the complexity of operations.
216+
- Try implementing basic graph algorithms like BFS and DFS on the adjacency list representation to get a deeper understanding of how graphs work.
217+
- Use a graph visualization tool to help understand how edges are added and how traversal algorithms work.
218+
219+

0 commit comments

Comments
 (0)