c++performancepoolavl-tree

Is there any benefit to writing an object pool to store an AVL Tree?


I'm currently working on a school project where I am asked to write an fast AVL Tree for efficient data storage and retrieval. I've been reading about object pools and am considering implementing one to manage the nodes of my AVL Tree. My questions are:

Here's a basic implementation of an AVL Tree in C++ without an object pool:

#include <iostream>

struct Node {
    int key;
    Node* left;
    Node* right;
    int height;
    
    Node(int k) : key(k), left(nullptr), right(nullptr), height(1) {}
};

int height(Node* n) {
    return n ? n->height : 0;
}

int getBalance(Node* n) {
    return n ? height(n->left) - height(n->right) : 0;
}

Node* rightRotate(Node* y) {
    Node* x = y->left;
    Node* T2 = x->right;
    
    x->right = y;
    y->left = T2;
    
    y->height = std::max(height(y->left), height(y->right)) + 1;
    x->height = std::max(height(x->left), height(x->right)) + 1;
    
    return x;
}

Node* leftRotate(Node* x) {
    Node* y = x->right;
    Node* T2 = y->left;
    
    y->left = x;
    x->right = T2;
    
    x->height = std::max(height(x->left), height(x->right)) + 1;
    y->height = std::max(height(y->left), height(y->right)) + 1;
    
    return y;
}

Node* insert(Node* node, int key) {
    if (!node) return new Node(key);
    
    if (key < node->key)
        node->left = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else
        return node;
    
    node->height = 1 + std::max(height(node->left), height(node->right));
    
    int balance = getBalance(node);
    
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
    
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
    
    if (balance > 1 && key > node->left->key) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }
    
    if (balance < -1 && key < node->right->key) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
    
    return node;
}

void preOrder(Node* root) {
    if (root) {
        std::cout << root->key << " ";
        preOrder(root->left);
        preOrder(root->right);
    }
}

Node* free(Node* root){
    if (root){
        free(root->left);
        free(root->right);
        delete root;
    }
    return nullptr;
}

int main() {
    Node* root = nullptr;
    
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);
    root = insert(root, 50);
    root = insert(root, 25);
    
    std::cout << "Preorder traversal of the constructed AVL tree is \n";
    preOrder(root);
    root = free(root);
    return 0;
}

Would implementing an object pool for the nodes in this AVL Tree provide any significant advantages?


Solution

  • Using a node pool would enable you to:

    1. Reference nodes by index instead of address, potentially reducing the memory size of Node.
    2. Improve the odds of retrieving Nodes from the cache instead of from memory. Given 32-bit int indexes and the usual 64-byte cache line, one fetch could retrieve four Nodes at once.
    3. Allow you to nuke the whole pool in one go instead of pointer-chasing across your entire memory space.