From 461cf101bfda730622f0207a77307f1c3da50137 Mon Sep 17 00:00:00 2001
From: Daaimah Tibrey <41805952+daaimah123@users.noreply.github.com>
Date: Thu, 12 Jun 2025 05:00:45 -0700
Subject: [PATCH 1/2] Create red-black-self-balancing-tree.md
---
algorithms/red-black-self-balancing-tree.md | 569 ++++++++++++++++++++
1 file changed, 569 insertions(+)
create mode 100644 algorithms/red-black-self-balancing-tree.md
diff --git a/algorithms/red-black-self-balancing-tree.md b/algorithms/red-black-self-balancing-tree.md
new file mode 100644
index 000000000..7b8a1aff5
--- /dev/null
+++ b/algorithms/red-black-self-balancing-tree.md
@@ -0,0 +1,569 @@
+# Red-Black Trees: Mastering Self-Balancing Binary Search Trees
+
+## What You'll Discover
+- The fascinating world of self-balancing trees
+- How Red-Black Trees maintain perfect balance automatically
+- Real-world applications that power your favorite software
+- Hands-on implementation and visualization techniques
+
+## ⏰ Time Commitment
+
+**Total Time: 4-6 hours**
+- Reading & Theory: 2 hours
+- Hands-on Activities: 2-3 hours
+- Practice Problems: 1-2 hours
+
+_**Take breaks! Complex data structures need time to sink in.**_
+
+## 🔗 Prerequisites
+- **[Trees](https://github.com/Techtonica/curriculum/blob/main/data-structures/trees.md)**
+- **[Recursion](https://github.com/Techtonica/curriculum/tree/main/recursion)**
+
+## 🎯 Motivation
+Imagine you're building a contact app. With a regular binary search tree, if users add contacts in alphabetical order, your tree becomes a glorified linked list - searches take forever!
+
+Red-Black Trees solve this elegantly. They're the secret sauce behind:
+- **Java's TreeMap and TreeSet** - Lightning-fast sorted collections
+- **C++ STL's map and set** - The backbone of competitive programming
+- **Linux's Completely Fair Scheduler** - How your computer decides which programs run when
+- **Database indexing systems** - Making your queries blazingly fast
+
+### The Real-World Impact
+When Netflix recommends your next binge-watch or when Google Maps finds the fastest route home, balanced trees like Red-Black Trees are working behind the scenes, ensuring operations stay fast even with millions of data points.
+
+## 🎯 Learning Objectives
+By the end of this lesson, you'll be able to:
+
+1. **Explain** the five fundamental properties that make a Red-Black Tree special
+2. **Visualize** how rotations maintain tree balance during insertions and deletions
+3. **Implement** a working Red-Black Tree with insertion operations
+4. **Analyze** why Red-Black Trees guarantee O(log n) performance
+5. **Compare** Red-Black Trees with other self-balancing alternatives
+6. **Apply** Red-Black Tree concepts to solve real-world problems
+
+## 📖 Specific Things to Learn
+
+### Core Concepts
+
+#### 1. The Five Sacred Rules of Red-Black Trees
+
+Every Red-Black Tree must follow these non-negotiable rules:
+
+1. **Every node is either red or black**
+2. **The root is always black**
+3. **All leaves (NIL nodes) are black**
+4. **Red nodes cannot have red children** (no two red nodes can be adjacent)
+5. **Every path from root to leaf contains the same number of black nodes**
+
+#### 2. Understanding Tree Rotations
+
+Rotations are the magic that keeps trees balanced. Think of them as carefully choreographed dance moves:
+
+
+🔄 Left Rotation Implementation
+
+```javascript
+function leftRotate(tree, x) {
+ // Store the right child - this will become the new root of this subtree
+ let y = x.right;
+
+ // Move y's left subtree to become x's right subtree
+ x.right = y.left;
+ if (y.left !== null) {
+ y.left.parent = x;
+ }
+
+ // Update y's parent to point to x's current parent
+ y.parent = x.parent;
+
+ // Update x's parent to point to y instead of x
+ if (x.parent === null) {
+ tree.root = y; // y becomes the new root
+ } else if (x === x.parent.left) {
+ x.parent.left = y;
+ } else {
+ x.parent.right = y;
+ }
+
+ // Make x the left child of y
+ y.left = x;
+ x.parent = y;
+}
+```
+
+
+
+🔄 Right Rotation Implementation
+
+```javascript
+function rightRotate(tree, y) {
+ // Store the left child - this will become the new root of this subtree
+ let x = y.left;
+
+ // Move x's right subtree to become y's left subtree
+ y.left = x.right;
+ if (x.right !== null) {
+ x.right.parent = y;
+ }
+
+ // Update x's parent to point to y's current parent
+ x.parent = y.parent;
+
+ // Update y's parent to point to x instead of y
+ if (y.parent === null) {
+ tree.root = x; // x becomes the new root
+ } else if (y === y.parent.left) {
+ y.parent.left = x;
+ } else {
+ y.parent.right = x;
+ }
+
+ // Make y the right child of x
+ x.right = y;
+ y.parent = x;
+}
+```
+
+
+#### 3. Node Structure and Basic Operations
+
+
+🏗️ Red-Black Tree Node Class
+
+```javascript
+class RBNode {
+ constructor(data) {
+ this.data = data;
+ this.color = 'RED'; // New nodes start as red
+ this.left = null;
+ this.right = null;
+ this.parent = null;
+ }
+
+ // Helper method to check if node is red
+ isRed() {
+ return this.color === 'RED';
+ }
+
+ // Helper method to check if node is black
+ isBlack() {
+ return this.color === 'BLACK';
+ }
+
+ // Get the grandparent of this node
+ grandparent() {
+ if (this.parent && this.parent.parent) {
+ return this.parent.parent;
+ }
+ return null;
+ }
+
+ // Get the uncle of this node (parent's sibling)
+ uncle() {
+ const gp = this.grandparent();
+ if (!gp) return null;
+
+ if (this.parent === gp.left) {
+ return gp.right;
+ } else {
+ return gp.left;
+ }
+ }
+}
+```
+
+
+#### 4. The Insertion Algorithm
+
+Insertion in Red-Black Trees happens in two phases:
+1. **Standard BST insertion** (insert as red node)
+2. **Fix any violations** of Red-Black properties
+
+
+🔧 Complete Insertion Implementation
+
+```javascript
+class RedBlackTree {
+ constructor() {
+ this.root = null;
+ }
+
+ insert(data) {
+ // Phase 1: Standard BST insertion
+ const newNode = new RBNode(data);
+
+ if (!this.root) {
+ this.root = newNode;
+ newNode.color = 'BLACK'; // Root must be black
+ return;
+ }
+
+ // Find the correct position
+ let current = this.root;
+ let parent = null;
+
+ while (current) {
+ parent = current;
+ if (data < current.data) {
+ current = current.left;
+ } else if (data > current.data) {
+ current = current.right;
+ } else {
+ return; // Duplicate values not allowed
+ }
+ }
+
+ // Insert the new node
+ newNode.parent = parent;
+ if (data < parent.data) {
+ parent.left = newNode;
+ } else {
+ parent.right = newNode;
+ }
+
+ // Phase 2: Fix any Red-Black violations
+ this.fixInsertViolations(newNode);
+ }
+
+ fixInsertViolations(node) {
+ // Continue until we reach root or parent is black
+ while (node !== this.root && node.parent.isRed()) {
+ const parent = node.parent;
+ const grandparent = node.grandparent();
+ const uncle = node.uncle();
+
+ if (parent === grandparent.left) {
+ // Parent is left child of grandparent
+ if (uncle && uncle.isRed()) {
+ // Case 1: Uncle is red - recolor
+ parent.color = 'BLACK';
+ uncle.color = 'BLACK';
+ grandparent.color = 'RED';
+ node = grandparent;
+ } else {
+ // Uncle is black or null
+ if (node === parent.right) {
+ // Case 2: Node is right child - left rotate
+ node = parent;
+ this.leftRotate(node);
+ }
+ // Case 3: Node is left child - recolor and right rotate
+ node.parent.color = 'BLACK';
+ node.grandparent().color = 'RED';
+ this.rightRotate(node.grandparent());
+ }
+ } else {
+ // Parent is right child of grandparent (mirror cases)
+ if (uncle && uncle.isRed()) {
+ parent.color = 'BLACK';
+ uncle.color = 'BLACK';
+ grandparent.color = 'RED';
+ node = grandparent;
+ } else {
+ if (node === parent.left) {
+ node = parent;
+ this.rightRotate(node);
+ }
+ node.parent.color = 'BLACK';
+ node.grandparent().color = 'RED';
+ this.leftRotate(node.grandparent());
+ }
+ }
+ }
+
+ // Ensure root is always black
+ this.root.color = 'BLACK';
+ }
+}
+```
+
+
+## 🎮 Hands-On Activities
+
+### Activity 1: Visualizing Red-Black Properties (30 minutes)
+
+**Goal**: Build intuition for what makes a tree "Red-Black compliant"
+
+1. **Draw these trees and identify which ones are valid Red-Black Trees:**
+
+ Tree A:
+ ```
+ 8(B)
+ / \
+ 4(R) 12(R)
+ / \ / \
+ 2(B) 6(B) 10(B) 14(B)
+ ```
+
+ Tree B:
+ ```
+ 10(B)
+ / \
+ 5(R) 15(B)
+ / \ \
+ 3(R) 7(R) 18(R)
+ ```
+
+ Tree C:
+ ```
+ 20(B)
+ / \
+ 10(R) 30(R)
+ / \ / \
+ 5(R) 15(B) 25(R) 35(B)
+ ```
+
+2. **For invalid trees, explain which rule they violate**
+3. **Practice counting black-height for each path**
+
+**Answer Key** (for instructors):
+- Tree A: ✅ Valid - follows all Red-Black properties
+- Tree B: ❌ Invalid - violates Rule 4 (red node 5 has red children 3 and 7)
+- Tree C: ❌ Invalid - violates Rule 4 (red node 10 has red child 5, red node 30 has red child 25)
+
+
+### Activity 2: Step-by-Step Insertion Walkthrough (45 minutes)
+
+**Goal**: Master the insertion algorithm by tracing through examples
+
+Start with an empty Red-Black Tree and insert these values in order: `10, 5, 15, 3, 7, 12, 18, 1`
+
+For each insertion:
+
+1. Show the tree after standard BST insertion
+2. Identify any Red-Black violations
+3. Apply the appropriate fix (recoloring or rotation)
+4. Draw the final tree state
+
+
+
+💡 Insertion Walkthrough Helper Code
+
+```javascript
+// Helper function to visualize tree state
+function printTree(node, prefix = "", isLast = true) {
+if (node === null) return;
+
+console.log(prefix + (isLast ? "└── " : "├── ") +
+ node.data + "(" + node.color[0] + ")");
+
+const children = [];
+if (node.left) children.push([node.left, false]);
+if (node.right) children.push([node.right, true]);
+
+children.forEach(([child, isLastChild], index) => {
+ const isLastInGroup = index === children.length - 1;
+ printTree(child,
+ prefix + (isLast ? " " : "│ "),
+ isLastChild && isLastInGroup);
+ });
+}
+
+// Usage after each insertion
+const tree = new RedBlackTree();
+tree.insert(10);
+console.log("After inserting 10:");
+printTree(tree.root);
+```
+
+
+### Activity 3: Build a Red-Black Tree Validator (60 minutes)
+
+**Goal**: Implement a function that checks if a tree satisfies all Red-Black properties
+
+
+🔍 Tree Validator Implementation
+
+```javascript
+class RBTreeValidator {
+static validate(tree) {
+if (!tree.root) return { valid: true, message: "Empty tree is valid" };
+ const results = {
+ rule1: this.checkRule1(tree.root),
+ rule2: this.checkRule2(tree.root),
+ rule3: this.checkRule3(tree.root),
+ rule4: this.checkRule4(tree.root),
+ rule5: this.checkRule5(tree.root)
+ };
+
+ const allValid = Object.values(results).every(r => r.valid);
+
+ return {
+ valid: allValid,
+ details: results,
+ message: allValid ? "Tree is a valid Red-Black Tree!" : "Tree violates Red-Black properties"
+ };
+}
+
+// Rule 1: Every node is either red or black
+static checkRule1(node) {
+ if (!node) return { valid: true };
+
+ const validColor = node.color === 'RED' || node.color === 'BLACK';
+ if (!validColor) {
+ return { valid: false, message: \`Node \${node.data} has invalid color: \${node.color}\` };
+ }
+
+ const leftCheck = this.checkRule1(node.left);
+ const rightCheck = this.checkRule1(node.right);
+
+ return {
+ valid: leftCheck.valid && rightCheck.valid,
+ message: leftCheck.message || rightCheck.message
+ };
+}
+
+// Rule 2: Root is black
+static checkRule2(root) {
+ return {
+ valid: root.color === 'BLACK',
+ message: root.color === 'BLACK' ? null : "Root must be black"
+ };
+}
+
+// Rule 4: Red nodes cannot have red children
+static checkRule4(node) {
+ if (!node) return { valid: true };
+
+ if (node.color === 'RED') {
+ const leftRed = node.left && node.left.color === 'RED';
+ const rightRed = node.right && node.right.color === 'RED';
+
+ if (leftRed || rightRed) {
+ return {
+ valid: false,
+ message: \`Red node \${node.data} has red child\`
+ };
+ }
+ }
+
+ const leftCheck = this.checkRule4(node.left);
+ const rightCheck = this.checkRule4(node.right);
+
+ return {
+ valid: leftCheck.valid && rightCheck.valid,
+ message: leftCheck.message || rightCheck.message
+ };
+}
+
+// Rule 5: All paths have same black height
+static checkRule5(node) {
+ const getBlackHeight = (n) => {
+ if (!n) return 1; // NIL nodes are black
+
+ const leftHeight = getBlackHeight(n.left);
+ const rightHeight = getBlackHeight(n.right);
+
+ if (leftHeight === -1 || rightHeight === -1 || leftHeight !== rightHeight) {
+ return -1; // Invalid
+ }
+
+ return leftHeight + (n.color === 'BLACK' ? 1 : 0);
+ };
+
+ const height = getBlackHeight(node);
+ return {
+ valid: height !== -1,
+ message: height === -1 ? "Black heights are not equal on all paths" : null
+ };
+ }
+}
+```
+
+
+### Activity 4: Performance Comparison Lab (45 minutes)
+
+**Goal**: See the performance benefits of Red-Black Trees in action
+
+Create a performance testing suite that compares:
+
+- Regular BST with sorted input (worst case)
+- Red-Black Tree with sorted input
+- Both trees with random input
+
+
+
+⚡ Performance Testing Code
+
+```javascript
+class PerformanceTester {
+static testInsertion(TreeClass, data, label) {
+const tree = new TreeClass();
+const startTime = performance.now();
+
+ data.forEach(value => tree.insert(value));
+
+ const endTime = performance.now();
+ const height = this.getHeight(tree.root);
+
+ console.log(\`\${label}:\`);
+ console.log(\` Time: \${(endTime - startTime).toFixed(2)}ms\`);
+ console.log(\` Height: \${height}\`);
+ console.log(\` Nodes: \${data.length}\`);
+ console.log(\` Efficiency: \${(height / Math.log2(data.length)).toFixed(2)}x optimal\`);
+ console.log('');
+
+ return { time: endTime - startTime, height, nodes: data.length };
+}
+
+static getHeight(node) {
+ if (!node) return 0;
+ return 1 + Math.max(this.getHeight(node.left), this.getHeight(node.right));
+}
+
+static runComparison() {
+ const sortedData = Array.from({length: 1000}, (_, i) => i + 1);
+ const randomData = [...sortedData].sort(() => Math.random() - 0.5);
+
+ console.log("=== PERFORMANCE COMPARISON ===\n");
+
+ console.log("📈 SORTED INPUT (Worst Case for Regular BST):");
+ this.testInsertion(BinarySearchTree, sortedData, "Regular BST");
+ this.testInsertion(RedBlackTree, sortedData, "Red-Black Tree");
+
+ console.log("🎲 RANDOM INPUT:");
+ this.testInsertion(BinarySearchTree, randomData, "Regular BST");
+ this.testInsertion(RedBlackTree, randomData, "Red-Black Tree");
+ }
+
+}
+
+// Run the comparison
+PerformanceTester.runComparison();
+```
+
+
+## 🧠 Practice Problems
+
+### Problem 1: Red-Black Tree Detective
+
+Given a tree representation, determine if it's a valid Red-Black Tree and explain your reasoning.
+
+### Problem 2: Insertion Sequence Reconstruction
+
+Given a final Red-Black Tree, determine a possible insertion sequence that could have created it.
+
+### Problem 3: Rotation Counter
+
+Implement a modified Red-Black Tree that counts the total number of rotations performed during a series of insertions.
+
+## 🎯 Key Takeaways
+
+- **Red-Black Trees guarantee O(log n) operations** even in worst-case scenarios
+- **The five rules work together** to maintain balance automatically
+- **Rotations and recoloring** are the tools that fix violations
+- **Real-world applications** make Red-Black Trees incredibly valuable
+- **Understanding the "why"** behind each rule helps with implementation
+
+
+## 🚀 Next Steps
+
+Ready to level up? Explore these advanced topics:
+
+- **Red-Black Tree Deletion** - More complex but follows similar patterns
+- **AVL Trees** - Another self-balancing approach with stricter balance
+- **B-Trees** - The database world's favorite balanced tree
+- **Splay Trees** - Self-adjusting trees that bring frequently accessed items to the top
+
+
+*Remember: Data structures are tools to solve problems. Focus on understanding when and why to use Red-Black Trees, not just how to implement them!*
From 7de18bf66350bbce1bdefe2697f5d2da28567f0c Mon Sep 17 00:00:00 2001
From: Daaimah Tibrey <41805952+daaimah123@users.noreply.github.com>
Date: Thu, 12 Jun 2025 13:11:16 -0700
Subject: [PATCH 2/2] formatting
---
algorithms/red-black-self-balancing-tree.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/algorithms/red-black-self-balancing-tree.md b/algorithms/red-black-self-balancing-tree.md
index 7b8a1aff5..947432e67 100644
--- a/algorithms/red-black-self-balancing-tree.md
+++ b/algorithms/red-black-self-balancing-tree.md
@@ -401,7 +401,7 @@ static checkRule1(node) {
const validColor = node.color === 'RED' || node.color === 'BLACK';
if (!validColor) {
- return { valid: false, message: \`Node \${node.data} has invalid color: \${node.color}\` };
+ return { valid: false, message: `Node ${node.data} has invalid color: ${node.color}` };
}
const leftCheck = this.checkRule1(node.left);
@@ -432,7 +432,7 @@ static checkRule4(node) {
if (leftRed || rightRed) {
return {
valid: false,
- message: \`Red node \${node.data} has red child\`
+ message: `Red node ${node.data} has red child`
};
}
}
@@ -496,11 +496,11 @@ const startTime = performance.now();
const endTime = performance.now();
const height = this.getHeight(tree.root);
- console.log(\`\${label}:\`);
- console.log(\` Time: \${(endTime - startTime).toFixed(2)}ms\`);
- console.log(\` Height: \${height}\`);
- console.log(\` Nodes: \${data.length}\`);
- console.log(\` Efficiency: \${(height / Math.log2(data.length)).toFixed(2)}x optimal\`);
+ console.log(`${label}:`);
+ console.log(` Time: ${(endTime - startTime).toFixed(2)}ms`);
+ console.log(` Height: ${height}`);
+ console.log(` Nodes: ${data.length}`);
+ console.log(` Efficiency: ${(height / Math.log2(data.length)).toFixed(2)}x optimal`);
console.log('');
return { time: endTime - startTime, height, nodes: data.length };