Skip to main content
Android Development with Kotlin
CHAPTER 30 Beginner

Course Capstone Project

Updated: May 16, 2026
15 min read

# CHAPTER 30

Course Capstone Project: In-Memory Database

1. Introduction

Welcome to the final chapter! Over the past 29 lessons, you have dissected the fundamental building blocks of software engineering. You have manipulated physical RAM with Arrays and Linked Lists, established hierarchy with Trees, enforced constraints with Stacks and Queues, mapped networks with Graphs, and accelerated processing with Hash Maps and Advanced Sorting. However, in the enterprise world, you never use just *one* data structure. Senior architecture involves combining multiple data structures to cover each other's weaknesses. In this Capstone, we will synthesize your knowledge to architect the core engine of a high-performance In-Memory Database (like Redis).

2. Project Requirements & Architecture

We are tasked with building a database engine that holds User Profile data in RAM. It must fulfill three strict system requirements:
  1. 1. Instant Retrieval: Finding a specific user by their ID string must be executed in absolute O(1) time.
  1. 2. Range Queries & Sorting: The database must be able to instantly output all users perfectly sorted by their Age, providing O(log n) lookup speeds for ranges (e.g., "Find all users older than 25").
  1. 3. Transaction Rollback: If an administrator accidentally deletes a user, the system must have an "Undo" feature to instantly restore the most recently deleted user.

3. Choosing the Data Structures

To satisfy these conflicting requirements, we must intelligently weave three distinct structures together:
  • Requirement 1 (O(1) Retrieval): We need a Hash Map. The Key will be the UserID, and the Value will be the User Object.
  • Requirement 2 (Sorted Age Queries): Hash Maps are totally chaotic. We need a parallel Binary Search Tree (BST) / Red-Black Tree. We will insert the Age as the BST node key, allowing blazing fast In-Order Traversals for sorted outputs.
  • Requirement 3 (Undo Functionality): We need a Stack. A Stack perfectly enforces the LIFO (Last In, First Out) mathematical rule required for reverting chronological actions.

4. The Implementation (Java)

#### Step 1: Define the Data Model

java
12345678910
// The standard data container
class User {
    String userId;
    String name;
    int age;

    public User(String id, String n, int a) {
        this.userId = id; this.name = n; this.age = a;
    }
}

#### Step 2: Architect the Database Engine We instantiate the core trio of data structures to operate simultaneously. *(Note: We utilize Java's TreeMap, which is a native Red-Black Self-Balancing BST).*

java
123456789101112131415161718192021
import java.util.*;

public class CoreDatabaseEngine {
    // 1. The O(1) Hash Map for Instant Lookup by ID
    private HashMap<String, User> userLookup;
    
    // 2. The O(log n) BST for Sorted Data by Age
    // Maps Age -> List of Users (because multiple users can have the same age!)
    private TreeMap<Integer, List<User>> ageIndex;
    
    // 3. The Stack for LIFO Undo Operations
    private Stack<User> deletionHistory;

    public CoreDatabaseEngine() {
        userLookup = new HashMap<>();
        ageIndex = new TreeMap<>();
        deletionHistory = new Stack<>();
    }
    
    // ... Methods will be added here ...
}

#### Step 3: The Insertion Logic (O(log n)) When a user is created, we must surgically insert their data into BOTH the Hash Map and the BST to keep our indexes perfectly synchronized.

java
123456789101112131415
    public void insertUser(String id, String name, int age) {
        User newUser = new User(id, name, age);
        
        // 1. Inject into the Hash Map O(1)
        userLookup.put(id, newUser);
        
        // 2. Inject into the BST Index O(log n)
        // If the age bracket doesn't exist, create a new list branch
        if (!ageIndex.containsKey(age)) {
            ageIndex.put(age, new ArrayList<>());
        }
        ageIndex.get(age).add(newUser);
        
        System.out.println("Inserted: " + name);
    }

#### Step 4: O(1) Search and O(log n) Range Queries Now we harvest the power of our architecture!

