Functions/Operations To Be Implemented Using Custom Map

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

  1. insert()
  2. find()
  3. update()
  4. accessing any key
  5. erase()
  6. count()
  7. size()
  8. empty()
  9. clear()
  10. iterate the map 

The methods and functionalities are discussed below:

1. insert(): 

This method is used to insert a key-value pair in the map. There are two insert() methods used here. 

One is made public and it takes two parameters:

  • first – It is the key
  • second – It is the respective value of the key

Syntax:

map.insert(first, second);

Below is the implementation of this method

C++




void insert(int first, int second)
{
    Map* temp = iterator(first);
 
    // If element doesnot exist already
    if (temp == nullptr)
        insert(first)->second = second;
     
    // If element exists already update it
    else
        temp->second = second;
}


Time Complexity: O(logN) where N is the size of map

The other one is made private. This method is called inside the operator overloading function of []

  • It takes only one parameter: first (It is the key).
  • Creates the new node with “first” as the key and returns the instance of the node.

Syntax:

map[first] = second;

Below is the implementation of this method:

C++




Map* insert(int first)
{
    // Increase the number of elements
    cnt++;
    Map* newnode = create(first);
 
    // If empty tree simply create the root
    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);
 
            // If element already exists
            // decrease the count
            cnt--;
 
            // If the key is found then it is
            // returned by reference so that it is
            // updatable
            return temp;
        }
    }
    if (first < prev->first)
        prev->left = newnode;
    else
        prev->right = newnode;
     
    newnode->par = prev;
 
    // Once inserted Check and balance the tree
    // at every node in path from "newnode" to "root"
    balance(newnode);
 
    // New object is inserted and returned to
    // initialize in the main during assignment
    return newnode;
}
 
int& operator[](int key) {
    return insert(key)->second;
}


Time Complexity: O(logN) where N is the size of the map

2. find(): 

It is used to find an element. This is a public method. It takes one parameter: first (which is the key) and returns the reference associated with the key. Internally it calls the private method iterator() to find the key

Syntax:

map.find(first);

Below is the implementation of the method

C++




Map* iterator(int first)
{
    Map* temp = root;
    while (temp != nullptr && temp->first != first) {
        if (first < temp->first) {
            temp = temp->left;
        }
        else {
            temp = temp->right;
        }
    }
    return temp;
}
 
Map* find(int first) {
    return iterator(first);
}


Time Complexity: O(logN) where N is the size of the map.

3. update(): 

This value is used to update the value associated with a key. This is a public method. It takes two parameters:

  • first: It is the key to be found.
  • second: It is the new value of the key.

The function calls the iterator() function to get the instance of the key and updates the value associated to that key. If no such key exists then no operation is performed.

Syntax:

map.update(first, second);

Below is the implementation of the method.

C++




void update(int first, int second)
{
    Map* temp = iterator(first);
    if (temp != nullptr) {
        temp->second = second;
    }
}


Time Complexity: O(logN) where N is the size of the map

4. Accessing any key: 

Any value can be accessed using the subscript operator[]. The concept of method overloading is used to implement the functionality. It is a public method and the search() function is called inside the overloading function. It takes one parameter: first (it is the value of the key)

Syntax:

map[first];

Below is the implementation of the method.

C++




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;
}
 
const int search(int first) const
{
    const Map* temp = iterator(first);
 
    // If element exists with the given key
    // return its value
    if (temp != nullptr)
        return temp->second;
 
    // If element doesn't exist
    // return default value of 0
    return 0;
}
 
const int operator[](int key) const
{
    // Search method is also qualified with const
    return search(key);
}


Time Complexity: O(logN) where N is the size of the map.

5. erase(): 

It deletes the node with the given key and replaces it with either its in-order predecessor or in-order successor. It is a public method. It takes one parameter: first (it is the key whose value needs to be deleted). At the end of the function, it calls balance() method on the parent of that node which replaced the deleted node to balance the AVL tree.

Syntax:

map.erase(first);

Below is the implementation of the method.

C++




void erase(int first, Map* temp = root)
{
    Map* prev = 0;
    cnt--;
    while (temp != 0 && 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 == 0 && r == 0) {
        if (prev == 0) {
            root = 0;
        }
        else {
            if (prev->left == temp) {
                prev->left = 0;
            }
            else {
                prev->right = 0;
            }
            free(temp);
            balance(prev);
        }
        return;
    }
 
    Map* start;
    if (l != 0) {
        if (l == temp->left) {
            l->right = temp->right;
            if (l->right != 0) {
                l->right->par = l;
            }
            start = l;
        }
        else {
            if (l->left != 0) {
                l->left->par = l->par;
            }
            start = l->par;
            l->par->right = l->left;
            l->right = temp->right;
            l->par = 0;
            if (l->right != 0) {
                l->right->par = l;
            }
            l->left = temp->left;
            temp->left->par = l;
        }
        if (prev == 0) {
            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 != 0) {
                r->left->par = r;
            }
            start = r;
        }
        else {
            if (r->right != 0) {
                r->right->par = r->par;
            }
            start = r->par;
            r->par->left = r->right;
            r->left = temp->left;
            r->par = 0;
            if (r->left != 0) {
                r->left->par = r;
            }
            r->right = temp->right;
            temp->right->par = r;
        }
        if (prev == 0) {
            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;
    }
}


Time Complexity: O(logN) where N is the size of the map.

6. count(): 

This method returns the count of a key in the map. This is a public method. It takes one parameter: first(which is the key of value whose count should be found). This method calls the iterator() method internally and if no node is found then count is 0. Otherwise, count returns 1.

Syntax:

map.count(first);

Below is the implementation of the method.

C++




int count(int first)
{
    Map* temp = iterator(first);
 
    // If key is found
    if (temp != nullptr)
        return 1;
 
    // If key is not found
    return 0;
}


Time Complexity: O(logN) where N is the size of the map.

7. size(): 

This method returns the size of the map. This is a public method. This method does not take any parameter.

Syntax:

map.size();

Below is the implementation of the method.

C++




int size(void) {
    return cnt;
}


Time Complexity: O(1)

8. empty(): 

This method checks if the map is empty or not. This is a public method. It returns true if the map is empty, else false. This method does not take any parameter. 

Syntax:

map.empty();

Below is the implementation of the method.

C++




bool empty(void)
{
    if (root == 0)
        return true;
    return false;
}


Time Complexity: O(1)

9. clear(): 

This method is used to delete the whole map in. This is a public method. It does not take any parameter. It takes the erase() method internally.

Syntax:

map.clear();

Below is the implementation of the method.

C++




void clear(void)
{
    while (root != nullptr) {
        erase(root->first);
    }
}


Time Complexity: O(N * logN) where N is the size of the map

10. iterate(): 

This method is used to traverse the whole map. This is a public method. It also does not take any parameter. The nodes are printed in the sorted manner of key.

Syntax:

map.iterate();

Below is the implementation of the method.

C++




void iterate(Map* head = root)
{
    if (root == 0)
        return;
    if (head->left != 0) {
        iterate(head->left);
    }
   
    cout << head->first << ' ';
   
    if (head->right != 0) {
        iterate(head->right);
    }
}


Time Complexity: O(N) where N is the size of the map

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