Creation of Custom Map Header

C++




// map.h
 
// C++ Program to implement Map class(using AVL tree)
// This is a header file map.h and doesnot contain main()
 
#include <iostream>
using namespace std;
 
// Custom Map Class
class Map {
private:
    Map* iterator(int first)
    {
        // A temporary variable created
        // so that we do not
        // lose the "root" of the tree
        Map* temp = root;
 
        // Stop only when either the key is found
        // or we have gone further the leaf node
        while (temp != nullptr &&
            temp->first != first) {
 
            // Go to left if key is less than
            // the key of the traversed node
            if (first < temp->first) {
                temp = temp->left;
            }
 
            // Go to right otherwise
            else {
                temp = temp->right;
            }
        }
        // If there doesn't exist any element
        // with first as key, nullptr is returned
        return temp;
    }
 
    // Returns the pointer to element
    // whose key matches first.
    // Specially created for search method
    // (because search() is const qualified).
    const Map* iterator(int first) const
    {
        Map* temp = root;
        while (temp != nullptr
            && temp->first != first) {
            if (first < temp->first) {
                temp = temp->left;
            }
            else {
                temp = temp->right;
            }
        }
        return temp;
    }
 
    // The const property is used to keep the
    // method compatible with the method "const
    // int&[]operator(int) const"
    // Since we are not allowed to change
    // the class attributes in the method
    // "const int&[]operator(int) const"
    // we have to assure the compiler that
    // method called(i.e "search") inside it
    // doesn't change the attributes of class
    const int search(int first) const
    {
        const Map* temp = iterator(first);
        if (temp != nullptr) {
            return temp->second;
        }
        return 0;
    }
 
    // Utility function to return the Map* object
    // with its members initialized
    // to default values except the key
    Map* create(int first)
    {
        Map* newnode = (Map*)malloc(sizeof(Map));
        newnode->first = first;
        newnode->second = 0;
        newnode->left = nullptr;
        newnode->right = nullptr;
        newnode->par = nullptr;
 
        // Depth of a newnode shall be 1
        // and not zero to differentiate
        // between no child (which returns
        // nullptr) and having child(returns 1)
        newnode->depth = 1;
        return newnode;
    }
 
    // All the rotation operation are performed
    // about the node itself
    // Performs all the linking done when there is
    // clockwise rotation performed at node "x"
    void right_rotation(Map* x)
    {
        Map* y = x->left;
        x->left = y->right;
        if (y->right != nullptr) {
            y->right->par = x;
        }
        if (x->par != nullptr && x->par->right == x) {
            x->par->right = y;
        }
        else if (x->par != nullptr && x->par->left == x) {
            x->par->left = y;
        }
        y->par = x->par;
        y->right = x;
        x->par = y;
    }
 
    // Performs all the linking done when there is
    // anti-clockwise rotation performed at node "x"
    void left_rotation(Map* x)
    {
        Map* y = x->right;
        x->right = y->left;
        if (y->left != nullptr) {
            y->left->par = x;
        }
        if (x->par != nullptr && x->par->left == x) {
            x->par->left = y;
        }
        else if (x->par != nullptr && x->par->right == x) {
            x->par->right = y;
        }
        y->par = x->par;
        y->left = x;
        x->par = y;
    }
 
    // Draw the initial and final graph of each
    // case(take case where every node has two child)
    // and update the nodes depth before any rotation
    void helper(Map* node)
    {
        // If left skewed
        if (depthf(node->left)
            - depthf(node->right) > 1) {
 
            // If "depth" of left subtree of
            // left child of "node" is
            // greater than right
            // subtree of left child of "node"
            if (depthf(node->left->left)
                > depthf(node->left->right)) {
                node->depth
                    = max(depthf(node->right) + 1,
                        depthf(node->left->right) + 1);
                node->left->depth
                    = max(depthf(node->left->left) + 1,
                        depthf(node) + 1);
                right_rotation(node);
            }
 
            // If "depth" of right subtree
            // of left child of "node" is
            // greater than
            // left subtree of left child
            else {
                node->left->depth = max(
                    depthf(node->left->left) + 1,
                    depthf(node->left->right->left)
                    + 1);
                node->depth
                    = max(depthf(node->right) + 1,
                    depthf(node->left->right->right) + 1);
                node->left->right->depth
                    = max(depthf(node) + 1,
                        depthf(node->left) + 1);
                left_rotation(node->left);
                right_rotation(node);
            }
        }
 
        // If right skewed
        else if (depthf(node->left)
                - depthf(node->right) < -1) {
 
            // If "depth" of right subtree of right
            // child of "node" is greater than
            // left subtree of right child
            if (depthf(node->right->right)
                > depthf(node->right->left)) {
                node->depth
                    = max(depthf(node->left) + 1,
                        depthf(node->right->left) + 1);
                node->right->depth
                    = max(depthf(node->right->right) + 1,
                        depthf(node) + 1);
                left_rotation(node);
            }
 
            // If "depth" of left subtree
            // of right child of "node" is
            // greater than that of right
            // subtree of right child of "node"
            else {
                node->right->depth = max(
                    depthf(node->right->right) + 1,
                    depthf(node->right->left->right) + 1);
                node->depth = max(
                    depthf(node->left) + 1,
                    depthf(node->right->left->left) + 1);
                node->right->left->depth
                    = max(depthf(node) + 1,
                        depthf(node->right) + 1);
                right_rotation(node->right);
                left_rotation(node);
            }
        }
    }
 
