Advanced Programming
Master Algorithms, Software Engineering, Design Patterns, Databases, and Professional Development Skills
Algorithms
What is an Algorithm? š§®
The foundation of computer science - step-by-step problem solving
The Treasure Hunt Analogy
Imagine giving directions to a treasure: "Walk 10 steps north, turn left, walk 5 steps, dig under the big oak tree." These precise instructions are an algorithm!
A computer algorithm works the same way. It takes an input, follows specific steps, and produces an output. Different algorithms can solve the same problem - some are faster, some use less memory.
Why Algorithms Matter?
Google Search processes billions of pages in milliseconds. That's not magic - it's smart algorithms! Good algorithms make slow computers fast; bad algorithms make fast computers slow.
Algorithm Characteristics
Input
Takes zero or more inputs
Output
Produces at least one output
Definiteness
Each step is clear and unambiguous
Finiteness
Must end after finite steps
Big O Notation - Measuring Speed š
Learn how to measure how fast your code runs
The Race Track Analogy
Imagine two cars racing from New York to Los Angeles. One is a Ferrari, the other is a bicycle. The Ferrari takes 30 hours (fast!), the bicycle takes 30 days (slow!).
Big O Notation is like a speedometer for code! It tells us how much time (or memory) our code needs as the data grows. Does it take 1 second for 100 items? What about 1 million items?
Why Does It Matter?
Facebook has 3 billion users! If their "Find Friend" feature was slow (like checking every user one by one), it would take forever. But with a fast algorithm, it takes milliseconds!
Big O Complexity Chart
// O(1) - Constant Time (Always 1 step)
function getFirstItem(array) {
return array[0]; // Instant, no matter how big the array!
}
// O(n) - Linear Time (Steps = items)
function findMax(array) {
let max = array[0];
for (let i = 0; i < array.length; i++) {
if (array[i] > max) max = array[i]; // Check each item once
}
return max;
}
// O(n²) - Quadratic Time (Steps = items à items)
function findDuplicates(array) {
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < array.length; j++) {
// Nested loops = slower!
}
}
}
Searching Algorithms - Finding Things š
Linear Search vs Binary Search - Finding items fast!
The Library Analogy
Imagine looking for a book in a messy pile. You check one by one from the top. This is Linear Search - simple but slow for big piles.
Now imagine a library with books sorted alphabetically. You open the middle shelf - is your book before or after "M"? You eliminate half the library instantly! This is Binary Search - super fast!
Game Example: Finding a Player
In a game with 1 million players, finding someone by Linear Search might take 1 second. Binary Search finds them in just 20 steps! That's 50,000 times faster!
Binary Search Visualization
Looking for 30:
Step 1: Check middle (12) ā 30 is bigger ā Search right half
Step 2: Check middle of right (20) ā 30 is bigger ā Search right half
Step 3: Check middle (25) ā 30 is bigger ā Found 30!
Only 3 steps instead of 8! šÆ
// Linear Search - O(n) - Check one by one
function linearSearch(array, target) {
for (let i = 0; i < array.length; i++) {
if (array[i] === target) {
return i; // Found it at index i!
}
}
return -1; // Not found
}
// Binary Search - O(log n) - Divide and conquer!
// ONLY works on sorted arrays!
function binarySearch(array, target) {
let left = 0;
let right = array.length - 1;
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (array[mid] === target) {
return mid; // Found it!
} else if (array[mid] < target) {
left = mid + 1; // Target is in right half
} else {
right = mid - 1; // Target is in left half
}
}
return -1; // Not found
}
Sorting Algorithms - Putting Things in Order š
Bubble Sort, Selection Sort, Merge Sort - Organizing data!
The Card Sorting Analogy
Imagine you have a messy pile of playing cards. How do you sort them from A to K?
Bubble Sort: Compare adjacent cards, swap if out of order. Like bubbles rising to the top! Simple but slow for many cards.
Merge Sort: Split the pile in half, sort each half, then merge. Much faster! Like having two friends sort half each, then combining.
Sorting Speed Comparison
Bubble Sort - O(n²)
For 1000 items: ~1,000,000 comparisons
Merge Sort - O(n log n)
For 1000 items: ~10,000 comparisons
// Bubble Sort - Simple but slow
function bubbleSort(array) {
let n = array.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i - 1; j++) {
// If current is bigger than next, swap them
if (array[j] > array[j + 1]) {
[array[j], array[j + 1]] = [array[j + 1], array[j]];
}
}
}
return array;
}
// Selection Sort - Find smallest, put first
function selectionSort(array) {
for (let i = 0; i < array.length; i++) {
let minIndex = i;
// Find the smallest in remaining array
for (let j = i + 1; j < array.length; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
// Swap with first unsorted position
[array[i], array[minIndex]] = [array[minIndex], array[i]];
}
return array;
}
Recursion - Functions Calling Themselves šŖ
Solving big problems by breaking them into smaller ones
The Russian Doll Analogy
Russian nesting dolls open to reveal a smaller doll inside, which opens to reveal an even smaller doll, until you reach the tiniest solid doll.
Recursion is like that! A function solves a problem by calling itself with a smaller version of the same problem, until it reaches the simplest case (the tiny doll).
Important: The Base Case!
Every recursive function needs a base case (when to stop) and a recursive case (when to call itself). Without a base case, it's like dolls that never end - infinite recursion!
Factorial Recursion Tree
// Factorial: n! = n Ć (n-1) Ć (n-2) Ć ... Ć 1
function factorial(n) {
// Base case: 1! = 1, 0! = 1
if (n <= 1) return 1;
// Recursive case: n! = n Ć (n-1)!
return n * factorial(n - 1);
}
// Sum of array using recursion
function sumArray(array, index = 0) {
// Base case: reached end of array
if (index >= array.length) return 0;
// Recursive case: current + sum of rest
return array[index] + sumArray(array, index + 1);
}
// Countdown using recursion
function countdown(n) {
if (n <= 0) {
console.log("Blast off! š");
return;
}
console.log(n);
countdown(n - 1); // Call with smaller number
}
countdown(5); // 5, 4, 3, 2, 1, Blast off!
Software Engineering
SDLC - Software Development Life Cycle š
The journey from idea to finished software
The Construction Analogy
Building software is like building a house. You don't just start laying bricks! First, you plan (blueprint), then build the foundation, then walls, then finish.
SDLC is the step-by-step process that takes a software idea and turns it into a working product. It helps teams work together and catch problems early!
SDLC Phases
Planning š
What do we build? Who is it for?
Analysis š
Study requirements in detail
Design šØ
Create blueprints and mockups
Development š»
Write the actual code
Testing š
Find and fix bugs
Deployment š
Release to users
Maintenance š§
Keep it running smoothly
/*
PHASE 1 - PLANNING: "Build a 2D platformer game"
- Target: Kids aged 8-12
- Platform: Web browser
- Timeline: 6 months, 3 developers
PHASE 2 - ANALYSIS:
- Tech stack: HTML5 Canvas + JavaScript
- Risks: Browser compatibility, mobile performance
PHASE 3 - DESIGN:
- Character animations: Running, jumping, attacking
- 10 levels with increasing difficulty
- Database for high scores
PHASE 4 - DEVELOPMENT:
- Programmers build game engine
- Artists create sprites
- Sound designers create audio
PHASE 5 - TESTING:
- Check all browsers
- Find and fix bugs
- Security testing
PHASE 6 - DEPLOYMENT:
- Upload to web server
- Create landing page
- Social media announcement
PHASE 7 - MAINTENANCE:
- Fix bugs found by players
- Add new features
- Improve stability
*/
Software Development Models šļø
Waterfall, Agile, Scrum - Different ways to organize work
Development Models
š Waterfall Model
Approach: Linear and sequential
Flow: Plan ā Design ā Code ā Test ā Deploy
Best for: Clear, fixed requirements
ā Clear milestones
ā No early feedback
š Agile Model
Approach: Iterative and flexible
Flow: Small cycles (sprints)
Best for: Projects needing changes
ā Early feedback
ā Needs involvement
š Spiral Model
Approach: Risk-driven, iterative
Flow: Planning ā Risk ā Dev ā Eval
Best for: Large, complex projects
ā Early prototype
ā Can be expensive
// AGILE SPRINT: Building a Todo App (2 weeks)
/*
SPRINT PLANNING (Day 1):
- Pick tasks from backlog
- Goal: "Add reminders and categories"
- Timeline: 2 weeks
DAILY STANDUPS (Every morning, 15 min):
Dev 1: "Built reminder UI yesterday, connecting DB today"
Dev 2: "Fixed category bug, testing notifications today"
Dev 3: "Blocked - need help with timezone"
SPRINT REVIEW (Day 10):
- Demo to stakeholders
- "Users can now set reminders!"
- Feedback: "Add snooze feature next sprint"
SPRINT RETROSPECTIVE:
- Went well: Testing caught bugs early
- Improve: Better timezone handling
- Action: Add timezone library
NEXT SPRINT:
- Snooze feature
- Timezone improvements
*/
Software Architecture - Building Blueprints šļø
MVC, Microservices, Monolith - How to structure your application
The City Planning Analogy
A city needs planning. One giant building with everything? Or many small buildings each doing one thing? How do they connect? Roads? Tunnels?
Software Architecture is city planning for code. It decides how parts of your application connect. Good architecture makes code easy to maintain!
Architecture Patterns
šļø MVC (Model-View-Controller)
UI & Display
Logic & Flow
Data & Logic
Example: Blog - Model (posts), View (HTML), Controller (requests)
š² Monolithic Architecture
Like: One big building with everything. Simple but hard to scale.
š§© Microservices Architecture
Like: Separate buildings connected by roads. Each uses different tech!
// MODEL - Manages data
class UserModel {
constructor() {
this.users = [];
}
addUser(name, email) {
this.users.push({ id: Date.now(), name, email });
}
getUser(id) {
return this.users.find(u => u.id === id);
}
}
// VIEW - Manages display
class UserView {
displayUser(user) {
console.log(`User: ${user.name}`);
}
displayError(msg) {
console.error(`Error: ${msg}`);
}
}
// CONTROLLER - Handles logic
class UserController {
constructor(model, view) {
this.model = model;
this.view = view;
}
createUser(name, email) {
if (!name || !email) {
this.view.displayError("Required!");
return;
}
this.model.addUser(name, email);
this.view.displayUser({ name, email });
}
}
Design Patterns
Creational Patterns - Making Objects š
Singleton, Factory, Builder - Smart ways to create objects
The Factory Analogy
A car factory doesn't build each car from scratch every time. It has blueprints, assembly lines, and quality checks. Design patterns are like these proven factory methods for creating code!
Creational Patterns
š Singleton Pattern
Only ONE instance allowed!
Like: Only one President, one Database connection
getInstance() ā returns the ONE object
š Factory Pattern
Central place to create objects
Like: Pizza factory makes different types of pizzas
createProduct(type) ā returns right object
šØ Builder Pattern
Step-by-step object construction
Like: Building a custom sandwich at Subway
new Builder().setA().setB().build()
// SINGLETON - Only one database connection allowed!
class Database {
constructor() {
if (Database.instance) {
return Database.instance; // Return existing instance
}
this.connection = "Connected!";
Database.instance = this;
}
query(sql) {
console.log(`Running: ${sql}`);
}
}
const db1 = new Database();
const db2 = new Database();
console.log(db1 === db2); // true - Same object!
// FACTORY - Creates different types of objects
class NotificationFactory {
static create(type, message) {
switch(type) {
case "email":
return new EmailNotification(message);
case "sms":
return new SMSNotification(message);
case "push":
return new PushNotification(message);
}
}
}
const notif = NotificationFactory.create("email", "Hello!");
notif.send(); // Sends email notification
Structural Patterns - Connecting Objects š
Adapter, Decorator, Proxy - How objects work together
Structural Patterns
š Adapter Pattern
Makes incompatible interfaces work together
Like: A power adapter for different country plugs
OldSystem ā Adapter ā NewSystemš Decorator Pattern
Adds behavior without changing original
Like: Adding toppings to a pizza, or features to a phone case
BaseObject ā DecoratorA ā DecoratorBš”ļø Proxy Pattern
Controls access to an object
Like: A security guard checking ID before letting you in
Client ā Proxy ā RealObjectBehavioral Patterns - Object Communication š¢
Observer, Strategy, Command - How objects talk to each other
Behavioral Patterns
šļø Observer Pattern
One changes, others get notified
Like: YouTube subscriptions - new video notifies all subscribers
Subject ā [Observer1, Observer2, Observer3]šÆ Strategy Pattern
Swap algorithms at runtime
Like: Navigation app - switch between fastest route vs scenic route
Context.setStrategy(new FastStrategy())š Command Pattern
Encapsulate actions as objects
Like: Restaurant order ticket - waiters write, kitchen executes
Command ā Execute() ā Can also Undo()// OBSERVER PATTERN - YouTube Subscription System
class YouTubeChannel {
constructor(name) {
this.name = name;
this.subscribers = [];
}
subscribe(user) {
this.subscribers.push(user);
console.log(`${user.name} subscribed to ${this.name}`);
}
uploadVideo(videoTitle) {
console.log(`\nš„ New video: "${videoTitle}" on ${this.name}`);
// Notify ALL subscribers!
this.subscribers.forEach(user => {
user.notify(this.name, videoTitle);
});
}
}
class Subscriber {
constructor(name) {
this.name = name;
}
notify(channel, video) {
console.log(`š ${this.name}: New video "${video}" from ${channel}`);
}
}
// Usage
const techChannel = new YouTubeChannel("Code Masters");
const alice = new Subscriber("Alice");
const bob = new Subscriber("Bob");
techChannel.subscribe(alice);
techChannel.subscribe(bob);
techChannel.uploadVideo("Learn JavaScript in 10 Minutes!");
// Output:
// Alice subscribed to Code Masters
// Bob subscribed to Code Masters
// š„ New video: "Learn JavaScript..." on Code Masters
// š Alice: New video from Code Masters
// š Bob: New video from Code Masters
Database & APIs
Database Basics - Storing Data š
SQL, Tables, Relationships - How to organize information
The Filing Cabinet Analogy
Imagine a library with many filing cabinets. Each drawer (table) holds specific information. One drawer for "Users", one for "Books", one for "Borrow Records".
A Database is like this organized filing system! It stores data in tables with rows (records) and columns (fields). SQL is the language to ask questions to the database.
Database Tables Example
š„ Users Table
| id | name | |
|---|---|---|
| 1 | Alice | alice@email.com |
| 2 | Bob | bob@email.com |
| 3 | Carol | carol@email.com |
š Orders Table
| id | user_id | product |
|---|---|---|
| 101 | 1 | Laptop |
| 102 | 2 | Mouse |
| 103 | 1 | Keyboard |
Relationship: user_id connects Orders to Users (Alice has orders 101 & 103)
-- SELECT - Get data from database
SELECT * FROM Users; -- Get ALL users
SELECT name, email FROM Users; -- Get only name and email
SELECT * FROM Users WHERE id = 1; -- Get user with id=1 (Alice)
-- INSERT - Add new data
INSERT INTO Users (name, email)
VALUES ('David', 'david@email.com');
-- UPDATE - Change existing data
UPDATE Users
SET email = 'alice.new@email.com'
WHERE id = 1;
-- DELETE - Remove data
DELETE FROM Users WHERE id = 3; -- Delete Carol
-- JOIN - Combine tables
SELECT Users.name, Orders.product
FROM Users
JOIN Orders ON Users.id = Orders.user_id;
-- Result: Alice | Laptop
-- Alice | Keyboard
-- Bob | Mouse
APIs & HTTP - Talking to Servers š
REST API, HTTP Methods, JSON - How apps communicate
The Restaurant Waiter Analogy
In a restaurant, you (the customer) don't go to the kitchen yourself. You tell the waiter what you want, and they bring it from the kitchen. The waiter is the middleman!
An API (Application Programming Interface) is like that waiter! It's how different apps talk to each other. Your app (customer) asks the API (waiter) for data from the server (kitchen).
HTTP Methods (CRUD Operations)
š Read Data
Get information without changing anything
GET /api/users ā Returns list of users
ā Create Data
Add new data to the server
POST /api/users ā Creates new user
āļø Update Data
Replace existing data completely
PUT /api/users/1 ā Update user 1
šļø Delete Data
Remove data from server
DELETE /api/users/1 ā Remove user 1
// Fetch data from an API (like getting a menu)
async function getUsers() {
try {
const response = await fetch('https://api.example.com/users');
const data = await response.json();
console.log(data); // Array of user objects
} catch (error) {
console.error("Error fetching users:", error);
}
}
// POST - Create new user (like placing an order)
async function createUser(name, email) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name, email })
});
return await response.json();
}
// JSON - JavaScript Object Notation (data format)
const userData = {
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"hobbies": ["coding", "reading"] // Can have arrays!
};
Tools & Best Practices
Version Control - Git & GitHub šæ
Track changes, collaborate, manage code history
The Time Machine Analogy
Imagine writing a story and saving a copy every day. Day 1, Day 2, Day 3... If you mess up on Day 10, you can go back to Day 9's version!
Git is like a time machine for your code! It saves snapshots (commits) of your code. GitHub is like a cloud storage for all these snapshots, so your team can work together.
Git Workflow
Working Directory š»
Your local files where you code
Staging Area ā
Files ready to be saved
Local Repository š¾
Saved snapshot on your computer
Remote Repository āļø
GitHub - shared with team
# Setup a new repository
git init # Initialize git in current folder
git clone https://github.com/user/repo.git # Download existing repo
# Daily workflow
git status # Check what changed
git add filename.js # Stage specific file
git add . # Stage all changes
git commit -m "Added new feature" # Save snapshot with message
git push origin main # Upload to GitHub
# Collaboration
git pull origin main # Download latest changes
git branch feature-login # Create new branch
git checkout feature-login # Switch to branch
git merge feature-login # Combine branches
# Undo mistakes
git log # See commit history
git checkout -- filename.js # Discard file changes
git revert HEAD # Undo last commit
Error Handling - Graceful Failures š”ļø
Try, Catch, Finally - Handling when things go wrong
The Safety Net Analogy
Trapeze artists have safety nets. If they fall, the net catches them instead of crashing to the ground. The show continues!
Error handling is like that safety net! When code "falls" (has an error), we catch it gracefully instead of crashing the whole program.
try {
// Code that might fail
const result = 10 / 0; // Math error!
console.log(result);
const data = JSON.parse("not valid json"); // Parse error!
} catch (error) {
// Runs if ANY error happens in try
console.log("Oops! Something went wrong:");
console.log(error.message); // "Unexpected token..."
// Show user-friendly message
showErrorToUser("Please check your input and try again.");
} finally {
// ALWAYS runs, error or not
console.log("Cleanup: closing connections, hiding loading spinner");
}
// Program continues normally!
console.log("App still running!");
// Custom error throwing
function withdraw(amount) {
if (amount > balance) {
throw new Error("Insufficient funds!");
}
balance -= amount;
}
Async Programming - Non-Blocking Code ā³
Callbacks, Promises, Async/Await - Doing many things at once
The Restaurant Analogy
Synchronous (Blocking): You order food, stand at the counter waiting, not doing anything until food arrives. Then next customer orders.
Asynchronous (Non-blocking): You order food, get a buzzer, sit down. When buzzer rings, you get food. Meanwhile, you can chat, use phone, or the kitchen can cook multiple orders at once!
Synchronous vs Asynchronous
ā±ļø Synchronous (Blocking)
Total: 6 seconds (one after another)
ā” Asynchronous (Non-blocking)
Total: ~3 seconds (all at once!)
// PROMISE - "I promise to give you result later"
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId) {
resolve({ id: userId, name: "Alice" }); // Success!
} else {
reject("User ID required"); // Error!
}
}, 1000); // Wait 1 second (simulating network)
});
}
// ASYNC/AWAIT - Cleaner way to handle promises
async function loadUserProfile() {
try {
console.log("Loading...");
// Wait for data (but don't block other code!)
const user = await fetchUserData(123);
console.log("User loaded:", user);
const posts = await fetchUserPosts(user.id);
console.log("Posts loaded:", posts);
} catch (error) {
console.error("Failed to load:", error);
}
}
// Old way: Callbacks ("callback hell")
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
console.log(c); // Nested callbacks! Hard to read!
});
});
});
File Handling - Working with Files š
Reading, Writing, Processing files and data formats
The Library Card System
Libraries store books in organized sections. They have cards tracking who borrowed what. Computers need similar systems to organize and track files!
const fs = require('fs');
// READ a file
fs.readFile('users.txt', 'utf8', (err, data) => {
if (err) {
console.error("Error reading file:", err);
return;
}
console.log("File contents:", data);
});
// WRITE to a file
const content = "Hello, this is my file!";
fs.writeFile('output.txt', content, (err) => {
if (err) throw err;
console.log("File saved!");
});
// APPEND to a file (add to end)
fs.appendFile('log.txt', "\nNew log entry", (err) => {
if (err) throw err;
});
// Working with JSON files
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
// Save JSON
fs.writeFileSync('users.json', JSON.stringify(users, null, 2));
// Load JSON
const loadedUsers = JSON.parse(fs.readFileSync('users.json', 'utf8'));
console.log(loadedUsers);
Regular Expressions - Pattern Matching š
Regex - Finding and validating text patterns
The Search Filter Analogy
Imagine searching for all phone numbers in a 100-page document. Doing it manually would take hours! Or searching for all email addresses.
Regular Expressions (Regex) are like super-powered search filters! They find patterns in text - emails, phone numbers, dates, passwords, anything!
Common Regex Patterns
// Creating regex patterns
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phonePattern = /^\d{3}-\d{3}-\d{4}$/;
// Test if string matches pattern
emailPattern.test("alice@email.com"); // true ā
emailPattern.test("not-an-email"); // false ā
phonePattern.test("123-456-7890"); // true ā
phonePattern.test("1234567890"); // false ā
// Find and replace
const text = "My email is test@email.com and yours is hello@site.com";
const masked = text.replace(/[^\s@]+@[^\s@]+\.[^\s@]+/g, "***@***.***");
// Result: "My email is ***@***.*** and yours is ***@***.***"
// Extract data
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2024-03-15".match(datePattern);
// match[1] = "2024" (year)
// match[2] = "03" (month)
// match[3] = "15" (day)
// Common regex symbols:
// ^ = start of string
// $ = end of string
// \d = digit (0-9)
// \w = word character (letter, number, _)
// . = any character
// * = 0 or more
// + = 1 or more
// ? = 0 or 1
// {3} = exactly 3
// {2,5} = 2 to 5
Advanced Data Structures
Trees - Hierarchical Data š³
Binary Trees, Binary Search Trees - Organized like family trees
The Family Tree Analogy
A family tree starts with grandparents at the top, then parents, then children. Each person has children below them (descendants) and parents above (ancestors).
A Tree in programming works the same way! It has a root (top), nodes (people), and branches (connections). Perfect for organizing hierarchical data!
Binary Search Tree (BST)
Rule: Left child is always SMALLER, Right child is always BIGGER
class TreeNode {
constructor(value) {
this.value = value;
this.left = null; // Smaller values go left
this.right = null; // Bigger values go right
}
}
class BinarySearchTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new TreeNode(value);
if (!this.root) {
this.root = newNode;
return;
}
let current = this.root;
while (true) {
if (value < current.value) {
if (!current.left) {
current.left = newNode;
return;
}
current = current.left;
} else {
if (!current.right) {
current.right = newNode;
return;
}
current = current.right;
}
}
}
// Search - O(log n) in balanced tree!
search(value) {
let current = this.root;
while (current) {
if (value === current.value) return true;
if (value < current.value) current = current.left;
else current = current.right;
}
return false;
}
}
// Usage
const bst = new BinarySearchTree();
bst.insert(50);
bst.insert(30);
bst.insert(70);
console.log(bst.search(30)); // true
console.log(bst.search(100)); // false
Graphs - Connected Networks šøļø
Nodes and Edges - Modeling connections and relationships
The Road Map Analogy
A city map shows places (nodes) connected by roads (edges). Some roads are one-way, some have different distances. This is exactly how a Graph works!
Graphs model real-world connections: Facebook friends, flight routes, website links, computer networks - anything with relationships!
Social Network Graph
Nodes = People, Edges = Friendships. Finding "friends of friends" = Graph traversal!
class Graph {
constructor() {
this.adjacencyList = {};
}
addVertex(vertex) {
if (!this.adjacencyList[vertex]) {
this.adjacencyList[vertex] = [];
}
}
addEdge(v1, v2) {
this.adjacencyList[v1].push(v2);
this.adjacencyList[v2].push(v1); // Undirected
}
// Breadth First Search - Explore all neighbors first
BFS(start) {
const queue = [start];
const result = [];
const visited = {};
visited[start] = true;
while (queue.length) {
const vertex = queue.shift();
result.push(vertex);
this.adjacencyList[vertex].forEach(neighbor => {
if (!visited[neighbor]) {
visited[neighbor] = true;
queue.push(neighbor);
}
});
}
return result;
}
// Depth First Search - Go deep first, then backtrack
DFS(start) {
const result = [];
const visited = {};
const adjacencyList = this.adjacencyList;
(function dfs(vertex) {
if (!vertex) return null;
visited[vertex] = true;
result.push(vertex);
adjacencyList[vertex].forEach(neighbor => {
if (!visited[neighbor]) {
dfs(neighbor);
}
});
})(start);
return result;
}
}
// Usage
const g = new Graph();
g.addVertex("A"); g.addVertex("B"); g.addVertex("C");
g.addEdge("A", "B"); g.addEdge("B", "C");
console.log(g.BFS("A")); // ["A", "B", "C"]
console.log(g.DFS("A")); // ["A", "B", "C"]