Skip to content

Bst

#include "rng.hpp"   // Include RNG library
#include "timer.hpp" // Include Timer library
#include <compare>   // For three-way comparison (C++20)
#include <iostream>
#include <queue> // For breadth-first traversal

using namespace std;

// Node structure representing each node in the BST
class Node {
public:
    int data;    // Value stored in the node
    Node *left;  // Pointer to the left child
    Node *right; // Pointer to the right child

    // Constructor to initialize a new node
    Node(int value) : data(value), left(nullptr), right(nullptr) {}
};

// Class representing the Binary Search Tree
class BinarySearchTree {
private:
    Node *root; // Root node of the BST

    // Helper function to insert a value recursively
    Node *insertHelper(Node *node, int value) {
        // If the current node is null, create a new node
        if (node == nullptr) {
            return new Node(value);
        }

        // Compare value with the current node's data
        auto cmp = value <=> node->data;
        if (cmp < 0) {
            node->left = insertHelper(node->left, value); // Insert in the left subtree
        } else if (cmp > 0) {
            node->right = insertHelper(node->right, value); // Insert in the right subtree
        }
        // Duplicates are implicitly skipped (cmp == 0)

        return node;
    }

    // Helper function for in-order traversal
    void inOrderTraversal(Node *node) {
        if (node != nullptr) {
            inOrderTraversal(node->left);  // Visit left subtree
            cout << node->data << " ";     // Visit node
            inOrderTraversal(node->right); // Visit right subtree
        }
    }

    // Helper function for pre-order traversal
    void preOrderTraversal(Node *node) {
        if (node != nullptr) {
            cout << node->data << " ";      // Visit node
            preOrderTraversal(node->left);  // Visit left subtree
            preOrderTraversal(node->right); // Visit right subtree
        }
    }

    // Helper function for post-order traversal
    void postOrderTraversal(Node *node) {
        if (node != nullptr) {
            postOrderTraversal(node->left);  // Visit left subtree
            postOrderTraversal(node->right); // Visit right subtree
            cout << node->data << " ";       // Visit node
        }
    }

    // Helper function for breadth-first traversal
    void breadthFirstTraversal(Node *node) {
        if (!node)
            return;

        queue<Node *> q;
        q.push(node);

        while (!q.empty()) {
            Node *current = q.front();
            q.pop();
            cout << current->data << " "; // Visit node

            if (current->left)
                q.push(current->left);
            if (current->right)
                q.push(current->right);
        }
    }

    // Helper function to invert the BST
    void invert(Node *node) {
        if (node == nullptr)
            return;

        std::swap(node->left, node->right);

        // Recursively invert the children
        invert(node->left);
        invert(node->right);
    }

public:
    // Constructor to initialize an empty BST
    BinarySearchTree() : root(nullptr) {}

    /**
     * @brief Inserts a value into the BST.
     * @param value The value to insert.
     */
    void insert(int value) { root = insertHelper(root, value); }

    /**
     * @brief Performs in-order traversal of the BST.
     * Outputs the values in ascending order.
     */
    void inOrderTraversal() {
        cout << "In-Order Traversal: ";
        inOrderTraversal(root);
        cout << endl; // Print a newline after traversal
    }

    /**
     * @brief Performs pre-order traversal of the BST.
     * Outputs the values in pre-order.
     */
    void preOrderTraversal() {
        cout << "Pre-Order Traversal: ";
        preOrderTraversal(root);
        cout << endl;
    }

    /**
     * @brief Performs post-order traversal of the BST.
     * Outputs the values in post-order.
     */
    void postOrderTraversal() {
        cout << "Post-Order Traversal: ";
        postOrderTraversal(root);
        cout << endl;
    }

    /**
     * @brief Performs breadth-first traversal of the BST.
     * Outputs the values level by level.
     */
    void breadthFirstTraversal() {
        cout << "Breadth-First Traversal: ";
        breadthFirstTraversal(root);
        cout << endl;
    }

    /**
     * @brief Inverts the BST.
     * This swaps the left and right children of all nodes.
     */
    void invert() { invert(root); }

    /**
     * @brief Generates a random BST with N nodes.
     * @param n The number of nodes to generate.
     */
    void generateRandomBST(int n) {
        RandomNumberGenerator rng; // Create RNG instance
        // Timer timer;               // Create Timer instance

        // timer.start();
        for (int i = 0; i < n; ++i)
            insert(rng.getRandomNumber() % 100);

        // timer.logTime("Generate Random BST Time");
        // timer.printResults();
    }

    // Helper function to print the tree in a pretty format
    void prettyPrintHelper(Node *node, string prefix, bool isLeft) {
        if (node == nullptr)
            return;

        cout << prefix;
        cout << (isLeft ? "├── " : "└── "); // Use different symbols for left and right children
        cout << node->data << endl;

        prettyPrintHelper(node->left, prefix + (isLeft ? "│   " : "    "), true);
        prettyPrintHelper(node->right, prefix + (isLeft ? "│   " : "    "), false);
    }

    // Public function to start pretty printing from the root
    void prettyPrint() { prettyPrintHelper(root, "", false); }
};

int main() {
    BinarySearchTree bst;

    int size = 13;
    cout << "Generating a random BST with " << size << " nodes..." << endl;
    bst.generateRandomBST(size);
    bst.prettyPrint();

    bst.inOrderTraversal();
    bst.preOrderTraversal();
    bst.postOrderTraversal();

    cout << "Inverting the BST..." << endl;
    bst.invert();

    bst.inOrderTraversal();
    bst.breadthFirstTraversal();

    return 0;
}