    // Balancing the tree about the "node"
    void balance(Map* node)
    {
        while (node != root) {
            int d = node->depth;
            node = node->par;
            if (node->depth < d + 1) {
                node->depth = d + 1;
            }
            if (node == root
                && depthf(node->left)
                - depthf(node->right) > 1) {
                if (depthf(node->left->left)
                    > depthf(node->left->right)) {
                    root = node->left;
                }
                else {
                    root = node->left->right;
                }
                helper(node);
                break;
            }
            else if (node == root
                    && depthf(node->left)
                    - depthf(node->right)
                            < -1) {
                if (depthf(node->right->right)
                    > depthf(node->right->left)) {
                    root = node->right;
                }
                else {
                    root = node->right->left;
                }
                helper(node);
                break;
            }
            helper(node);
        }
    }
 
    // Utility method to return the
    // "depth" of the subtree at the "node"
    int depthf(Map* node)
    {
        if (node == nullptr)
 
            // If it is null node
            return 0;
        return node->depth;
    }
 
    // Function to insert a value in map
    Map* insert(int first)
    {
        cnt++;
        Map* newnode = create(first);
        if (root == nullptr) {
            root = newnode;
            return root;
        }
        Map *temp = root, *prev = nullptr;
        while (temp != nullptr) {
            prev = temp;
            if (first < temp->first) {
                temp = temp->left;
            }
            else if (first > temp->first) {
                temp = temp->right;
            }
            else {
                free(newnode);
                cnt--;
                return temp;
            }
        }
        if (first < prev->first) {
            prev->left = newnode;
        }
        else {
            prev->right = newnode;
        }
        newnode->par = prev;
        balance(newnode);
        return newnode;
    }
 
    // Returns the previous node in
    // inorder traversal of the AVL Tree.
    Map* inorderPredecessor(Map* head)
    {
        if (head == nullptr)
            return head;
        while (head->right != nullptr) {
            head = head->right;
        }
        return head;
    }
 
    // Returns the next node in
    // inorder traversal of the AVL Tree.
    Map* inorderSuccessor(Map* head)
    {
        if (head == nullptr)
            return head;
        while (head->left != nullptr) {
            head = head->left;
        }
        return head;
    }
 
public:
    // Root" is kept static because it's a class
    // property and not an instance property
    static class Map* root;
    static int cnt;
 
    // "first" is key and "second" is value
    Map *left, *right, *par;
    int first, second, depth;
 
    // overloaded [] operator for assignment or
    // inserting a key-value pairs in the map
    // since it might change the members of
    // the class therefore this is
    // invoked when any assignment is done
    int& operator[](int key) {
        return insert(key)->second;
    }
 
    // Since we have two methods with
    // the same name "[]operator(int)" and
    // methods/functions cannot be
    // distinguished by their return types
    // it is mandatory to include a const
    // qualifier at the end of any of the methods
 
    // This method will be called from a const
    // reference to the object of Map class
 
    // It will not be called for assignment
    // because it doesn't allow to change
    // member variables
 
    // We cannot make it return by reference
    // because the variable "temp" returned
    // by the "search" method is
    // statically allocated and therefore
    // it's been destroyed when it is called out
    const int operator[](int key) const
    {
        return search(key);
    }
 
    // Count returns whether an element
    // exists in the Map or not
    int count(int first)
    {
        Map* temp = iterator(first);
        if (temp != nullptr) {
            return 1;
        }
        return 0;
    }
 
    // Returns number of elements in the map
    int size(void) {
        return cnt;
    }
 
