Skip to content

Graph Iterator Creation Guide

Introduction

This guide covers how to create and use graph iterators in ApexDS. Graph iterators provide a clean interface for traversing graphs using various algorithms, making it easy to explore graph structures and implement graph-based algorithms.

Creating Graph Iterators

The createGraphIterator function is the factory method for creating specialized graph iterators. It follows the strategy pattern, allowing you to select the traversal algorithm at runtime.

Basic Usage

typescript
import { createGraph, createGraphIterator } from "@apexds/core";
import { EnumGraphType, EnumGraphTraversalType } from "@apexds/core";

// Create a graph
const graph = createGraph<number>(EnumGraphType.DIRECTED);
// ... add vertices and edges

// Create iterators with different traversal strategies
const bfsIterator = createGraphIterator(graph, EnumGraphTraversalType.BFS);
const dfsIterator = createGraphIterator(graph, EnumGraphTraversalType.DFS);
const dijkstraIterator = createGraphIterator(graph, EnumGraphTraversalType.DIJKSTRA);

Traversal Strategies

Breadth-First Search (BFS)

BFS explores the graph level by level, starting from the initial vertex. It's ideal for finding the shortest path in unweighted graphs.

typescript
const bfs = createGraphIterator(graph, EnumGraphTraversalType.BFS);
bfs.initIterator(startVertex);

console.log("BFS traversal:");
while (bfs.hasNext()) {
  console.log(bfs.next());
}

Use cases for BFS:

  • Finding shortest paths in unweighted graphs
  • Level-order traversal of trees
  • Web crawling
  • Social network friend suggestions (friends of friends)
  • Network broadcasting

Depth-First Search (DFS)

DFS explores as far as possible along each branch before backtracking. It's useful for exploring all possible paths.

typescript
const dfs = createGraphIterator(graph, EnumGraphTraversalType.DFS);
dfs.initIterator(startVertex);

console.log("DFS traversal:");
while (dfs.hasNext()) {
  console.log(dfs.next());
}

Use cases for DFS:

  • Path finding
  • Topological sorting
  • Detecting cycles in graphs
  • Solving puzzles (like mazes)
  • Connected components detection
  • Tree traversals (pre-order, in-order, post-order)

Dijkstra's Algorithm

Dijkstra's algorithm finds the shortest paths from a starting vertex to all other vertices in a weighted graph.

typescript
const dijkstra = createGraphIterator(graph, EnumGraphTraversalType.DIJKSTRA);
dijkstra.initIterator(startVertex);

// Get shortest path to target
const shortestPath = dijkstra.getPath(startVertex, targetVertex);
console.log("Shortest path:", shortestPath);

Use cases for Dijkstra:

  • GPS navigation systems
  • Network routing protocols
  • Flight reservation systems
  • Any scenario requiring shortest path in weighted graphs

Practical Examples

Social Network Analysis

typescript
// Create a social network graph
const socialGraph = createGraph<string>(EnumGraphType.UNDIRECTED);
// ... add users and friendships

// Find friends of friends using BFS
function findFriendsOfFriends(graph: IGraph<string>, user: string, maxDistance: number = 2) {
  const bfs = createGraphIterator(graph, EnumGraphTraversalType.BFS);
  bfs.initIterator(user);
  
  const connections: Record<string, number> = {};
  let distance = 0;
  
  while (bfs.hasNext() && distance < maxDistance) {
    const current = bfs.next();
    if (current !== user) {
      connections[current] = distance;
    }
    // In a real implementation, you would track the current level
    distance++;
  }
  
  return connections;
}

const suggestions = findFriendsOfFriends(socialGraph, "Alice", 2);

Pathfinding in Games

typescript
// Create a game map as a graph
const gameMap = createGraph<string>(EnumGraphType.DIRECTED);
// ... define rooms and connections with movement costs

// Find shortest path between rooms
function findPath(start: string, end: string): string[] | null {
  try {
    const dijkstra = createGraphIterator(gameMap, EnumGraphTraversalType.DIJKSTRA);
    dijkstra.initIterator(start);
    return dijkstra.getPath(start, end);
  } catch (error) {
    console.log("No path found between", start, "and", end);
    return null;
  }
}

const path = findPath("Entrance", "Treasure Room");
if (path) {
  console.log("Path to treasure:", path.join(" -> "));
}

Web Crawling Simulation

typescript
// Create a web graph
const webGraph = createGraph<string>(EnumGraphType.DIRECTED);
// ... add web pages and hyperlinks

// Crawl the web using BFS
function crawlWebsite(startUrl: string, maxPages: number) {
  const bfs = createGraphIterator(webGraph, EnumGraphTraversalType.BFS);
  bfs.initIterator(startUrl);
  
  const crawled: string[] = [];
  let count = 0;
  
  while (bfs.hasNext() && count < maxPages) {
    const page = bfs.next();
    crawled.push(page);
    count++;
    
    // Simulate page processing
    console.log("Crawling:", page);
  }
  
  return crawled;
}

const crawledPages = crawlWebsite("https://example.com", 100);

Iterator Lifecycle

Initialization

All graph iterators must be initialized with a starting vertex before use:

typescript
iterator.initIterator(startVertex);

State Management

Each iterator maintains its own traversal state:

typescript
// Multiple iterators can traverse the same graph differently
const bfs1 = createGraphIterator(graph, EnumGraphTraversalType.BFS);
const bfs2 = createGraphIterator(graph, EnumGraphTraversalType.BFS);

bfs1.initIterator("A");
bfs2.initIterator("B");

// These will produce different traversal orders

Path Retrieval

Dijkstra's iterator can retrieve shortest paths between vertices:

typescript
const dijkstra = createGraphIterator(graph, EnumGraphTraversalType.DIJKSTRA);
dijkstra.initIterator(start);

// Get path to any reachable vertex
dijkstra.getPath(start, destination);

Best Practices

Choose the Right Algorithm

  • Use BFS for shortest paths in unweighted graphs
  • Use DFS for exhaustive search and path exploration
  • Use Dijkstra for shortest paths in weighted graphs

Error Handling

typescript
try {
  const iterator = createGraphIterator(graph, traversalType);
  iterator.initIterator(startVertex);
} catch (error) {
  if (error instanceof IllegalArgumentException) {
    console.error("Invalid traversal mode:", error.message);
  }
}

Performance Considerations

  • BFS and DFS: O(V + E) time complexity
  • Dijkstra: O((V + E) log V) time complexity
  • BFS uses more memory (queue) than DFS (stack)
  • For very large graphs, consider iterative implementations to avoid stack overflow

Next Steps

After mastering graph iterators, explore:

  • Graph Presenters for visualizing your graphs
  • Topological Sort for ordering dependent tasks
  • Custom graph algorithms built on top of these iterators
  • Performance optimization techniques for large-scale graph processing

MIT Licensed