java
12345678910111213141516171819
    // Fast O(1) Search utilizing the Hash Map
    public User findUserById(String id) {
        return userLookup.get(id); 
    }

    // Fast O(log n) Range Query utilizing the Binary Search Tree
    public void printUsersOlderThan(int thresholdAge) {
        System.out.println("Users older than " + thresholdAge + ":");
        
        // The BST natively provides a .tailMap() function to instantly chop 
        // the tree and only traverse the Right subtrees larger than the threshold!
        SortedMap<Integer, List<User>> rightBranches = ageIndex.tailMap(thresholdAge, false);
        
        for (List<User> userList : rightBranches.values()) {
            for (User u : userList) {
                System.out.println(u.name + " (Age: " + u.age + ")");
            }
        }
    }

#### Step 5: Deletion and the LIFO Undo Stack When deleting, we push the corpse of the data into the Stack. When undoing, we pop it back to life!

java
123456789101112131415161718192021222324252627
    public void deleteUser(String id) {
        if (!userLookup.containsKey(id)) return;
        
        // 1. Extract the user from the Hash Map
        User deletedUser = userLookup.remove(id);
        
        // 2. Extract the user from the BST Index
        ageIndex.get(deletedUser.age).remove(deletedUser);
        
        // 3. Push to the Undo Stack O(1)
        deletionHistory.push(deletedUser);
        System.out.println("Deleted: " + deletedUser.name);
    }

    public void undoDelete() {
        if (deletionHistory.isEmpty()) {
            System.out.println("Nothing to Undo!");
            return;
        }
        
        // 1. Pop the LIFO Stack
        User restoredUser = deletionHistory.pop();
        
        // 2. Re-insert the data into the database engines
        insertUser(restoredUser.userId, restoredUser.name, restoredUser.age);
        System.out.println("UNDO SUCCESS: Restored " + restoredUser.name);
    }

5. Execution and Testing

Let's spin up the engine and run the code.
java
123456789101112131415161718
public static void main(String[] args) {
    CoreDatabaseEngine db = new CoreDatabaseEngine();
    
    db.insertUser("U101", "Alice", 28);
    db.insertUser("U102", "Bob", 45);
    db.insertUser("U103", "Charlie", 32);
    
    // O(1) Hash Map fetch
    System.out.println("Found: " + db.findUserById("U101").name); 
    
    // O(log n) BST fetch
    db.printUsersOlderThan(30); 
    // Output: Charlie (Age: 32), Bob (Age: 45) -> Perfectly Sorted!
    
    // Test the Stack Undo logic
    db.deleteUser("U103");
    db.undoDelete(); // Restores Charlie!
}

6. Complexity Analysis Conclusion

Look at what we accomplished by combining architectures:
  • We sacrificed Space Complexity (Our RAM footprint doubled because we store memory pointers to the User in both the Hash Map and the Tree).
  • In exchange, we achieved Ultimate Time Complexity. We have O(1) instant lookup by ID, while simultaneously maintaining a perfectly sorted O(log n) Tree for mathematical range queries, guarded by an O(1) LIFO Stack mechanism.
This is what it means to be a Senior Software Engineer: understanding the mathematical trade-offs to bend RAM and CPU logic to your absolute will.

7. Final Words

Data Structures and Algorithms are not just arbitrary puzzles designed by interviewers. They are the fundamental physics of the digital universe. Every time you send a text, stream a movie, or search the web, you are interacting with arrays, trees, hash maps, and graphs. You now possess the foundational knowledge to understand the architecture of the modern world. Keep practicing, keep optimizing, and never stop building.

Congratulations on completing the Data Structures and Algorithms curriculum!

8. Course Completion MCQs

Question 1

In the Capstone architecture, why was it mathematically necessary to combine a Hash Map and a Binary Search Tree (BST) into a unified engine?

Question 2

What Data Structure serves as the universal mathematical foundation for architecting "Undo/Redo" functionality across all software applications?

Question 3

When the architectural design mandates storing data in both a Hash Map and a BST simultaneously, what happens to the overall System Space Complexity?

Question 4

The Capstone codebase utilized Java's native TreeMap. What highly advanced, self-correcting algorithmic structure fundamentally powers TreeMap under the hood?

Question 5

By successfully completing this curriculum, what primary philosophical transformation have you achieved regarding software engineering?

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·