    // Removes an element given its key
    void erase(int first, Map* temp = root)
    {
        Map* prev = nullptr;
        cnt--;
        while (temp != nullptr &&
            temp->first != first) {
            prev = temp;
            if (first < temp->first) {
                temp = temp->left;
            }
            else if (first > temp->first) {
                temp = temp->right;
            }
        }
        if (temp == nullptr) {
            cnt++;
            return;
        }
        if (cnt == 0 && temp == root) {
            free(temp);
            root = nullptr;
            return;
        }
        Map* l
            = inorderPredecessor(temp->left);
        Map* r
            = inorderSuccessor(temp->right);
        if (l == nullptr && r == nullptr) {
            if (prev == nullptr) {
                root = nullptr;
            }
            else {
                if (prev->left == temp) {
                    prev->left = nullptr;
                }
                else {
                    prev->right = nullptr;
                }
                free(temp);
                balance(prev);
            }
            return;
        }
        Map* start;
        if (l != nullptr) {
            if (l == temp->left) {
                l->right = temp->right;
                if (l->right != nullptr) {
                    l->right->par = l;
                }
                start = l;
            }
            else {
                if (l->left != nullptr) {
                    l->left->par = l->par;
                }
                start = l->par;
                l->par->right = l->left;
                l->right = temp->right;
                l->par = nullptr;
                if (l->right != nullptr) {
                    l->right->par = l;
                }
                l->left = temp->left;
                temp->left->par = l;
            }
            if (prev == nullptr) {
                root = l;
            }
            else {
                if (prev->left == temp) {
                    prev->left = l;
                    l->par = prev;
                }
                else {
                    prev->right = l;
                    l->par = prev;
                }
                free(temp);
            }
            balance(start);
            return;
        }
        else {
            if (r == temp->right) {
                r->left = temp->left;
                if (r->left != nullptr) {
                    r->left->par = r;
                }
                start = r;
            }
            else {
                if (r->right != nullptr) {
                    r->right->par = r->par;
                }
                start = r->par;
                r->par->left = r->right;
                r->left = temp->left;
                r->par = nullptr;
                if (r->left != nullptr) {
                    r->left->par = r;
                }
                r->right = temp->right;
                temp->right->par = r;
            }
            if (prev == nullptr) {
                root = r;
            }
            else {
                if (prev->right == temp) {
                    prev->right = r;
                    r->par = prev;
                }
                else {
                    prev->left = r;
                    r->par = prev;
                }
                free(temp);
            }
            balance(start);
            return;
        }
    }
     
    // Returns if the map is empty or not
    bool empty(void)
    {
        if (root == nullptr)
            return true;
        return false;
    }
     
    // Given the key of an element it updates
    // the value of the key
    void update(int first, int second)
    {
        Map* temp = iterator(first);
        if (temp != nullptr) {
            temp->second = second;
        }
    }
 
    // Deleting the root of
    // the tree each time until the map
    // is not empty
    void clear(void)
    {
        while (root != nullptr) {
            erase(root->first);
        }
    }
 
    // Inorder traversal of the AVL tree
    void iterate(Map* head = root)
    {
        if (root == nullptr)
            return;
        if (head->left != nullptr) {
            iterate(head->left);
        }
        cout << head->first << ' ';
        if (head->right != nullptr) {
            iterate(head->right);
        }
    }
 
    // Returns a pointer/iterator to the element
    // whose key is first
    Map* find(int first) {
        return iterator(first);
    }
 
    // Overloaded insert method,
    // takes two parameters - key and value
    void insert(int first, int second)
    {
        Map* temp = iterator(first);
        if (temp == nullptr) {
            insert(first)->second = second;
        }
        else {
            temp->second = second;
        }
    }
};
 
Map* Map::root = nullptr;
int Map::cnt = 0;


Now save it as a header file say map.h to include it in other codes and implement the functionalities.

Build a custom Map using Header file in C++

Maps are associative containers that store elements in a mapped fashion. Each element has a key value and a mapped value. No two mapped values can have the same key values. Maps are implemented by self-balancing search trees. In C++ STL it uses Red-Black Tree.

Here we are going to implement a custom Map class which has an integer value as the key and the value stored corresponding to any key is also of integer type.  

We will implement it using the AVL tree. To implement the map, we will first create a header file which will incorporate the functionalities of a map class. Below is the basic structure of the Map class:

Similar Reads

Structure of Map class:

The structure of the AVL tree depends upon the structure of the node:...

Functions/Operations To Be Implemented Using Custom Map

...

Creation of Custom Map Header

We will cover the following functionalities and methods in our map:...

How to Execute the built Custom Map

...

Examples to show the use of Custom Map

...

Contact Us