unordered_multimap and its application

3.3

Allows Duplicates:
We have discussed about unordered_map in our previous post , but there is a limitation, we can not store duplicates in unordered_map, that is if we have a key value pair already in our unordered_multimap and another pair is inserted, then both will be there whereas in case of unordered_map the previous value corresponding to the key is updated by new value that is only would be there. Even can exist in unordered_multimap twice.

Internal Representation:
The internal implementation of unordered_multimap is same as that of unordered_map but for duplicate keys another count value is maintained with each key- value pair. As pairs are stored in hash table, there is no particular order among them but pair with same keys come together in data structure whereas pair with same values are not guaranteed to come together.

Time Complexity:
All operation on unordered_multimap takes constant amount of time on an average but time can go to linear in worst case depending on internally used hash function but in long run unordered_multimap outperforms multimap (tree based multimap).

Functions:
unorderd_multimap supports many function which are demonstrated in below code :

// C++ program to demonstrate various function of
// unordered_multimap
#include <bits/stdc++.h>
using namespace std;

//making typedef for short declaration
typedef unordered_multimap<string, int>::iterator umit;

// Utility function to print unordered_multimap
void printUmm(unordered_multimap<string, int> umm)
{
    // begin() returns iterator to first element of map
    umit it = umm.begin();

    for (; it != umm.end(); it++)
        cout << "<" << it->first << ", " << it->second
             << ">  ";

    cout << endl;
}

// Driver program to check all function
int main()
{
    // empty initialization
    unordered_multimap<string, int> umm1;

    // Initialization bu intializer list
    unordered_multimap<string, int> umm2 ({{"apple", 1},
                                           {"ball", 2},
                                           {"apple", 10},
                                           {"cat", 7},
                                           {"dog", 9},
                                           {"cat", 6},
                                           {"apple", 1}});

    // Initialization by assignment operation
    umm1 = umm2;
    printUmm(umm1);

    // empty returns true, if container is empty else it returns
    // false
    if (umm2.empty())
        cout << "unordered multimap 2 is empty\n";
    else
        cout << "unordered multimap 2 is not empty\n";

    // size returns total number of elements in container
    cout << "Size of unordered multimap 1 is " << umm1.size()
         << endl;

    string key = "apple";

    // find and return any pair, associated with key
    umit it = umm1.find(key);
    if (it != umm1.end())
    {
        cout << "\nkey " << key << " is there in unordered "
             << " multimap 1\n";
        cout << "\none of the value associated with " << key
             << " is " << it->second << endl;
    }
    else
        cout << "\nkey " << key << " is not there in unordered"
             << " multimap 1\n";

    // count returns count of total number of pair associated
    // with key
    int cnt = umm1.count(key);
    cout << "\ntotal values associated with " << key << " are "
         << cnt << "\n\n";

    printUmm(umm2);

    // one insertion by makeing pair explicitly
    umm2.insert(make_pair("dog", 11));

    // insertion by initializer list
    umm2.insert({{"alpha", 12}, {"beta", 33}});
    cout << "\nAfter insertion of <apple, 12> and <beta, 33>\n";
    printUmm(umm2);

    // erase deletes all pairs corresponding to key
    umm2.erase("apple");
    cout << "\nAfter deletion of apple\n";
    printUmm(umm2);

    // clear deletes all pairs from container
    umm1.clear();
    umm2.clear();

    if (umm2.empty())
        cout << "\nunordered multimap 2 is empty\n";
    else
        cout << "\nunordered multimap 2 is not empty\n";
}

Output:

<apple, 1>  <apple, 10>  <apple, 1>  <ball, 2>  <cat, 6>  <cat, 7>  <dog, 9>  
unordered multimap 2 is not empty
Size of unordered multimap 1 is 7

key apple is there in unordered  multimap 1

one of the value associated with apple is 1

total values associated with apple are 3

<apple, 1>  <apple, 10>  <apple, 1>  <ball, 2>  <cat, 6>  <cat, 7>  <dog, 9>  

