C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
161: Implementing a Binary Search Tree in C++
Alright, so you've mastered linked lists, and now we're branching out—literally. A Binary Search Tree (BST) is where things get interesting because we're moving from linear storage to a hierarchical one. The magic of a BST is that it keeps data sorted as you insert it, which makes searching incredibly fast. I've seen a lot of people overcomplicate the implementation, but if you keep the recursive nature of the tree in mind, it actually clicks pretty quickly.
How do I structure the Node and the Tree class so it's actually manageable?
You don't want your main logic floating around with raw pointers everywhere. The cleanest way to do this in C++ is to define a small Node struct and wrap it inside a BST class. The Node is just a container; the BST class is where the actual "brain" of the operation lives.
struct Node {
int studentId;
Node* left;
Node* right;
Node(int id) : studentId(id), left(nullptr), right(nullptr) {}
};
class BinarySearchTree {
private:
Node* root;
// We'll put our recursive helpers here
public:
BinarySearchTree() : root(nullptr) {}
void insert(int id) {
root = insertRecursive(root, id);
}
// ... other methods
};
I use a studentId here because it's a concrete example of something you'd actually want to index. Notice how the Node is a simple struct. Since it's just a data carrier, it doesn't need a bunch of complex methods; the BinarySearchTree class handles the heavy lifting.
I get the concept, but how do I handle the recursion for inserting nodes without losing the root?
This is where most learners trip up. They try to handle the root as a special case in every single function. Instead, use a private recursive helper function that returns a Node*. This allows the tree to "re-wire" itself as the recursion unwinds.
Node* insertRecursive(Node* current, int id) {
// Base case: we've found the empty spot where this ID belongs
if (current == nullptr) {
return new Node(id);
}
// If the ID is smaller, go left; if larger, go right
if (id < current->studentId) {
current->left = insertRecursive(current->left, id);
} else if (id > current->studentId) {
current->right = insertRecursive(current->right, id);
}
// Return the (potentially updated) current node back up the chain
return current;
}
By returning the node, you're essentially saying, "Here is the updated version of this subtree." It's a very elegant pattern. If the root was nullptr, the first call returns the new node, and root = insertRecursive(root, id) captures it perfectly.
How do I actually find something in the tree without checking every single node?
This is the whole point of the BST. Because we've maintained the rule that "left is smaller, right is larger," we can discard half the remaining tree with every single comparison. It's exactly like looking up a word in a physical dictionary.
bool search(Node* current, int id) {
if (current == nullptr) return false; // Not found
if (current->studentId == id) return true; // Found it!
if (id < current->studentId) {
return search(current->left, id);
} else {
return search(current->right, id);
}
}
I usually implement the public search method as a simple wrapper: bool contains(int id) { return search(root, id); }. This keeps the user of your class from having to deal with the Node* root pointer, which should stay private to avoid someone accidentally deleting the whole tree from main().
If I want to print the elements in sorted order, how do I do that?
There are a few ways to traverse a tree, but for a BST, the "In-Order Traversal" is the gold standard. If you visit the left child, then the current node, then the right child, you will magically print the IDs in perfectly ascending order. It's almost like the tree is doing the sorting for you.
void inOrderTraversal(Node* node) {
if (node == nullptr) return;
inOrderTraversal(node->left); // Visit left subtree
std::cout << node->studentId << " "; // Visit current node
inOrderTraversal(node->right); // Visit right subtree
}
Believe it or not, this is one of the most satisfying moments in learning data structures. You can insert 50, 20, 70, 10, 30 in any order, and inOrderTraversal will always spit out 10, 20, 30, 50, 70. Just remember that you'll need a destructor in your BinarySearchTree class to recursively delete all those nodes, or you'll have a memory leak on your hands.
📋 Practical Task
Implement a Student ID Registry with a Range Search
Your task is to extend the Binary Search Tree implementation. Create a class called StudentRegistry that uses a BST to store student IDs. In addition to the standard insert and search functionality, implement a method called printStudentsInRange(int min, int max).
This method should traverse the tree and print only the student IDs that fall between the min and max values (inclusive), in ascending order. To do this efficiently, your function should avoid visiting subtrees that couldn't possibly contain values within your range.
- Requirement 1: Implement the
insertandinOrdertraversal. - Requirement 2: Implement
printStudentsInRangeusing a recursive approach. - Requirement 3: In your
mainfunction, insert the following IDs:105, 50, 150, 25, 75, 125, 175. - Requirement 4: Call
printStudentsInRange(60, 130)and verify that it prints75, 105, 125.
There are no comments for now.