DSA Lab 06
DSA Lab 06
Lab Session-06
Graph Fundamentals and Applications
Dr. M. Abbas Abbasi
1 Objective
Understanding graph data structures, their representations, traversal algorithms, and solving real-world
problems using graph theory concepts.
2 Learning Outcomes
After completing this lab session, students will be able to:
• Implement graphs using adjacency lists and matrices
• Apply BFS and DFS traversal algorithms
• Solve path finding and connectivity problems
• Model real-world scenarios using graphs
• Analyze time and space complexity of graph algorithms
3 Graph Fundamentals
Graphs consist of vertices (nodes) connected by edges. They can be:
• Directed/Undirected: Directed graphs have edges with a direction, while undirected graphs do
not.
• Weighted/Unweighted: Weighted graphs have edges with associated weights, often representing
costs or distances.
• Cyclic/Acyclic: Cyclic graphs contain cycles, whereas acyclic graphs do not.
4 0 -- 1
5 |
6 v
1
7 2
8
9 Adjacency List :
10 0: 1 2
11 1: 0
12 2:
13 3:
14 4:
15
16 Explanation :
17 - 0 is connected to 1 ( undirected ) -> So , 1 is also connected to 0.
18 - 0 has a directed edge to 2 -> So , 2 is not connected back to 0.
19 - Nodes 3 and 4 are isolated ( no edges ) .
20
21 */
22 # include < iostream >
23 # include < vector >
24 # include < list >
25 using namespace std ;
26
27 class Graph {
28 int V ;
29 vector < list < int > > adj ;
30
31 public :
32 Graph ( int V ) : V ( V ) , adj ( V ) {}
33
39 void print () {
40 for ( int v = 0; v < V ; ++ v ) {
41 cout << v << " : " ;
42 for ( int neighbor : adj [ v ])
43 cout << neighbor << " " ;
44 cout << endl ;
45 }
46 }
47 };
48
49 int main () {
50 Graph g (5) ;
51 g . addEdge (0 , 1) ; // Undirected
52 g . addEdge (0 , 2 , true ) ; // Directed
53 g . print () ;
54 return 0;
55 }
Listing 1: Graph Class Implementation
4 0
5 / \
2
6 1 2
7 | \
8 3 ---> 4
9
10 Adjacency List :
11 0: 1 2
12 1: 3
13 2: 4
14 3: 4
15 4:
16
20 Explanation :
21 1. Start at 0 , visit 1 and 2.
22 2. Visit 1 s neighbor (3) .
23 3. Visit 2 s neighbor (4) .
24 4. Visit 3 s neighbor (4) , but it is already visited .
25 5. End traversal .
26 */
27 # include < iostream >
28 # include < vector >
29 # include < list >
30 # include < queue >
31 using namespace std ;
32
33 void BFS ( const vector < list < int > >& adj , int start ) {
34 vector < bool > visited ( adj . size () , false ) ;
35 queue < int > q ;
36 q . push ( start ) ;
37 visited [ start ] = true ;
38 while (! q . empty () ) {
39 int v = q . front () ;
40 q . pop () ;
41 cout << v << " " ;
42 for ( int neighbor : adj [ v ]) {
43 if (! visited [ neighbor ]) {
44 visited [ neighbor ] = true ;
45 q . push ( neighbor ) ;
46 }
47 }
48 }
49 cout << endl ;
50 }
51
52 int main () {
53 vector < list < int > > graph (5) ;
54 graph [0]. push_back (1) ;
55 graph [0]. push_back (2) ;
56 graph [1]. push_back (3) ;
57 graph [2]. push_back (4) ;
58 graph [3]. push_back (4) ;
59 cout << " BFS Traversal : " ;
60 BFS ( graph , 0) ;
61 return 0;
62 }
Listing 2: BFS Implementation
3
1 /*
2 Graph Representation :
3
4 0
5 / \
6 1 2
7 | \
8 3 ---> 4
9
10 Adjacency List :
11 0: 1 2
12 1: 3
13 2: 4
14 3: 4
15 4:
16
20 Explanation :
21 1. Start at 0 , push 1 and 2 (2 is pushed last , so it is processed later ) .
22 2. Pop 1 , visit it , push its neighbor 3.
23 3. Pop 3 , visit it , push its neighbor 4.
24 4. Pop 4 , visit it ( no new neighbors to push ) .
25 5. Pop 2 , visit it ( its neighbor 4 is already visited ) .
26 6. End traversal .
27 */
28 # include < iostream >
29 # include < vector >
30 # include < list >
31 # include < stack >
32 using namespace std ;
33
34 void DFS ( const vector < list < int > >& adj , int start ) {
35 vector < bool > visited ( adj . size () , false ) ;
36 stack < int > s ;
37 s . push ( start ) ;
38 while (! s . empty () ) {
39 int v = s . top () ;
40 s . pop () ;
41 if (! visited [ v ]) {
42 visited [ v ] = true ;
43 cout << v << " " ;
44 for ( auto it = adj [ v ]. rbegin () ; it != adj [ v ]. rend () ; ++ it ) {
45 if (! visited [* it ]) {
46 s . push (* it ) ;
47 }
48 }
49 }
50 }
51 cout << endl ;
52 }
53
54 int main () {
55 vector < list < int > > graph (5) ;
56 graph [0]. push_back (1) ;
57 graph [0]. push_back (2) ;
58 graph [1]. push_back (3) ;
59 graph [2]. push_back (4) ;
60 graph [3]. push_back (4) ;
61 cout << " DFS Traversal : " ;
62 DFS ( graph , 0) ;
63 return 0;
4
64 }
Listing 3: DFS Implementation (Iterative)
4 (4)
5 0 ------- 1
6 \ / \
7 (8) \ (8) (11)
8 \ / \
9 2 ------ 3
10 (7)
11
12 Adjacency List :
13 0: (1 ,4) (2 ,8)
14 1: (0 ,4) (2 ,8) (3 ,11)
15 2: (0 ,8) (1 ,8) (3 ,7)
16 3: (1 ,11) (2 ,7)
17 4: ( No edges )
18
29 Explanation :
30 1. Start at 0 , distances initialized : [0 , , , ].
31 2. Pick 0 , update neighbors : [0 , 4 , 8 , ].
32 3. Pick 1 ( min dist ) , update neighbors : [0 , 4 , 8 , 15].
33 4. Pick 2 ( min dist ) , update neighbors ( no change ) .
34 5. Pick 3 ( min dist ) , end .
35
36 The shortest paths from 0 to all other vertices are computed using a min - heap (
priority queue ) .
37 */
38 # include < iostream >
39 # include < vector >
40 # include < queue >
41 # include < climits >
42 using namespace std ;
43
46 class WeightedGraph {
47 int V ;
48 vector < list < iPair > > adj ;
49 public :
50 WeightedGraph ( int V ) : V ( V ) , adj ( V ) {}
51 void addEdge ( int u , int v , int w ) {
52 adj [ u ]. push_back ({ v , w }) ;
53 adj [ v ]. push_back ({ u , w }) ;
54 }
5
55 void dijkstra ( int src ) {
56 priority_queue < iPair , vector < iPair > , greater < iPair > > pq ;
57 vector < int > dist (V , INT_MAX ) ;
58 pq . push ({0 , src }) ;
59 dist [ src ] = 0;
60 while (! pq . empty () ) {
61 int u = pq . top () . second ;
62 pq . pop () ;
63 for ( auto &[ v , weight ] : adj [ u ]) {
64 if ( dist [ v ] > dist [ u ] + weight ) {
65 dist [ v ] = dist [ u ] + weight ;
66 pq . push ({ dist [ v ] , v }) ;
67 }
68 }
69 }
70 cout << " Vertex \ tDistance from Source \ n " ;
71 for ( int i = 0; i < V ; ++ i )
72 cout << i << " \ t " << dist [ i ] << endl ;
73 }
74 };
75
76 int main () {
77 WeightedGraph g (5) ;
78 g . addEdge (0 , 1 , 4) ;
79 g . addEdge (0 , 2 , 8) ;
80 g . addEdge (1 , 2 , 8) ;
81 g . addEdge (1 , 3 , 11) ;
82 g . addEdge (2 , 3 , 7) ;
83 g . dijkstra (0) ;
84 return 0;
85 }
Listing 4: Weighted Graph with Dijkstra’s Algorithm
6 Real-World Applications
6.1 Social Network Analysis
Graphs can model social networks where vertices represent users and edges represent friendships.
1 /*
2 Friend Network Graph :
3
4 0
5 / \
6 1 2
7 / \
8 3 4
9 \ /
10 5
11
6
24 - Friends of 2: [4] ( added to recommendations )
25 - Further depth is ignored , so recommendations are : [3 , 4]
26
27 Output :
28 Friend Recommendations for user 0: 3 4
29 */
30 # include < iostream >
31 # include < vector >
32 # include < list >
33 # include < queue >
34 using namespace std ;
35
36 vector < int > f rien dReco mmen datio ns ( const vector < list < int > >& graph , int user ) {
37 vector < bool > visited ( graph . size () , false ) ;
38 vector < int > recommendations ;
39 queue < int > q ;
40
63 int main () {
64 vector < list < int > > graph (6) ;
65 graph [0]. push_back (1) ;
66 graph [0]. push_back (2) ;
67 graph [1]. push_back (3) ;
68 graph [2]. push_back (4) ;
69 graph [3]. push_back (5) ;
70 graph [4]. push_back (5) ;
71
72 vector < int > recommendations = f rien dReco mmen datio ns ( graph , 0) ;
73 cout << " Friend Recommendations for user 0: " ;
74 for ( int rec : recommendations ) {
75 cout << rec << " " ;
76 }
77 cout << endl ;
78 return 0;
79 }
Listing 5: Friend Recommendation System with Testing
7
2 Web Graph Structure :
3
4 (0)
5 / \
6 (1) (2)
7 | |
8 (3) (4)
9 | /
10 (5)
11
26 Expected Output :
27 Starting web crawling from page 0:
28 Crawling page : 0
29 Crawling page : 1
30 Crawling page : 2
31 Crawling page : 3
32 Crawling page : 4
33 Crawling page : 5
34 */
35 # include < iostream >
36 # include < vector >
37 # include < list >
38 # include < queue >
39 using namespace std ;
40
41 void webCrawler ( const vector < list < int > >& webGraph , int startPage ) {
42 vector < bool > visited ( webGraph . size () , false ) ;
43 queue < int > q ;
44 q . push ( startPage ) ;
45 visited [ startPage ] = true ;
46 while (! q . empty () ) {
47 int current = q . front () ;
48 q . pop () ;
49 cout << " Crawling page : " << current << endl ;
50 for ( int linkedPage : webGraph [ current ]) {
51 if (! visited [ linkedPage ]) {
52 visited [ linkedPage ] = true ;
53 q . push ( linkedPage ) ;
54 }
55 }
56 }
57 }
58
59 int main () {
60 vector < list < int > > webGraph (6) ;
61 webGraph [0]. push_back (1) ;
62 webGraph [0]. push_back (2) ;
63 webGraph [1]. push_back (3) ;
64 webGraph [2]. push_back (4) ;
8
65 webGraph [3]. push_back (5) ;
66 webGraph [4]. push_back (5) ;
67
68 cout << " Starting web crawling from page 0:\ n " ;
69 webCrawler ( webGraph , 0) ;
70 return 0;
71 }
Listing 6: Basic Web Crawler Simulation with Testing
7 Lab Tasks
Task 1: Graph Representation (30 minutes)
Implement a graph class supporting:
0---1 2---3
| | / | / |
4 5---6---7
2. Verify:
• BFS from 0: [0,1,4,5,2,6,3,7] (or similar)
• DFS from 2: [2,1,0,4,5,6,3,7] (or similar)
• Number of connected components (should be 1)
• Contains cycle (should be true)
9
Task 3: Weighted Graphs (45 minutes)
Implement Dijkstra’s algorithm and:
10