After insertion of <apple, 12> and <beta, 33>
<beta, 33>  <alpha, 12>  <apple, 1>  <apple, 10>  <apple, 1>  <ball, 2>
<cat, 6>  <cat, 7>  <dog, 11>  <dog, 9>  

After deletion of apple
<beta, 33>  <alpha, 12>  <ball, 2>  <cat, 6>  <cat, 7>  <dog, 11>  <dog, 9>  

unordered multimap 2 is empty

As we can see in above code most of the operation work similar to unordered_map but some things to note are :
We can use initializer list for initializing and inserting many pairs at once.
There is no [] operator for unordered_multimap because values corresponding to a key are not unique, there can be many values associated with a single key so [] operator can not be applied to them.
Erase function deletes all instances of values associated with supplied key.
Find function returns an iterator to any instance of key-value pair among all pair associated with that key.

How to access/delete if a specific value for a key?
If we want to check whether a specific is there or not, we need to loop over all pairs of key-value corresponding to k, in similar way we can erase one copy of a specific from data structure. There is no specified order in which all values of a key are stored.

// C++ program to implement find and erase for specific
// key-value pair for unordered_multimap
#include <bits/stdc++.h>
using namespace std;

// making typedef for short declaration
typedef unordered_multimap<string, int>:: iterator umit;

// function to check whether p is there in map or not
bool find_kv(unordered_multimap<string, int>& umm,
             pair<string, int> p)
{
    // equal_range returns pair of iterator of first and last
    // position associated with key
    pair<umit, umit> it = umm.equal_range(p.first);
    umit it1 = it.first;

    pair<string, int> tmp;

    // looping over all values associated with key
    while (it1 != it.second)
    {
        tmp = *it1;
        if (tmp == p)
            return true;
        it1++;
    }
    return false;
}

// function to delete one copy of pair p from map umm
void erase_kv(unordered_multimap<string, int>& umm,
              pair<string, int> p)
{
    // equal_range returns pair of iterator of first and
    // last position associated with key
    pair<umit, umit> it = umm.equal_range(p.first);
    umit it1 = it.first;
    pair<string, int> tmp;

    // looping over all values associated with key
    while (it1 != it.second)
    {
        tmp = *it1;
        if (tmp == p)
        {
            // iterator version of erase : deletes pair
            // at that position only
            umm.erase(it1);
            break;
        }
        it1++;
    }
}

// Utility function to print unordered_multimap
void printUmm(unordered_multimap<string, int> umm)
{
    // begin() returns iterator to first element of map
    umit it = umm.begin();
    for (; it != umm.end(); it++)
        cout << "<" << it->first << ", " << it->second << "> ";
    cout << endl;
}

// Driver program to check above function
int main()
{
    // initializing multimap by initializer list
    unordered_multimap<string, int> umm ({{"apple", 1},
        {"ball", 2},
        {"apple", 10},
        {"cat", 7},
        {"dog", 9},
        {"cat", 6},
        {"apple", 1}
    });

    cout << "Initial content\n";
    printUmm(umm);
    pair<string, int> kv = make_pair("apple", 1);

    cout << "\nAfter insertion of one more <apple, 1>\n";
    printUmm(umm);

    if (find_kv(umm, kv))
        erase_kv(umm, kv);
    else
        cout << "key-value pair is not there in unordered multimap\n";

    cout << "\nAfter deletion one occurrence of <apple, 1>\n";
    printUmm(umm);
}

Output:

Initial content
<apple, 1> <apple, 10> <apple, 1> <ball, 2> <cat, 6> <cat, 7> <dog, 9> 

After insertion of one more <apple, 1>
<apple, 1> <apple, 10> <apple, 1> <ball, 2> <cat, 6> <cat, 7> <dog, 9> 

After deletion one occurrence of <apple, 1>
<apple, 10> <apple, 1> <ball, 2> <cat, 6> <cat, 7> <dog, 9> 

This article is contributed by Utkarsh Trivedi. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above

GATE CS Corner    Company Wise Coding Practice

Recommended Posts:



3.3 Average Difficulty : 3.3/5.0
Based on 3 vote(s)










Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.