Why Graphs Exist and What Trees Cannot Model in DSA Typescript - Performance Analysis
We want to understand why graphs are needed beyond trees and how this affects the time to process connections.
How does the complexity of handling graphs compare to trees?
Analyze the time complexity of traversing a graph compared to a tree.
function traverseGraph(adjList: Map, start: number): void {
const visited = new Set();
const stack = [start];
while (stack.length > 0) {
const node = stack.pop()!;
if (!visited.has(node)) {
visited.add(node);
for (const neighbor of adjList.get(node) || []) {
stack.push(neighbor);
}
}
}
}
This code visits all nodes reachable from a start node in a graph using depth-first search.
Look for loops and repeated visits.
- Primary operation: Visiting each node and exploring its neighbors.
- How many times: Each node and each edge is processed once during traversal.
As the number of nodes and edges grows, the work grows with both.
| Input Size (n nodes, e edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 25 operations (nodes + edges) |
| 100 nodes, 200 edges | About 300 operations |
| 1000 nodes, 5000 edges | About 6000 operations |
Pattern observation: Operations grow roughly with the sum of nodes and edges, not just nodes like in trees.
Time Complexity: O(n + e)
This means the time to traverse depends on both the number of nodes and the number of edges in the graph.
[X] Wrong: "Graphs are just like trees, so traversal time depends only on nodes."
[OK] Correct: Graphs can have many connections (edges) between nodes, so edges add to the work done.
Understanding how graphs differ from trees and their traversal costs helps you explain data structure choices clearly and confidently.
What if the graph is very dense, with edges close to the maximum possible? How would that affect the time complexity?
Practice
Solution
Step 1: Understand tree limitations
Trees are hierarchical and cannot have cycles or multiple parents for a node.Step 2: Understand graph capabilities
Graphs allow any connections, including cycles and multiple edges between nodes.Final Answer:
Because graphs can represent connections between nodes in any pattern, including cycles. -> Option DQuick Check:
Graphs model cycles, trees cannot [OK]
- Thinking trees can have cycles
- Confusing data types with structure
- Assuming graphs are simpler than trees
Solution
Step 1: Identify adjacency list type
An adjacency list is an array of arrays, where each inner array holds connected node indices.Step 2: Match TypeScript syntax
TypeScript syntax for adjacency list is number[][] for array of number arrays.Final Answer:
const graph: number[][] = []; -> Option BQuick Check:
Adjacency list = number[][] [OK]
- Using single number type for adjacency list
- Using object {} instead of array []
- Wrong type annotations
const graph: number[][] = [[1], [2], [0]];
function hasCycle(node: number, visited: boolean[], stack: boolean[]): boolean {
if (!visited[node]) {
visited[node] = true;
stack[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor] && hasCycle(neighbor, visited, stack)) {
return true;
} else if (stack[neighbor]) {
return true;
}
}
}
stack[node] = false;
return false;
}
const visited = [false, false, false];
const stack = [false, false, false];
console.log(hasCycle(0, visited, stack));
What is the output?Solution
Step 1: Understand graph structure
Graph edges: 0->1, 1->2, 2->0 form a cycle.Step 2: Trace hasCycle function
DFS visits nodes 0,1,2 and detects back edge from 2 to 0 in recursion stack, returning true.Final Answer:
true -> Option CQuick Check:
Cycle detected = true [OK]
- Assuming no cycle in small graph
- Confusing visited and stack arrays
- Ignoring recursion stack usage
const graph: number[][] = [[1], [2], [0]];
function hasCycle(node: number, visited: boolean[], stack: boolean[]): boolean {
if (visited[node]) {
return false;
}
visited[node] = true;
stack[node] = true;
for (const neighbor of graph[node]) {
if (!visited[neighbor] && hasCycle(neighbor, visited, stack)) {
return true;
} else if (stack[neighbor]) {
return true;
}
}
stack[node] = false;
return false;
}
const visited = [false, false, false];
const stack = [false, false, false];
console.log(hasCycle(0, visited, stack));
What is the bug in this code?Solution
Step 1: Analyze early return on visited node
Returning false immediately when node is visited skips cycle detection on back edges.Step 2: Understand correct cycle detection logic
Should only return false if node visited and not in recursion stack; else return true if in stack.Final Answer:
It returns false immediately if node is visited, missing cycles. -> Option AQuick Check:
Early return on visited node causes missed cycles [OK]
- Returning false too early
- Confusing visited and recursion stack
- Ignoring recursion stack check
Solution
Step 1: Identify social network connection patterns
Users can follow each other in any pattern, including cycles and mutual connections.Step 2: Compare data structures
Trees cannot represent cycles or multiple parents; graphs can represent any connection pattern.Final Answer:
Use a graph because it supports cycles and multiple connections; trees cannot model cycles or multiple parents. -> Option AQuick Check:
Graphs model social networks; trees cannot [OK]
- Choosing tree for cyclic connections
- Confusing linked list with graph
- Ignoring cycles in social networks
Ready to prove it?
Pass the test and this pattern moves unknown
