- Project Overview
- Architecture Overview
- Core Data Structures
- Main Classes
- Key Functions
- Usage Guide
- Data Storage & Persistence
- Example Implementation
The Database Creator is a C++ template-based database system that enables engineers to create custom databases with their own schema through a Binary Search Tree (BST) implementation. The system provides essential database operations including:
- Insertion: Add new records with unique identifiers
- Search: Find records by unique parameter
- Deletion: Remove individual records or entire subtrees
- Persistence: Save and load data to/from files
- Traversal: Navigate and display data in multiple formats (inorder, preorder, postorder, level-order)
Repository: Andrew20371160/Database-Creator
Language: C++ (100%)
Files: bst.h, bst.cpp
The database is built on a template-based Binary Search Tree (BST) architecture with support for custom data types. The main architectural components are:
template <typename DataType>
struct node {
DataType data;
node<DataType>* left;
node<DataType>* right;
node<DataType>* parent;
};Each node stores a generic data type and maintains pointers to left, right, and parent nodes.
bst<DataType>: Generic binary search tree templatecustom_data<unique_data_type>: Custom data container with unique parameter and additional data fieldsother_data: Auxiliary data storage for multiple data types (long, double, string, char, bool)
The system uses a template metaprogramming approach with:
- Generic tree operations independent of data type
- Support for both primitive types (int, double, char) and complex types (custom structures)
- Separation of unique identifying data from auxiliary data
Represents a single BST node with:
- data: The actual payload
- left: Pointer to left subtree
- right: Pointer to right subtree
- parent: Pointer to parent node (for bidirectional traversal)
The main template class providing all database operations.
node<DataType>* root; // Root of the tree
mutable node<DataType>* traverser; // Navigation pointer
long long size; // Number of nodesget_node(): Allocate new nodeis_left(),is_right(),is_root(): Node position checksfix_parent(): Update parent pointersget_max(),get_min(): Find extremal nodescopy_bst(): Deep copy operationsdel_tree(): Recursive tree deletionfill_sorted(): O(N) tree construction from sorted datainorder_save(): Save tree with index file
Enables creation of custom database records with:
template<typename unique_data_type>
class custom_data {
private:
unique_data_type unique_parameter; // Unique key
other_data other; // Additional data
};- L: Long integers (long array)
- D: Double floating-point (double array)
- S: Strings (string array)
- C: Characters (char array)
- B: Booleans (bool array)
Manages allocation and storage of multiple data type arrays:
class other_data {
private:
string* strings;
double* doubles;
long* longs;
char* characters;
bool* booleans;
int data_type_count[5]; // Size of each array
};bst() // Empty tree
bst(const DataType* arr, long long size) // From array
bst(const vector<DataType>& arr) // From vector
bst(const bst& src) // Copy constructorInsertion & Deletion:
bool insert(const DataType& data) // Insert element
bool remove(const DataType& data) // Remove element
bool remove_tree() // Clear entire tree
bool remove_subtree(const DataType& data) // Remove subtreeSearching:
bool search(const DataType& data) const // Find element
DataType access_traverser() // Access found elementTraversal & Display:
void inorder() const // In-order traversal
void preorder() const // Pre-order traversal
void postorder() const // Post-order traversal
void breadth_first() const // Level-order (BFS)
void move() // Interactive navigationFile Operations:
bool save() const // Save with index file
bool load() // Load from file
void save_breadth_first() const // Save tree structure
void load_breadth_first() // Load tree structureUtility:
long long get_size() // Get element count
bool is_sorted(...) // Check if data is sortedOperators:
void operator=(const bst& src) // Assignment
bool operator==(const bst& src) const // Equality
bool operator<(const bst& src) const // Compare max values
bool operator>(const bst& src) const // Compare max values
template<typename T>
ostream& operator<<(ostream&, const bst<T>&) // Print treecustom_data() // Empty
custom_data(const custom_data& src) // Copy
custom_data(int arr[5]) // From array sizes
custom_data(int longs, int doubles, int strings, // Individual sizes
int chars, int bools)Data Access (Accessors):
unique_data_type& at_unique() // Access unique key
long& at_longs(int index) // Access long at index
double& at_doubles(int index) // Access double at index
char& at_chars(int index) // Access char at index
string& at_strings(int index) // Access string at index
bool& at_bools(int index) // Access bool at indexConfiguration:
void set_data_type_size(int data_type_enum, int size) // Resize array
int get_data_type_count(int dt) const // Get array sizeComparison Operators:
bool operator<(const custom_data& src) const // Based on unique_parameter
bool operator>(const custom_data& src) const
bool operator<=(const custom_data& src) const
bool operator>=(const custom_data& src) const
bool operator==(const custom_data& src) const
bool operator!=(const custom_data& src) constConversion & I/O:
string to_string() const // Convert to string
void operator=(const custom_data& src) // Assignment
template<typename T>
ostream& operator<<(ostream&, const custom_data<T>&) // Output streamother_data() // Empty
other_data(int arr[5]) // From array of sizes
other_data(int longs, int doubles, int strings, // Individual parameters
int chars, int bools)~other_data() // Destructor
void operator=(const other_data& other) // Assignment
string to_string() const // Convert to string
bool operator==(const other_data& other) const // Equality (not implemented)bool getInput(char& choice) // Safe character input
bool getInput(int& choice) // Safe integer inputThese functions handle input stream errors gracefully without crashing when invalid input is received.
bool openFileForWriting(const string& filePath)
bool openFileForReading(const string& filePath)Validate file access before operations.
string to_string(const int& data)
string to_string(const double& data)
string to_string(const char& data)
string to_string(const bool& data)
string to_string(const string& data)
string to_string(const float& data)
string to_string(const long& data)
string to_string(const unsigned int& data)
template<typename DataType>
string to_string(const vector<DataType>& vec)Convert various data types to string representation for serialization.
// Vector operations for custom_data
template<typename vector_data_type>
vector_data_type* get_vec(const int size)
template<typename vector_data_type>
void copy_vec(vector_data_type*& dest, const vector_data_type* src,
int& dest_size, const int src_size)
template<typename vector_data_type>
void resize_vec(vector_data_type*& vec, int& old_vec_size, int wanted_size)
template<typename vector_data_type>
string vec_to_string(vector_data_type* vec, int size)
// Breadth-first save/load helper
template<typename DataType>
bool is_null_queue(queue<node<DataType>*>& q)
// Utility
void delay(int milliseconds) // Sleep function for testing// Create a BST for integers
bst<int> intTree;
// Insert values
intTree.insert(50);
intTree.insert(30);
intTree.insert(70);
// Search
if (intTree.search(30)) {
cout << "Found 30\n";
}
// Display in-order
cout << "In-order traversal: ";
intTree.inorder(); // Output: 30 , 50 , 70 ,
// Remove element
intTree.remove(30);
// Get tree size
cout << "Tree size: " << intTree.get_size() << "\n"; // Output: 2// Define enumeration for string indices
enum { FIRST_NAME = 0, LAST_NAME, BIRTH_DATE, CITY };
// Create custom data type (int as unique ID)
// Structure: 1 long (age), 1 double (height), 4 strings, 1 char, 1 bool
custom_data<int> person(1, 1, 4, 1, 1);
// Set up BST for custom data
bst<custom_data<int>> database;
// Populate person record
person.at_unique() = 12345; // ID
person.at_longs(0) = 28; // Age
person.at_doubles(0) = 5.9; // Height
person.at_strings(FIRST_NAME) = "John";
person.at_strings(LAST_NAME) = "Doe";
person.at_strings(BIRTH_DATE) = "1995/05/15";
person.at_strings(CITY) = "New York";
person.at_chars(0) = 'B'; // Hair color
person.at_bools(0) = 1; // Alive status
// Insert into database
database.insert(person);
// Search by ID
if (database.search(person)) {
cout << "Found: " << database.access_traverser().at_strings(FIRST_NAME) << "\n";
}int data[] = {10, 20, 30, 40, 50};
bst<int> tree(data, 5); // O(N) if sorted, O(N log N) otherwise// Save tree
bst<int> tree;
tree.insert(50);
tree.insert(30);
tree.insert(70);
if (tree.save()) {
cout << "Saved successfully\n";
}
// Load tree
bst<int> loadedTree;
if (loadedTree.load()) {
cout << "Loaded successfully\n";
loadedTree.inorder(); // Display loaded data
}bst<int> tree;
// ... populate tree ...
tree.move(); // Interactive mode with controls:
// w: go up (parent)
// a: go left
// d: go right
// s: show whole tree
// r: reset to root
// Enter: stop at current node
// q: quitbst<int> tree1, tree2;
// ... populate both ...
if (tree1 == tree2) {
cout << "Trees are identical\n";
}
if (tree1 < tree2) {
cout << "Max of tree1 < Max of tree2\n";
}The system uses two files for optimal performance:
- Stores actual tree data in in-order traversal
- Format:
data₁\0data₂\0data₃\0... - Null characters (
\0) separate records
- Binary file containing file positions
- Each entry stores starting position of corresponding data record
- Enables O(N) loading from sorted files
- Similar to stack pointer concept in memory management
Two-tier approach:
-
If index file exists (.bin):
- Assumes data is sorted (in-order)
- Uses divide-and-conquer from sorted data
- Time complexity: O(N)
- Creates balanced tree structure
-
If index file missing:
- Checks if data is sorted
- If sorted: Loads into vector, then constructs O(N)
- If unsorted: Builds tree incrementally
- Time complexity: O(N log N)
Alternative persistence method that preserves tree structure:
tree.save_breadth_first() // Save level-by-level structure
tree.load_breadth_first() // Restore exact structureUses "NULL" placeholder for empty nodes to maintain tree topology.
The project includes a practical example: a civil records database system.
enum { FIRST_NAME = 0, LAST_NAME, BIRTH_DATE, CITY };
class civil_record {
private:
bst<custom_data<int>> database;
custom_data<int> person;
public:
civil_record();
~civil_record();
void insert_person(); // Add new record
void delete_person(); // Remove record
void search_person(); // Find and display record
void save_database(); // Persist to file
void load_database(); // Load from file
void delete_database(); // Clear all records
void show_database(); // Display all records
};int main() {
civil_record record;
int choice;
while (choice != 8) {
cout << "\n1---Insert a new person\n";
cout << "2---Search for a person\n";
cout << "3---show all the entries of the database\n";
cout << "4---Delete a person\n";
cout << "5---Save current database\n";
cout << "6---Load a database\n";
cout << "7---Remove current database\n";
cout << "8---Exit";
cout << "\nchoice: ";
cin >> choice;
switch(choice) {
case 1: record.insert_person(); break;
case 2: record.search_person(); break;
case 3: record.show_database(); break;
case 4: record.delete_person(); break;
case 5: record.save_database(); break;
case 6: record.load_database(); break;
case 7: record.delete_database(); break;
case 8: return 0;
}
}
return 0;
}The civil records example stores:
- Unique Parameter: Person ID (int)
- Age: Long integer
- Height: Double
- First Name, Last Name, Birth Date, City: Strings
- Hair Color: Character
- Life Status: Boolean
| Operation | Best Case | Worst Case | Average Case |
|---|---|---|---|
| Insert | O(log N) | O(N) | O(log N) |
| Search | O(log N) | O(N) | O(log N) |
| Remove | O(log N) | O(N) | O(log N) |
| Load (sorted) | O(N) | O(N) | O(N) |
| Load (unsorted) | O(N log N) | O(N log N) | O(N log N) |
| Save | O(N) | O(N) | O(N) |
| Traversal | O(N) | O(N) | O(N) |
The project uses:
- Standard C++ library (iostream, fstream, string, vector, queue)
<conio.h>for interactive navigation (platform-specific)<chrono>and<random>for testing utilities
Compile with:
g++ -std=c++11 bst.cpp -o database_creatorThis comprehensive documentation covers the entire Database Creator system, providing engineers with a complete understanding of its architecture, capabilities, and usage patterns for building custom database applications.