What is a Graph?

A collection of Nodes and Edges

A graph is great establishing relationships between Nodes

Directed Graphs

graph LR
  a --> b
	b --> c
	a --> c
	c --> d

Undirected Graphs

graph LR
  a --- b
	b --- c
	a --- c
	c --- d

Representation of Graphs

Adjacency Matrix / Sparse Matrix

Adjacency List

Let Following be a Graph

graph LR
	a --> b  
	a --> c
	b --> d
	c --> e
	d --> f
	

Adjacency Matrix

Adjacency List

let gr = [
  [0, 1, 1, 0, 0, 0],
  [0, 0, 0, 1, 0, 0],
  [0, 0, 0, 0, 1, 0],
  [0, 0, 0, 0, 0, 1],
  [0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0]
];
let gr = [
	a: [c, b],
	b: [d],
	c: [e],
	d: [f]
	e: []
	f: []
}

<aside> šŸ’” Can you see the amount of space being wasted to store this simple graph in a adjacency matrix? For storing 5 relationships I have to always use $O(n*e)$ space. What if we could only save the Relationships instead of Non-Relationships? Therefore for sparse graphs like this, adhacency lists are optimal

</aside>

Traversals

DFS

DFS Traversal goes deep in a directon untill it can go no more.

DFS uses stack Data Structure

DFS visits nodes linearly

Screenshot 2023-09-14 at 8.39.47 PM.png

BFS

BFS is traversal that traverses ā€œNearest Neighbour Firstā€.

BFS Queue Data structure.

BFS visits nodes radially

Screenshot 2023-09-14 at 6.56.18 PM.png

Iterative Approach - DFS

Iterative Approach - BFS

function dfs(graph, source='a') {
	let stack = [source];
	
	while(stack.length > 0) {
		let current = stack.pop();
		console.log(current)

		for(let neighbour of gr[current]) {
			stack.push(neighbour)
		}
	}	
}
function bfs(gr, source) {
	let queue = [source];
	
	//repeat till queue has elements
	while(queue.length > 0) { 
		
		// pop and print current element
		let current = queue.pop(); 
		console.log(current);
		
		//Add all neighbouring elements in queue
		for(let neighbour of gr[current]) {
			queue.unshift(neighbour)
		}
	}
}